webpack-分包相关知识记录

256 阅读4分钟

webpack 分包的好处

  1. 单个包太大影响首屏渲染速度(出现白屏)
  2. 可以按需加载文件
  3. 可以分割更小的包,加载更快
  4. 可以控制资源的加载优先级, 提供代码的加载性能

入口起点

  • 使用 entry 配置手动分离代码, 配置多入口的方式。如:
module.exports = {
	/**
	 * 可以将entry配置成一个对象就可以配置多个入口,webpack打包的时候会分别打包
	 * 注意: 还需要配置 filename,不然webpack不知道要打包那个文件
	 * 问题?: 如果多个入口文件都用了同一个包webpack在打包的时候都会打包到对应的js文件中,该怎么处理? (入口依赖)
	 * 回答: 通过配置单独的包,然后在配置入口的时候依赖这个包,从而解决多个入口依赖相同的包
	 */
	entry: {
		// 相同依赖的库单独打包
		common: ['axios'],
		// 写成对象的形式,
		index: {
			// import 打包时从哪个文件开始
			import: './src/index.js',
			// 可以通过 dependOn 属性表示要依赖哪个包, 在打包时就会去找这个common的依赖
			dependOn: 'common'
		},
		main: {
			import: './src/main.js',
			dependOn: 'common'
		}
	},
};

自定义分包

  • 使用 SplitChunksPlugin 去重和分离代码。如:
module.exports = {
	entry: './src/main.js',
	output: {
		path: path.resolve(__dirname, 'dist'),
		filename: '[name]-bundle.js',
		clean: true,
		chunkFilename: '[name]-chunk.js'
	},
	devServer: {
		open: true
	},
	// 优化配置
	optimization: {
		/**
		 * 生成chunkId的算法配置
		 * named: 根据完整的文件路径名生成名称
		 * deterministic: 在不同的环境中生成相同的值
		 * natural: 在webpack4中有,使用顺序的id值
		 *
		 * 推荐: 在生成环境中使用 deterministic, 在开发环境中使用 named
		 */
		chunkIds: 'deterministic',
		/**
		 * 配置运行时所有chunk需要用到的代码打包待一个包中
		 */
		runtimeChunk: {
			// 设置包的名称
			name: 'runtime'
		},
		/**
		 * 自定义拆分模块分包,在 production 环境下默认开启
		 * 默认是对 node_module 目录下导入的包进行拆包
		 */
		splitChunks: {
			/**
			 * chunks: 配置那些模块需要进行分包操作,默认值 async,
			 * 属性值:
			 *  - async: 只有动态导入的模块会进行分包操作
			 *  - all: 所有通过导入的模块都会进行分包, 打包到同一个包中
			 *
			 * 还可以写出函数形式,根据name判断那些包需要进行分包
			 */
			chunks: 'all',
			// chunks: (chunk) => {
			// 	return chunk.name == 'about';
			// },

			/**
			 * 当一个包大于指定的大小时,继续进行拆包(byte单位)
			 */
			// maxSize: 20000,
			/**
			 * 将包拆分成小于minSize的包
			 */
			// minSize: 10000,

			/**
			 * 自定义对需要拆包的内容进行拆分
			 */
			minSize: 100,
			cacheGroups: {
				vendors: {
					// 通过匹配路径来进行拆包,在node_module下导入的代码都拆分成一个包
					test: /[\\/]node_modules[\\/]/,
					filename: '[id]_vendors.js'
				},
				utils: {
					// 在utils下导入的代码都拆分成一个包
					test: /utils/,
					filename: '[id]_utils.js'
				}
			}
		}
	},
};

动态导入

  • 通过 import 函数动态导入代码 webpack 会单独进行分包, 用不到的代码就不需要打包,在需要使用的时候在在加载下来。如:
import('xxx.js')

Prefetch(预获取) 和 Preload(预加载)

prefetch

  • 作用: 在浏览器空闲时下载包
  • 用法: 在使用 import 函数时通过添加魔法注释 /* webpackPrefetch: true */ 告诉 webpack 这个是需要预请求的。如:
import(
  /* webpackPrefetch: true */
  'xxx.js'
)

preload

  • 作用: 可以让拆分的包跟随主包下载时并行下载
  • 用法: 在使用 import 函数时通过添加魔法注释 /* webpackPreload: true */ 告诉 webpack 这个是需要预请求的。如:
import(
  /* webpackPreload: true */
  'xxx.js'
)

CDN 方式

webpack.config.js 中

module.exports = {
	/**
	 * cdn引入第三方包:
	 *  1. 先排除需要的第三方包
	 *  2. 在index.html中引入你要的第三方包的cdn
	 */
	// 排除那些包不需要进行打包
	externals: {
		// key(属性值): 要排除的库的名称
		// value(值): 是要使用第三方包的全局变量
		react: 'React',
		axios: 'axios'
	},
};

index.html 中:

<!-- 通过引入cdn的方式使用第三方包 -->
<script src="https://cdn.bootcdn.net/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.min.js"></script>

CSS 样式抽离(MiniCssExtractPlugin)

  • 作用: 将 CSS 抽离到单独的的文件当中
  • 用法:
moduel.exports = {
  plugins: [
    // 1. 在plugins中使用 MiniCssExtractPlugin
		new MiniCssExtractPlugin({
			filename: '[name].css',
			chunkFilename: '[name]_chunk.css'
		})
	],
  module: {
    // 2. 在匹配规则中使用MiniCssExtractPlugin的loader和css-loader处理 .css 后缀的文件
		rules: [{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] }]
  }
}

占位符(placeholders)

[id]: 会根据配置的 chunksId 生成对应的算法

webpack.config.js

module.exports = {
	output: {
    // id的值就是根据chunkIds配置的属性值生成的值
		filename: '[id]-bundle.js',
		chunkFilename: '[id]-chunk.js'
	},
    /**
		 * 生成chunkId的算法配置
		 * named: 根据完整的文件路径名生成名称
		 * deterministic: 在不同的环境中生成相同的值
		 * natural: 在webpack4中有,使用顺序的id值
		 *
		 * 推荐: 在生成环境中使用 deterministic, 在开发环境中使用 named
		 */
  optimization: {
		chunkIds:'deterministic',
	}
}

[hash]:

  • 作用: 根据 chunk 的内容生成值,每次内容改变都会重新生成新的值
  • 比如: 有个 main.js 页面,你改变了 main.js 中的内容,那么打包后的 hash 值就会改变

webpack.config.js

module.exports = {
	output: {
		filename: '[hash]-bundle.js',
		chunkFilename: '[hash]-chunk.js'
	},
}

[chunkhash]:

  • 作用: 根据 chunk 的内容生成值,每次内容改变都会重新生成新的值。
  • 注意: 如果导入的模块也做了分包处理,那么导入模块的 chunk 的 hash 值也会改变

webpack.config.js

module.exports = {
	output: {
		filename: '[chunkhash]-bundle.js',
		chunkFilename: '[chunkhash]-chunk.js'
	},
}

[contenthash]:

  • 作用: 根据 chunk 的内容生成值,每次内容改变都会重新生成新的值。
  • 注意: contenthash只会改变当前改变模块 chunk 的 hash 值,导入的模块做了分包处理的话 hash 值不会改变,可以解决 chunkhash 的问题

webpack.config.js

module.exports = {
	output: {
		filename: '[contenthash]-bundle.js',
		chunkFilename: '[contenthash]-chunk.js'
	},
}