起步

webpack 用于编译 JavaScript 模块。一旦完成 安装,你就可以通过 webpack CLIAPI 与其配合交互。如果你还不熟悉 webpack,请阅读 核心概念对比,了解为什么要使用 webpack,而不是社区中的其他工具。

基本安装

首先我们创建一个目录,初始化 npm,然后 在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack):

mkdir webpack-demo && cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev
贯穿整个指南的是,我们将使用 diff 块,来展示对目录、文件和代码所做的修改。

现在,我们将创建以下目录结构、文件和内容:

project

  webpack-demo
  |- package.json
+ |- index.html
+ |- /src
+   |- index.js

src/index.js

function component() {
  let element = document.createElement('div');

  // lodash(目前通过一个 script 引入)对于执行这一行是必需的
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());

index.html

<!doctype html>
<html>
  <head>
    <title>起步</title>
    <script src="https://unpkg.com/lodash@4.16.6"></script>
  </head>
  <body>
    <script src="./src/index.js"></script>
  </body>
</html>

我们还需要调整 package.json 文件,以便确保我们安装包是 private(私有的),并且移除 main 入口。这可以防止意外发布你的代码。

如果你想要了解 package.json 内在机制的更多信息,我们推荐阅读 npm 文档

package.json

  {
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
+   "private": true,
-   "main": "index.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2"
    },
    "dependencies": {}
  }

在此示例中,<script> 标签之间存在隐式依赖关系。在 index.js 文件执行之前,还需要在页面中先引入 lodash。这是因为 index.js 并未显式声明它需要 lodash,只是假定推测已经存在一个全局变量 _

使用这种方式去管理 JavaScript 项目会有一些问题:

  • 无法直接体现,脚本的执行依赖于外部库。
  • 如果依赖不存在,或者引入顺序错误,应用程序将无法正常运行。
  • 如果依赖被引入但是并没有使用,浏览器将被迫下载无用代码。

让我们使用 webpack 来管理这些脚本。

创建一个 bundle

首先,我们稍微调整下目录结构,将“源”代码(/src)从我们的“分发”代码(/dist)中分离出来。源代码是用于书写和编辑的代码。分发代码是构建过程产生的代码最小化和优化后的 输出(output) 目录,最终将在浏览器中加载:

project

  webpack-demo
  |- package.json
+ |- /dist
+   |- index.html
- |- index.html
  |- /src
    |- index.js

要在 index.js 中装入 lodash 依赖,我们需要在本地安装 library:

npm install --save lodash
在安装一个 package,而此 package 要打包到生产环境 bundle 中时,你应该使用 npm install --save。如果你在安装一个用于开发环境目的的 package 时(例如,linter, 测试库等),你应该使用 npm install --save-dev。在 npm 文档 中查找更多信息。

现在,在我们的 script 中 import lodash

src/index.js

+ import _ from 'lodash';
+
  function component() {
    let element = document.createElement('div');

-   // lodash(目前通过一个 script 引入)对于执行这一行是必需的
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');

    return element;
  }

  document.body.appendChild(component());

现在,我们将会打包所有脚本,我们必须更新 index.html 文件。由于现在是通过 import 引入 lodash,所以要将 lodash <script> 删除,然后修改另一个 <script> 标签来加载 bundle,而不是原始的 /src 文件:

dist/index.html

  <!doctype html>
  <html>
   <head>
     <title>起步</title>
-    <script src="https://unpkg.com/lodash@4.16.6"></script>
   </head>
   <body>
-    <script src="./src/index.js"></script>
+    <script src="main.js"></script>
   </body>
  </html>

在这个设置中,index.js 显式要求引入的 lodash 必须存在,然后将它绑定为 _(没有全局作用域污染)。通过声明模块所需的依赖,webpack 能够利用这些信息去构建依赖图,然后使用图生成一个会以正确顺序执行的优化 bundle。

可以这样说,执行 npx webpack,会将我们的脚本 src/index.js 作为 入口起点,也会生成 dist/main.js 作为 输出。Node 8.2/npm 5.2.0 以上版本提供的 npx 命令,可以运行在开始安装的 webpack package 中的 webpack 二进制文件(即 ./node_modules/.bin/webpack):

npx webpack

...
Built at: 13/06/2018 11:52:07
  Asset      Size  Chunks             Chunk Names
main.js  70.4 KiB       0  [emitted]  main
...

WARNING in configuration(配置警告)
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/('mode' 选项还未设置,webpack 会将其值回退至 'production'。将 'mode' 选项设置为 'development''production',来启用对应环境的默认优化设置。)
输出可能会稍有不同,但是只要构建成功,那么你就可以放心继续。并且不要担心警告,稍后我们就会解决。

