Webpack 分割文件的正确方法

本文代码中所用的Webpack版本为4.0+。

打包为一个文件

Webpack把每个输出的JS文件名称都改写为一个独一无二的名字来强制浏览器拉取最新版本的JS文件。

module.exports = {
	// js 文件入口
	entry: path.resolve(__dirname, 'src/main.js'),
	output: {
		path: path.resolve(__dirname, 'dist'),
		filename: '[name].[contenthash].js',
	},
};

上面的配置通过给文件名附加内容Hash来形成一个唯一的名称。

将vendor单独打包为一个文件

因为项目依赖的Vendor不会频繁发生修改,所以不需要客户端浏览器每次都去请求这部分内容,我们可以将vendor内容单独打包出来。

module.exports = {
	// js 文件入口
	entry: path.resolve(__dirname, 'src/main.js'),
	output: {
		path: path.resolve(__dirname, 'dist'),
		filename: '[name].[contenthash].js',
	},
	optimization: {
		splitChunks: {
			chunks: 'all',
		},
	},
};

上面的optimization配置告诉Webpack将node_modules中所用到的依赖文件单独打包成一个vendor~main.js文件。

将vendor分开打包为多个文件

虽然上面将vendor单独打包为一个文件解决了每次更新都会去请求依赖的情况,但有时我们也会更新某个依赖,如果将这些需要更新的依赖
也单独打包就完美了。

const path = require('path');
const webpack = require('webpack');

module.exports = {
	entry: path.resolve(__dirname, 'scr/index.js'),
	plugins: [
		new webpack.HashedModuleIdsPlugin(), // 生成稳定的模块ID,防止因为ID的变化内容没变而导致Hash的变化。
	],
	output: {
		path: path.resolve(__dirname, 'dist'),
		filename: '[name].[contenthash].js',
	},
	optimization: {
		runtimeChunk: 'single',
		splitChunks: {
			chunks: 'all',
			maxInitialRequests: Infinity,
			minSize: 0,
			cacheGroups: {
				vendor: {
					test: /[\\/]node_modules[\\/]/,
					name(module) {
						// get the name. E.g. node_modules/packageName/not/this/part.js
						// or node_modules/pakcageName
						const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
						
						// npm package names are URL-safe, but some server doesn't like @ symbols
						return `npm.${packageName.replace('@', '')}`;
					},
				},	
			},
		},
	},
}