知海

输出管理

webpackjsorg-main指南-教程

T> 本指南基于 资源管理 指南中的代码示例进行扩展。

到目前为止,我们一直在 index.html 文件中手动引入所有资源,但随着应用程序的增长,一旦你开始 在文件名中使用哈希 并输出 多个 bundle,手动管理 index.html 文件将变得非常困难。不过,有一些插件可以使这个过程更容易管理。

准备

首先,让我们稍微调整一下项目结构:

项目

diff 复制代码
  webpack-demo
  ├── package.json
  ├── package-lock.json
  ├── webpack.config.js
  ├── /dist
  ├── /src
  │   ├── index.js
+ │   ├── print.js
  └── /node_modules

让我们在 src/print.js 文件中添加一些逻辑:

src/print.js

js 复制代码
export default function printMe() {
  console.log("I get called from print.js!");
}

并在 src/index.js 文件中使用该函数:

src/index.js

diff 复制代码
 import _ from 'lodash';
+import printMe from './print.js';

 function component() {
   const element = document.createElement('div');
+  const btn = document.createElement('button');

   element.innerHTML = _.join(['Hello', 'webpack'], ' ');

+  btn.innerHTML = 'Click me and check the console!';
+  btn.onclick = printMe;
+
+  element.appendChild(btn);
+
   return element;
 }

 document.body.appendChild(component());

同时更新我们的 dist/index.html 文件,为 webpack 拆分入口做好准备:

dist/index.html

diff 复制代码
 <!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8" />
-    <title>Asset Management</title>
+    <title>Output Management</title>
+    <script src="./print.bundle.js"></script>
   </head>
   <body>
-    <script src="bundle.js"></script>
+    <script src="./index.bundle.js"></script>
   </body>
 </html>

现在调整配置。我们将 src/print.js 添加为新的入口点 (print),同时修改输出配置,以便根据入口点名称动态生成 bundle 名称:

webpack.config.js

diff 复制代码
 import path from 'node:path';
 import { fileURLToPath } from 'node:url';

 const __filename = fileURLToPath(import.meta.url);
 const __dirname = path.dirname(__filename);

 export default {
-  entry: './src/index.js',
+  entry: {
+    index: './src/index.js',
+    print: './src/print.js',
+  },
   output: {
-    filename: 'bundle.js',
+    filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
   },
 };

让我们运行 npm run build 并查看生成的结果:

bash 复制代码
...
[webpack-cli] Compilation finished
asset index.bundle.js 69.5 KiB [emitted] [minimized] (name: index) 1 related asset
asset print.bundle.js 316 bytes [emitted] [minimized] (name: print)
runtime modules 1.36 KiB 7 modules
cacheable modules 530 KiB
  ./src/index.js 406 bytes [built] [code generated]
  ./src/print.js 83 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 1996 ms

我们可以看到 webpack 生成了 print.bundle.jsindex.bundle.js 文件,这些文件也正是我们在 index.html 中指定的。如果你在浏览器中打开 index.html,点击按钮时可以看到控制台输出。

但是,如果我们更改了某个入口点的名称,或者新增了一个入口点,会发生什么情况呢?生成的 bundle 会在构建时被重命名,但我们的 index.html 文件仍会引用旧名称。让我们通过 HtmlWebpackPlugin 来解决这个问题。

T> 如果你检查过 print.bundle.js,可能会注意到它不包含 printMe 函数。相反,它只包含一个 IIFE,且没有可观察到的副作用。


这是因为在我们当前的配置中,webpack 将每个入口点视为一个独立的程序,在加载 bundle 时运行。由于 print.js 仅导出了一个函数而从未调用 printMe(),将其作为独立入口执行并不需要任何可执行的运行时代码。因此,webpack 会将其作为一种优化而省略掉该代码,因为它不会产生任何可观察到的效果。


相比之下,由于 index.js 导入并使用了 printMe,webpack 会将该函数直接包含在 index.bundle.js 中。请记住,webpack 是一个模块_打包器_,因此 index.bundle.js 包含了运行所需的所有代码,而不是未解析的 import 语句。