在浏览器中打开 index.html,如果一切正常,你应该能看到以下文本:'Hello webpack'。

模块

ES2015 中的 importexport 语句已经被标准化,并且 多数浏览器已经能够支持。一些旧版本浏览器虽然无法支持它们,但是通过 webpack 开箱即用的模块支持,我们也可以使用这些ES2015 模块标准。

在幕后,webpack 实际上会将代码进行 transpile(转译),因此旧版本浏览器也可以执行。如果检查 dist/main.js,你就可以看到 webpack 是如何实现,这是独创精巧的设计!除了 importexport,webpack 还能够很好地支持各种其他模块语法,更多信息请查看 模块 API

注意,webpack 不会更改代码中除 importexport 语句以外的部分。如果你在使用其它 ES2015 特性,请确保你在 webpack loader 系统 中使用了一个像是 BabelBublétranspiler(转译器)

使用一个配置文件

在 webpack v4 中,可以无须任何配置,然而大多数项目会需要很复杂的设置,这就是为什么 webpack 仍然要支持 配置文件。这比在 terminal(终端) 中手动输入大量命令要高效的多,所以让我们创建一个配置文件:

project

  webpack-demo
  |- package.json
+ |- webpack.config.js
  |- /dist
    |- index.html
  |- /src
    |- index.js

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
};

现在,让我们通过新的配置文件再次执行构建:

npx webpack --config webpack.config.js

...
  Asset      Size  Chunks             Chunk Names
main.js  70.4 KiB       0  [emitted]  main
...

WARNING in configuration(配置警告)
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.('mode' 选项还未设置,webpack 会将其值回退至 'production'。将 'mode' 选项设置为 'development''production',来启用对应环境的默认优化设置。)
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/(你也可以将其设置为 'none',以禁用所有默认行为。了解更多 https://webpack.js.org/concepts/mode/)
如果 webpack.config.js 存在,则 webpack 命令将默认选择使用它。我们在这里使用 --config 选项只是向你表明,可以传递任何名称的配置文件。这对于需要拆分成多个文件的复杂配置是非常有用。

比起 CLI 这种简单直接的使用方式,配置文件具有更多的灵活性。我们可以通过配置方式指定 loader 规则(loader rule)、插件(plugin)、resolve 选项,以及许多其他增强功能。更多详细信息请查看 配置文档

npm scripts

考虑到用 CLI 这种方式来运行本地的 webpack 副本并不是特别方便,我们可以设置一个快捷方式。调整 package.json 文件,添加在 npm scripts 中添加一个 npm 命令:

package.json

  {
    "name": "webpack-demo",
    "version": "1.0.0",
    "description": "",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
+     "build": "webpack"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "webpack": "^4.20.2",
      "webpack-cli": "^3.1.2"
    },
    "dependencies": {
      "lodash": "^4.17.5"
    }
  }

现在,可以使用 npm run build 命令,来替代我们之前使用的 npx 命令。注意,使用 npm scripts,我们可以像使用 npx 那样通过模块名引用本地安装的 npm packages。这是大多数基于 npm 的项目遵循的标准,因为它允许所有贡献者使用同一组通用脚本(如果必要,每个 flag 都带有 --config 标志)。

现在运行以下命令,然后看看你的脚本别名是否正常运行:

npm run build

...
  Asset      Size  Chunks             Chunk Names
main.js  70.4 KiB       0  [emitted]  main
...

WARNING in configuration(配置警告)
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.('mode' 选项还未设置,webpack 会将其值回退至 'production'。将 'mode' 选项设置为 'development''production',来启用对应环境的默认优化设置。)
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/(你也可以将其设置为 'none',以禁用所有默认行为。了解更多 https://webpack.js.org/concepts/mode/)
通过在 npm run build 命令和你的参数之间添加两个中横线,可以将自定义参数传递给 webpack,例如:npm run build -- --colors

结论

现在,你已经有了一个基础构建配置,你应该移至下一章节 资源管理 指南,以了解如何通过 webpack 来管理资源,例如 images、fonts。此刻你的项目看起来应该如下:

project

webpack-demo
|- package.json
|- webpack.config.js
|- /dist
  |- main.js
  |- index.html
|- /src
  |- index.js
|- /node_modules
如果你使用的是 npm 5,你可能还会在目录中看到一个 package-lock.json 文件。

如果你想要了解 webpack 设计思想,你应该看下 基本概念配置 页面。此外,API 章节可以深入了解 webpack 提供的各种接口。


贡献人员