使用Webpack的url-loader
,我将一些2300 40px x 30px png图标(小型神奇宝贝精灵)加载到一个数组中,产生约2.2MB的缩小JavaScript。这些图像和包装它们的模块实际上永远不会改变,也没有任何可以改变的依赖关系。我想将它们拉入一个单独的js文件,以便在运行webpack --watch
时,每次我更改依赖于该图像数组的代码时,Webpack都不会触发这些图像的重新提取和缩小,过程大约需要20秒。
以前,对于这样的事情,我使用了一个单独的入口点和CommonsChunkPlugin
,如Webpack文档的Code Splitting部分所述。 (我不知道这是否是假设的使用方式,但它有效。)由于Webpack 4弃用了CommonsChunkPlugin
,因此不再可行,但我不能弄清楚如何使用它的替代品config.optimization.splitChunks
来达到同样的效果。
由于某种原因,Webpack弃用了CommonsChunkPlugin
而使用webpack.optimization.splitChunks
配置,使用CommonsChunkPlugin
在初始化时抛出错误,然后没有更新他们的code splitting documentation反映这种变化。我找了几个小时的官方文档splitChunks
以及如何使用它,我找到的最接近的是"RIP CommonsChunkPlugin" gist和Medium.com article,它只给出了对更改的高级解释
client/pokemon-icons.js
import Pokedex from 'pokedex'; // has no dependencies
class PokemonIcons {
constructor() {
let req = require.context('../resources/icons/regular', false, /\.png$/);
req.keys().forEach(fn => {
let species = /([-a-zA-Z0-9]+)\.png$/.exec(fn)[1];
this[species] = { regular: req(fn) };
});
req = require.context('../resources/icons/shiny', false, /\.png$/);
req.keys().forEach(fn => {
let species = /([-a-zA-Z0-9]+)\.png$/.exec(fn)[1];
this[species].shiny = req(fn);
});
let egg = require('../resources/icons/egg.png');
this.egg = { regular: egg, shiny: egg };
}
getIcon(pokemon) {
return this[Pokedex.FileNames[pokemon.species]][pokemon.shiny];
}
}
const icons = new PokemonIcons();
export default icons;
文档提供了几种方法来告诉Webpack将代码提取到自己的块文件中。
require.ensure()
“旧”方法使用require.ensure()
来加载一组模块,并在加载模块后调用回调。
client/soullink/index.js
示例require.ensure(['../pokemon-icons'], () => {
const config = require('config.json');
if (config.someFlag) {
require('./some-js'); // does not rely on `pokemon-icons.js`
} else {
require('./some-other-js'); // has dependencies which rely on `pokemon-icons.js`
}
});
实际上,这个方法确实创建了一个单独的块文件,但每次更改其他代码时,仍会重新生成该块文件。
import()
“新”方法使用import()
返回Promise
。或者,对于babel的babel-ployfill
和babel-preset-2017
,我们可以使用await
语法。
Promise
语法import('../pokemon-images').then(icons => {
let icon = icons.getIcon(...);
// ...
});
await
语法async function getIcon(...args) {
let icons = await import('../pokemon-images');
return icons.getIcon(...args);
}
我无法让这些方法生成单独的块文件,更不用说缓存它了。
这些方法都不是理想的,因为在回调,承诺和异步函数中包装所有内容都很痛苦,特别是因为我在类的构造函数中调用getIcon()
,这可能是'被标记为异步(它很简单,可以解决这个问题,但仍然令人讨厌)。
我不知道它是否重要,但我正在使用HtmlWebpackPlugin
使用ejs-loader
生成HTML文件,然后插入对插件{{1}中列出的入口点的引用选项数组。
我的配置还会编译两个入口点和两个需要相关条目的chunks
。
这些是我的webpack配置文件的相关部分。
HtmlWebpackPlugin
我尝试过添加
import webpack from 'webpack';
import fs from 'fs';
import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
function genConfig(env, options) {
return {
entry: {
index: './client/slot-display/index',
soullink: './client/soullink-manager/index', // this is the entry that requires pokemon-icons.js
vendors: [ 'lodash' ],
},
output: {
filename: '[name].js',
chunkFilename: '[name].js',
path: path.resolve(__dirname, 'public')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.ejs$/,
loader: 'ejs-loader',
},
{
test: /\.png$/,
use: [
'url-loader'
]
}
],
},
plugins: [
new webpack.ProvidePlugin({
_: 'lodash',
}),
new HtmlWebpackPlugin({
template: '!!ejs-loader!./client/slot-display/index.ejs',
filename: 'index.html',
chunks: ['index'],
inject: 'body',
cache: true
}),
new HtmlWebpackPlugin({
template: '!!ejs-loader!./client/soulLink-manager/index.ejs',
filename: 'soullink/index.html',
chunks: ['soullink'],
inject: 'body',
cache: true
})
]
};
}
export default genConfig;
和
optimization: {
splitChunks: {
chunks: 'all', // with and without this line
cacheGroups: { // with and without this object
default: false, // with and without this line
pokemonIcons: {
test: /pokemon-icons\.js$/, // with and without this line
name: 'pokemon-icons', // also 'pokemonIcons'
minChunks: Infinity
}
}
}
}
并根据需要进行设置:
entry: {
pokemonIcons: './client/pokemon-icons', // with and without this separate entry
// the various soullink entries I've tried:
soullink: './client/soullink-manager/index',
soullink: [ './client/pokemon-icons', './client/soullink-manager/index' ],
soullink: [ 'babel-polyfill', './client/soullink-manager/index' ],
soullink: [ 'babel-polyfill', './client/pokemon-icons', './client/soullink-manager/index' ],
}