输出管理
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.js 和 index.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,让我们深入 开发指南。或者,如果你想深入了解更多高级主题,我们建议你阅读 代码分离指南。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
