管理输出

目前为止,都是在 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 之间的映射。了解 manifest 将会帮助了解如何以其他方式控制 webpack 输出

WebpackManifestPlugin 插件可以将 manifest 数据提取为 json 文件。

参阅 manifest 概念页面以深入了解如何在项目中使用此插件,同时 缓存 指南介绍了其与长效缓存之间的关系。

总结

现在已经了解如何向 HTML 动态添加 bundle,接下来继续深入 开发环境 指南。如果想要深入更多相关高级话题,那么推荐前往 代码分离 指南。

8 位贡献者

skipjackTheDutchCodersudarsangpJGJPEugeneHlushkoAnayaDesignchenxsansnitin315

Webpack 5 现已正式发布。请阅读我们的 发布公告。如还未准备升级,请阅读 webpack 4 文档