此处使用多个入口点仅仅是为了演示输出管理和 HtmlWebpackPlugin。在实际项目中,你通常应避免为此类工具模块创建单独的入口点。如果你的多个入口点共享依赖,请参阅代码分离指南中的 防止重复 部分。

设置 HtmlWebpackPlugin

首先安装插件并调整 webpack.config.js 文件:

bash 复制代码
npm install --save-dev html-webpack-plugin

webpack.config.js

diff 复制代码
 import path from 'node:path';
 import { fileURLToPath } from 'node:url';
+import HtmlWebpackPlugin from 'html-webpack-plugin';

 const __filename = fileURLToPath(import.meta.url);
 const __dirname = path.dirname(__filename);

 export default {
   entry: {
     index: './src/index.js',
     print: './src/print.js',
   },
+  plugins: [
+    new HtmlWebpackPlugin({
+      title: 'Output Management',
+    }),
+  ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
   },
 };

在进行构建之前,你应该知道 HtmlWebpackPlugin 默认会生成自己的 index.html 文件,即使我们在 dist/ 文件夹中已有一个。这意味着它将用新生成的文件替换我们的 index.html 文件。让我们看看执行 npm run build 会发生什么:

bash 复制代码
...
[webpack-cli] Compilation finished
asset index.bundle.js 69.5 KiB [compared for emit] [minimized] (name: index) 1 related asset
asset print.bundle.js 316 bytes [compared for emit] [minimized] (name: print)
asset index.html 253 bytes [emitted]
runtime modules 1.36 KiB 7 modules
cacheable modules 530 KiB
  ./src/index.js 406 bytes [built] [code generated]
  ./src/print.js 83 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 2189 ms

如果你在代码编辑器中打开 index.html,你会看到 HtmlWebpackPlugin 为你创建了一个全新的文件,并且所有的 bundle 都已自动添加进去。

如果你想了解更多关于 HtmlWebpackPlugin 提供的所有功能和选项,建议你阅读 HtmlWebpackPlugin 仓库。

清理 /dist 文件夹

你可能已经注意到,在之前的指南和代码示例中,我们的 /dist 文件夹变得相当杂乱。webpack 会为你生成文件并将它们放入 /dist 文件夹,但它不会跟踪哪些文件实际被你的项目使用。

通常,在每次构建前清理 /dist 文件夹是一个好习惯,这样只会生成需要的文件。让我们使用 output.clean 选项来处理这个问题。

webpack.config.js

diff 复制代码
 import path from 'node:path';
 import { fileURLToPath } from 'node:url';
 import HtmlWebpackPlugin from 'html-webpack-plugin';

 const __filename = fileURLToPath(import.meta.url);
 const __dirname = path.dirname(__filename);

 export default {
   entry: {
     index: './src/index.js',
     print: './src/print.js',
   },
   plugins: [
     new HtmlWebpackPlugin({
       title: 'Output Management',
     }),
   ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
+    clean: true,
   },
 };

现在运行 npm run build 并检查 /dist 文件夹。如果一切正常,你现在应该只看到构建生成的文件,而不再有旧文件了!

Manifest

你可能想知道 webpack 及其插件是如何“知道”生成了哪些文件的。答案就在 webpack 维护的 manifest 中,它记录了所有模块如何映射到输出 bundle。如果你有兴趣以其他方式管理 webpack 的 output,manifest 将是一个很好的起点。

可以使用 ManifestPlugin 将 manifest 数据提取到 json 文件中以供使用。

我们不会在项目中展示如何使用此插件的完整示例,但你可以阅读 概念页面缓存指南,了解这如何与长期缓存相关联。

总结

现在你已经了解了如何动态地向 HTML 中添加 bundle,让我们深入 开发指南。或者,如果你想深入了解更多高级主题,我们建议你阅读 代码分离指南

帮助我们改进文档

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