管理输出

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

预先准备

首先,调整一下我们的项目:

project

  webpack-demo
  |- package.json
  |- package-lock.json
  |- webpack.config.js
  |- /dist
  |- /src
    |- index.js
+   |- print.js
  |- /node_modules

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

src/print.js

export default function printMe() {
  console.log('I get called from print.js!');
}

并且在 src/index.js 文件中使用这个函数:

src/index.js

 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

 <!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8" />
-    <title>管理资源</title>
+    <title>管理输出</title>
+    <script src="./print.bundle.js"></script>
   </head>
   <body>
-    <script src="bundle.js"></script>
+    <script src="./index.bundle.js"></script>
   </body>
 </html>

接下来调整配置。我们将在 entry 添加 src/print.js 作为新的入口起点(print),然后修改 output,使得根据入口起点定义的名称,动态生成 bundle 名称:

webpack.config.js

 const path = require('path');

 module.exports = {
-  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,然后看到输出如下:

...
[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.4.0 compiled successfully in 1996 ms

可以看到,webpack 将会生成 print.bundle.jsindex.bundle.js 文件,这也和我们在 index.html 文件中指定的文件名称相对应。试试在浏览器中打开 index.html,看看点击按钮时会发生什么。

但是,如果更改入口起点的名称,或者添加一个新的入口,那么会在构建时重新命名生成的 bundle,但是 index.html 仍然在引用旧的名称!我们可以使用 HtmlWebpackPlugin 来解决这个问题。

设置 HtmlWebpackPlugin

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

npm install --save-dev html-webpack-plugin

webpack.config.js

 const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   entry: {
     index: './src/index.js',
     print: './src/print.js',
   },
+  plugins: [
+    new HtmlWebpackPlugin({
+      title: '管理输出',
+    }),
+  ],
   output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
   },
 };

在执行构建之前,你应该了解,虽然在 dist/ 文件夹我们已经有了 index.html 这个文件,但是 HtmlWebpackPlugin 还是会默认生成它自己的 index.html 文件。换言之,它会用新生成的 index.html 文件,替换原有文件。看看执行 npm run build 后会发生什么:

...
[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.4.0 compiled successfully in 2189 ms

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

如果想要了解 HtmlWebpackPlugin 插件提供的全部的功能和选项,请阅读 HtmlWebpackPlugin 仓库中的源码。

清理 /dist 文件夹

你可能已经注意到,由于遗留了之前的指南的代码示例,/dist 文件夹显得相当杂乱。webpack 将生成文件并放置在 /dist 文件夹中,但是它不会追踪哪些文件是实际在项目中用到的。

通常比较推荐的做法是,在每次构建前清理 /dist 文件夹,这样只会生成用到的文件。可以使用 output.clean 配置项实现这个需求。

webpack.config.js

 const path = require('path');
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   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 插件似乎“知道”应该生成哪些文件 —— webpack 通过 manifest 追踪所有模块到输出 bundle 之间的映射。如果你想要知道如何以其他方式来控制 webpack 输出,了解 manifest 是个好的开始。

WebpackManifestPlugin 插件可以将 manifest 数据提取为一个 json 文件以供使用。

我们不会在此展示如何在项目中使用此插件,你可以在 manifest 概念页面深入阅读,以及在 缓存 指南中了解它与长效缓存有何关系。

总结

现在,你已经了解如何向 HTML 动态添加 bundle,让我们深入 开发环境 指南。或者如果你想要深入更多相关高级话题,我们推荐你前往 代码分离 指南。

9 位贡献者

skipjackTheDutchCodersudarsangpJGJPEugeneHlushkoAnayaDesignchenxsansnitin315Yucohny