知海

快速开始

webpackjsorg-main开始-简介

快速开始

Webpack 非常适合那些需要可定制构建管道的应用:打包 JavaScript 模块、处理静态资源、集成 loader 和插件,以及为不同环境定制构建输出。对于一个只有一两个脚本的非常小的页面,打包器可能一开始并非必需;但对于具有共享依赖、npm 包、静态资源和生产构建的应用,webpack 能让您明确控制一切是如何组装的。

Webpack 用于高效地编译 JavaScript 模块。一旦安装,您可以通过其 CLIAPI 与 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 而不是 importexport 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 developmentyarn webpack --mode developmentpnpm exec webpack --mode development 来生成更易读的 bundle。

在浏览器中打开 dist 目录下的 index.html,如果一切顺利,您应该会看到以下文本:'Hello webpack'

Modules

importexport 语句已在 ES2015 中标准化。目前大多数浏览器都支持它们,但仍有一些浏览器无法识别新语法。不过不用担心,webpack 开箱即用地支持它们。

在幕后,webpack 分析您的模块图,并将模块打包成浏览器可以按正确顺序加载的代码。它处理诸如 importexport 之类的模块语法,并且也支持各种其他模块语法。有关详细信息,请参阅 模块 API

请注意,webpack 不会更改除 importexport 语句之外的任何代码。如果您正在使用其他 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.jswebpack 命令默认会使用它。我们在此使用 --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 提供的各种接口。

帮助我们改进文档

发现翻译问题或内容错误?请告诉我们。