如何将 Webpack 4 SplitChunksPlugin 与 HtmlWebpackPlugin 一起用于多页应用程序?
Posted
技术标签:
【中文标题】如何将 Webpack 4 SplitChunksPlugin 与 HtmlWebpackPlugin 一起用于多页应用程序?【英文标题】:How to use Webpack 4 SplitChunksPlugin with HtmlWebpackPlugin for Multiple Page Application? 【发布时间】:2018-11-21 00:43:54 【问题描述】:我正在尝试利用 SplitChunksPlugin 为 MPA 中的每个页面/模板生成单独的包。当我使用 htmlWebpackPlugin 时,我会为每个页面获取一个 html 文件,其中包含指向正确包的脚本标记。这太棒了!但是,我遇到的问题是我的供应商文件。我希望单独的 html 文件仅指向他们需要的供应商捆绑包。当 SplitChunksPlugin 创建多个供应商捆绑包时,我无法让每个单独的 html 文件指向正确的供应商捆绑包。生成的捆绑包是:
home.bundle.js
product.bundle.js
cart.bundle.js
vendors~cart~home~product.bundle.js
vendors~cart~product.bundle.js
所以基本上 home 模板应该引用 home.bundle.js、vendors~cart~home~product.bundle.js,而不是第二个 vendor bundle。只有购物车和产品模板应该引用这两个供应商捆绑包。我正在使用 HtmlWebpackPlugin 的 chunks 选项,但除非我像这样明确引用它的名称,否则无法让它提取正确的供应商包:
chunks: ['vendors~cart~home~product.bundle','home']
但这有点违背了动态呈现脚本标签的目的。我尝试创建一个供应商入口点,但这将我所有的供应商聚集在一起。 我缺少一些简单的配置吗?
我的 webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const Visualizer = require('webpack-visualizer-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports =
mode: 'development',
devtool: 'cheap-module-eval-source-map',
entry:
home: './src/js/page-types/home.js',
product: './src/js/page-types/product.js',
cart: './src/js/page-types/cart.js'
,
output:
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist/js')
,
optimization:
splitChunks:
chunks: 'all'
,
plugins: [
new CleanWebpackPlugin(['dist']),
new Visualizer(),
new HtmlWebpackPlugin(
filename: 'home.html',
chunks: ['vendors','home']
),
new HtmlWebpackPlugin(
filename: 'product.html',
chunks: ['vendors','product']
),
new HtmlWebpackPlugin(
filename: 'cart.html',
chunks: ['vendors~cart~product','cart']
),
], ...
我的 js 模块:
/* home.js */
import jQuery from 'jquery';
import 'bootstrap';
cart 和 product 也引用了 react 库:
/* cart.js */
import jQuery from 'jquery';
import 'bootstrap';
import React from 'react';
import ReactDOM from 'react-dom';
/* product.js */
import jQuery from 'jquery';
import 'bootstrap';
import React from 'react';
import ReactDOM from 'react-dom';
示例html输出home.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack App</title>
</head>
<body>
<script type="text/javascript" src="home.bundle.js"></script></body>
</html>
【问题讨论】:
不是每个块都会有 react、jquery 和 bootstrap 吗?理想情况下,我们希望它们位于单独的供应商文件中,这样它就不会被复制到每个块中? @anvarik 非常好的问题。我知道我最初有同样的问题,因为我们不希望浏览器不得不一遍又一遍地重复下载库。这将与我们试图实现的性能背道而驰。幸运的是,webpack 已经通过 SplitChunksPlugin 自动处理了这个问题。它会智能地将您的所有供应商拆分为单独的捆绑包,并根据您导入它们的方式将一些供应商组合成一个捆绑包。您可以在此处查看相关文档:webpack.js.org/guides/code-splitting/#splitchunksplugin 【参考方案1】:一种选择是手动创建您的供应商块,然后将页面所需的任何块包含在HtmlWebpackPlugin
的chunks
选项中。
webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const Visualizer = require('webpack-visualizer-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports =
mode: 'development',
devtool: 'cheap-module-eval-source-map',
entry:
home: './src/js/page-types/home.js',
product: './src/js/page-types/product.js',
cart: './src/js/page-types/cart.js'
,
output:
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist/js')
,
optimization:
splitChunks:
cacheGroups:
'vendor-bootstrap':
name: 'vendor-bootstrap',
test: /[\\/]node_modules[\\/](jquery|bootstrap)[\\/]/,
chunks: 'initial',
priority: 2
,
'vendor-react':
name: 'vendor-react',
test: /[\\/]node_modules[\\/]react.*?[\\/]/,
chunks: 'initial',
priority: 2
,
'vendor-all':
name: 'vendor-all',
test: /[\\/]node_modules[\\/]/,
chunks: 'initial',
priority: 1
,
,
plugins: [
new CleanWebpackPlugin(['dist']),
new Visualizer(),
new HtmlWebpackPlugin(
filename: 'home.html',
chunks: ['vendor-bootstrap', 'vendor-all', 'home']
),
new HtmlWebpackPlugin(
filename: 'product.html',
chunks: ['vendor-bootstrap', 'vendor-react', 'vendor-all', 'product']
),
new HtmlWebpackPlugin(
filename: 'cart.html',
chunks: ['vendor-bootstrap', 'vendor-react', 'vendor-all', 'cart']
),
], ...
vendor-all
块用于捕获未包含在其他块中的任何其他供应商库。
【讨论】:
很好的尝试。但我永远不会为我的项目推荐这种方法。维护这些块和模块依赖会很烦人。 从长远来看这很难维护,html-webpack-plugin 的 4.x 版本足够智能,无需进一步配置即可在模板中包含正确的块集,这是我想要的推荐使用。 @dennisbot 是的,试过了,像魅力一样工作。【参考方案2】:使用 html-webpack-plugin 的第 4 版(现在处于测试阶段),并且只在 chunks 选项中包含入口块。
npm i -D html-webpack-plugin@next
和
module.exports =
new HtmlWebpackPlugin(
filename: 'home.html',
chunks: ['home']
),
new HtmlWebpackPlugin(
filename: 'product.html',
chunks: ['product']
),
new HtmlWebpackPlugin(
filename: 'cart.html',
chunks: ['cart']
),
;
这将自动包含相关的块。
【讨论】:
我实际上在 HtmlWebpackPlugin 版本 3 中扩展了一个方法来解决这个问题,但我不喜欢我的解决方案。对于另一个项目,我使用了这个解决方案。 @nilptr 这与新版本 4 测试版完美配合。谢谢! @Dave 对于那些宁愿仍然使用 HtmlWebpackPlugin 3 的好奇的少数人,您介意给出您的解决方案的概要作为答案吗?我认为管理层不会太喜欢我使用测试版软件。以上是关于如何将 Webpack 4 SplitChunksPlugin 与 HtmlWebpackPlugin 一起用于多页应用程序?的主要内容,如果未能解决你的问题,请参考以下文章
错误:webpack.optimize.CommonsChunkPlugin 已被移除,请改用 config.optimization.splitChunks
前端资讯Webpack 4 将移除 CommonsChunkPlugin
Webpack项目优化之CDN加速Gzip压缩和SplitChunks拆分
Webpack splitChunks 插件 - 为啥设置块的优先级使其初始化异步?
webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks ins