在上一节中,我们从开发体验角度讲解了如何优化项目中的 webpack 配置,主要是如何提升 webpack 的构建速度。除了开发体验,输出质量也是在构建过程中很重要的一个性能指标。本篇文章我们带大家一起来看下如何提升 webpack 构建产物的质量。我们的目的主要是减小打包后文件的体积大小、并且可以按需引入、以及压缩混淆代码,提高用户体验。下面是本篇文章的脑图,大家先睹为快。
# 代码分割
在项目中,一般是使用同一套技术栈和公共资源。那么如果每个页面的代码中都有这些公开资源,是不是就会导致资源的浪费呢?在每一个页面下都会加载重复的公共资源,一是会浪费用户的流量,二是不利于项目的性能,造成页面加载缓慢,影响用户体验。
基本思路就是我们先要确定哪些是我们项目中使用内容长期不会更改的三方库(react、react-dom 等)和我们团队内部自己封装的公共 JS(util.js 等)。然后将其提取出放入到一个公共文件 common.js 中。这样,只要不升级基础库的版本,那么 common.js 文件的内容就不会变化,在访问页面的时候,就可以一直使用浏览器缓存中的资源。
在了解了提取公共代码的思路之后,我们看下在 webpack 中,怎么具体实现。在 webpack3 中我们可以使用 CommonChunkPlugin 这个插件来提取公共代码。我们希望提取第三方依赖库(这里只写了 react)作为公共代码实现持久缓存,这样配置的话,如果业务代码产生了改动,那么重新构建出来的 vendor 包的 hash 是不会变化的。可以进行如下配置:
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: {
main: './index.js',
vendor: ['react']
},
output: {
filename: '[chunkhash:8].[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor'],
filename: '[name].js'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
filename: '[name].js',
chunks: ['vendor']
}),
]
}
在 webpack4 中,移除了 CommonChunkPlugin,取而代之的是 optimization.splitChunks 和 optimization.runtimeChunk。我们创建一个 commons 代码块,其包含了所有被其他入口共享的代码,同时也创建一个 vendors 的代码块,其包含了整个应用来自 node_modules 的代码,也可以实现提取公共代码的功能。其配置如下:
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: "commons",
chunks: "initial",
minChunks: 2
},
vendors: {
test: /[\/]node_modules[\/]/,
name: "vendors",
chunks: "all"
}
}
}
}
}
# 按需加载
# 路由组件按需加载
在我们使用 react 的时候,React Router 就有一套自己的按需加载的方案,可以实现对路由按需加载。也就是只加载当前路由匹配的组件代码,不加载其他组件的代码。
我们要让路由动态加载,需要将 component方法 换成 getComponent方法,getComponent 这个方法可以异步进行加载组件,也就是只有当前路由被匹配时,才会调用到这个方法。使用姿势如下:
import { createHashHistory } from "history";
const rootRoute = {
path: '/',
indexRoute: {
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('components/HelloWorld'))
}, 'HelloWorld')
},
},
}
ReactDOM.render(
(
<Router history: createHashHistory(), routes={rootRoute}/>
), document.getElementById('root')
);
