快速开始
快速开始
Webpack 非常适合那些需要可定制构建管道的应用:打包 JavaScript 模块、处理静态资源、集成 loader 和插件,以及为不同环境定制构建输出。对于一个只有一两个脚本的非常小的页面,打包器可能一开始并非必需;但对于具有共享依赖、npm 包、静态资源和生产构建的应用,webpack 能让您明确控制一切是如何组装的。
Webpack 用于高效地编译 JavaScript 模块。一旦安装,您可以通过其 CLI 或 API 与 webpack 交互。如果您还不熟悉 webpack,请阅读核心概念和此对比,了解为何您应该使用它而不是社区中的其他工具。
W> 本指南中的示例使用 webpack-cli 7,它需要 Node.js 20.9.0 或更高版本。
快速开始(最小可行示例)
如果您想快速启动并运行一个可用的 webpack 项目,最简单的方法是使用 create-webpack-app 来搭建一个。
bash
npx create-webpack-app webpack-demo
cd webpack-demo
T> 需要基于 CLI 的项目设置或模板?请参阅 webpack 脚手架流程的 Init 命令。
T> 此命令会生成一个开箱即用的 webpack 项目,并带有合理的默认配置。如果您想了解如何逐步手动设置 webpack,请继续阅读下文。
基本设置
首先,让我们创建一个目录,初始化 npm,在本地安装 webpack,并安装 webpack-cli(用于在命令行中运行 webpack 的工具):
bash
# 请只为其中一个包管理器运行命令。
mkdir webpack-demo
cd webpack-demo
# npm
npm init -y
npm install webpack webpack-cli --save-dev
# yarn
yarn init -y
yarn add webpack webpack-cli --dev
# pnpm
pnpm init
pnpm add webpack webpack-cli -D
在整个指南中,我们将使用 diff 块来向您展示我们对目录、文件和代码所做的更改。例如:
diff
+ 这是您应复制到代码中的新行
- 这是要从代码中删除的行
这是无需改动的行。
现在,我们将创建以下目录结构、文件和内容:
项目结构
diff
webpack-demo
├── package.json
├── package-lock.json
+ ├── index.html
+ └── src/
+ └── index.js
src/index.js
js
function component() {
const element = document.createElement("div");
// Lodash 目前通过 script 标签引入,此行代码依赖于此
element.innerHTML = _.join(["Hello", "webpack"], " ");
return element;
}
document.body.appendChild(component());
index.html
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Getting Started</title>
<script src="https://unpkg.com/lodash@4.17.21"></script>
</head>
<body>
<script src="./src/index.js"></script>
</body>
</html>
我们还需要调整 package.json 文件,以确保将包标记为 private,并移除 main 入口。这是为了防止意外发布您的代码。
我们还添加了 "type": "module",以便 Node.js 将本项目中的 .js 文件视为 ES 模块。该设置适用于整个项目,包括未来的 Node.js 脚本和 webpack 配置文件。如果您希望保留 Node 默认的 CommonJS 行为,请省略 "type": "module",并在本指南后面使用 require(...) 和 module.exports 而不是 import 和 export default 来编写配置。
T> 如果您想了解更多关于 package.json 的内部工作原理,我们建议阅读 npm 文档。
package.json
diff
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
- "main": "index.js",
+ "private": true,
+ "type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"webpack": "^5.105.0",
"webpack-cli": "^7.0.0"
}
}
在此示例中,<script> 标签之间存在隐式依赖关系。我们的 index.js 文件依赖 lodash 在其运行之前被包含在页面中。这创建了对全局变量(_)的隐式依赖,使得脚本执行顺序变得至关重要且难以维护。
以这种方式管理 JavaScript 项目存在一些问题:
- 无法立即看出脚本依赖外部库。
- 如果依赖缺失或包含顺序错误,应用将无法正常运行。
- 如果包含了依赖但未使用,浏览器将被迫下载不必要的代码。
Webpack 通过显式声明依赖并将它们打包在一起来解决这些问题。这消除对全局变量的依赖,并确保脚本按正确顺序执行。
创建 Bundle
首先,我们稍微调整一下目录结构,将“源代码”(./src)与“分发代码”(./dist)分开。“源代码”是我们编写和编辑的代码。“分发代码”是构建过程中最小化和优化后的 output,最终将被浏览器加载。请按如下方式调整目录结构:
项目结构
diff
webpack-demo
├── package.json
├── package-lock.json
+ ├── /dist
+ │ └── index.html
- ├── index.html
└── /src
└── index.js
dist 目录是构建输出,因此在成熟的项目中,您通常不会手动编辑那里的文件。我们暂时将 index.html 移动到 dist 中仅作为临时脚手架,以便浏览器有一个 HTML 文件来加载第一个生成的 bundle。稍后在另一篇指南中,我们将生成 index.html 而不是手动编辑它。完成此操作后,清空 dist 目录并重新生成其中的所有文件应该是安全的。
为了将 lodash 依赖与 index.js 打包,我们需要在本地安装该库:
bash
# 请只为其中一个包管理器运行命令。
# npm
npm install lodash
# yarn
yarn add lodash
# pnpm
pnpm add lodash
T> 对于 npm 5 及更高版本,使用 npm install <package> 安装的包默认会保存到 dependencies。如果您出于开发目的安装包(例如 linter、测试库等),则应使用 npm install --save-dev。更多信息可以在 npm 文档 中找到。
现在,让我们在脚本中导入 lodash:
src/index.js
diff
+import _ from 'lodash';
+
function component() {
const element = document.createElement('div');
- // Lodash, currently included via a script, is required for this line to work
+ // Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());
现在,由于我们将打包脚本,必须更新 index.html 文件。让我们移除 lodash 的 <script> 标签,因为我们现在 import 了它,并修改另一个 <script> 标签以加载 bundle,而不是原始的 ./src 文件:
dist/index.html
diff
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Getting Started</title>
- <script src="https://unpkg.com/lodash@4.17.21"></script>
</head>
<body>
- <script src="./src/index.js"></script>
+ <script src="main.js"></script>
</body>
</html>
T> 还有其他几种脚本加载策略。延迟加载就是其中一种替代方案,将脚本合并到 <head> 中并赋予 defer 属性。此策略在文档解析的同时并行下载外部脚本资源,并在解析完成后按文档出现顺序执行脚本。这与上述方式形成对比,后者解析器暂停以下载外部资源,然后同步执行。要了解更多相关信息,MDN 有一份不错的参考指南。
在这种设置下,index.js 显式要求存在 lodash,并将其绑定为 _(无全局作用域污染)。通过声明模块需要哪些依赖,webpack 可以利用此信息构建依赖图。然后,它使用该图生成优化的 bundle,其中脚本将按正确顺序执行。
话虽如此,让我们从项目根目录运行 npx webpack。如果 webpack 是本地安装的,npx 将运行来自 node_modules/.bin 的本地二进制文件;否则,它可能会下载并执行它。此命令将 src/index.js 中的脚本作为入口点,并生成 dist/main.js 作为输出。
bash
# 请只为其中一个包管理器运行命令。
# npm
npx webpack
# yarn
yarn webpack
# pnpm
pnpm exec webpack
[webpack-cli] Compilation finished
asset main.js 69.3 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 1851 ms
T> 您的输出可能略有不同,但如果构建成功,那么您就可以开始了。
T> 未设置 mode 时,webpack 默认以生产模式运行,因此上述输出包含 [minimized],生成的 dist/main.js 将针对浏览器进行优化,而不便于阅读。学习时,您可以运行 npx webpack --mode development、yarn webpack --mode development 或 pnpm exec webpack --mode development 来生成更易读的 bundle。
在浏览器中打开 dist 目录下的 index.html,如果一切顺利,您应该会看到以下文本:'Hello webpack'。
Modules
import 和 export 语句已在 ES2015 中标准化。目前大多数浏览器都支持它们,但仍有一些浏览器无法识别新语法。不过不用担心,webpack 开箱即用地支持它们。
在幕后,webpack 分析您的模块图,并将模块打包成浏览器可以按正确顺序加载的代码。它处理诸如 import 和 export 之类的模块语法,并且也支持各种其他模块语法。有关详细信息,请参阅 模块 API。
请注意,webpack 不会更改除 import 和 export 语句之外的任何代码。如果您正在使用其他 ES2015 特性,请确保通过 webpack 的 loader 系统 使用诸如 Babel 之类的转译器。
使用配置文件
从版本 4 开始,webpack 不需要任何配置,但大多数项目需要更复杂的设置,这就是 webpack 支持配置文件的原因。这比在终端中手动输入大量命令要高效得多,所以让我们创建一个:
Webpack 配置文件可以使用 CommonJS 或 ECMAScript 模块编写。以下示例使用现代 ESM 语法。
项目结构
diff
webpack-demo
├── package.json
├── package-lock.json
+ ├── webpack.config.js
├── /dist
│ └── index.html
└── /src
└── index.js
webpack.config.js
js
import path from "node:path";
import { fileURLToPath } from "node:url";
// 在 Node.js 原生支持 import.meta.dirname 之前的版本中,
// 从 import.meta.url 派生 __dirname。
// (Node 20.11+ 支持 import.meta.dirname 和 import.meta.filename。)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
};
现在,让我们再次运行构建,但这次使用我们的新配置文件:
bash
# 请只为其中一个包管理器运行命令。
# npm
npx webpack --config webpack.config.js
# yarn
yarn webpack --config webpack.config.js
# pnpm
pnpm exec webpack --config webpack.config.js
[webpack-cli] Compilation finished
asset main.js 69.3 KiB [compared for emit] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 1934 ms
T> 如果存在 webpack.config.js,webpack 命令默认会使用它。我们在此使用 --config 选项只是为了表明您可以传递任何名称的配置。这对于需要拆分为多个文件的更复杂配置非常有用。
配置文件比 CLI 用法提供更大的灵活性。我们可以通过这种方式指定 loader 规则、插件、解析选项和许多其他增强功能。请参阅配置文档了解更多信息。
NPM 脚本
考虑到从 CLI 运行本地 webpack 副本并不特别有趣,我们可以设置一个小的快捷方式。让我们通过添加一个 npm 脚本来调整我们的 package.json:
package.json
diff
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.105.0",
"webpack-cli": "^7.0.0"
},
"dependencies": {
"lodash": "^4.17.21"
}
}
现在,npm run build 命令可以替代我们之前使用的 npx 命令。请注意,在 scripts 中,我们可以像使用 npx 一样,通过名称引用本地安装的 npm 包。这种约定是大多数基于 npm 的项目中的标准做法,因为它允许所有贡献者使用相同的常用脚本集。
现在运行以下命令,看看您的脚本别名是否有效:
bash
# 请只为其中一个包管理器运行命令。
# npm
npm run build
# yarn
yarn build
# pnpm
pnpm run build
...
[webpack-cli] Compilation finished
asset main.js 69.3 KiB [compared for emit] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
./src/index.js 257 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 1940 ms
T> 可以通过在 npm run build 命令和参数之间添加两个破折号来向 webpack 传递自定义参数,例如 npm run build -- --color。
总结
既然您已经完成了基本构建,接下来应该进入下一篇指南 资源管理,学习如何使用 webpack 管理图片和字体等资源。此时,您的项目应该如下所示:
项目结构
diff
webpack-demo
├── package.json
├── package-lock.json
├── webpack.config.js
├── /dist
│ ├── main.js
│ └── index.html
├── /src
│ └── index.js
└── /node_modules
W> 不要使用 webpack 编译不受信任的代码。这可能导致恶意代码在您的计算机、远程服务器或应用最终用户的 Web 浏览器中执行。
如果您想了解更多关于 webpack 的设计,可以查看基本概念和配置页面。此外,API 部分深入探讨了 webpack 提供的各种接口。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
