移动spa商城优化记(二)--- 减少70%的打包等待时间

5,263 阅读6分钟

背景

上篇讲了首屏优化,具体文章详见移动spa商城优化记(一)---首屏优化篇,这次来分享一下打包速度的一些优化经验,因为在实际项目开发中,随着项目的不断增大,依赖项不断增多,我们会发现webpack打包速度会越来越慢,有时候npm run一下可能出去上个厕所的时间都够了,在这快速发展的时代,这么拖节奏的事情绝不允许,本篇还是以公司spa商城为例,详细介绍一下优化打包速度方面的经验。

开始

公司这个项目的起手模板是vue-cli的webpack模板,项目完成大概有将30个页面,未经优化前打包时间如图:

优化前的时间
大概两分钟左右,是不是出去上个厕所的时间都够了。

接下来开始优化,优化主要分四方面:减少打包文件数量,减少不必要的功能开销,优化打包方式,升级打包工具。

1.减少打包文件数量

指导思想:要打包的东西少了速度自然就快了。

1.dll

webpack.DllPlugin + webpack.DllReferencePlugin这组插件应该是借鉴了dll的思想所以叫dllplugin这个名字,目的就是将vue,vue-router,react,jquery等等这些体积较大,项目中不常更新的第三方包抽离出来单独打包,然后告诉webpack这些包我之前已经打包过了,你每次打包直接用就行了,不用每次再去重新打包一次了。

使用方法:

  1. build文件夹下新建一个webpack.dll.conf.js,内容可以这样写:
const path = require('path')
const webpack = require('webpack')

module.exports = {
    entry:{
        //这地方写你想抽离的包,可以参考你的package.json文件下的dependencies
        vue:['vue','vue-router'] 
    },
    output:{
        //这地方写你打包后生成文件的路径
        path:path.join(__dirname,"../src/dll"),
        filename:'[name].dll.js',
        library:'[name]'
    },
    plugins:[
        //这个插件是重点,用于打包上面entry里配置的包
        new webpack.DllPlugin({
            path:path.join(__dirname,"../src/dll",'[name]-manifest.json'),
            name:'[name]',
        }),
        new webpack.optimize.UglifyJsPlugin()
    ]
}

  1. 执行 webpack --config build/webpack.dll.conf.js打包生成抽离的公共包。
    此时src下应该能看到dll目录及生成的公共包js及json。
    公共包js及json
  2. 正常webpack配置文件里配置DllReferencePlugin进行关联
 plugins: [
        new webpack.DllReferencePlugin({
            //这里写上一步打包出的json路径
            manifest:require('../src/dll/vue-manifest.json')
        })
        ......
    ]

现在,再次打包就可以了,你提取出的第三方包越多,打包速度优化的越明显。如果想让打包出的html可以自动引入第二步打包出的dll.js文件,可以使用add-asset-html-webpack-plugin或者自己修改HtmlWebpackPlugin的配置实现打包出的html内自动引入dll.js文件。

关于HtmlWebpackPlugin详细配置可以看这篇文章:
html-webpack-plugin用法全解
关于add-asset-html-webpack-plugin详细配置可以看这篇文章:
add-asset-html-webpack-plugin配置

另外使用cdn引入包然后加 externals配置的方式也可以,思路和dll一致,都是抽离第三方包,只打包业务代码,只不过这种方式第三方包直接引用cdn上的。

2.减少不必要的resolve

  1. 看下webpack的每个rule下面include里面是不是有多余的resolve,或者看看有没有把node_modules文件夹exclude掉。
  2. 用到babel-loader的地方,记得设置cacheDirectory,以利用bable的缓存。
  3. resolve里面的extensions可以删除不必要的后缀名自动补全,减少webpack的查询时间,比如extensions: ['.js', '.vue', '.json','.scss','.css'],写这么多自动补全写代码的时候是省了后缀名了,但是这需要webpack打包时去自动查询后缀增加了时间开销。
  4. import时多使用完整路径而不是目录名,如import './components/scroll/index.js'而不是import './components/scroll,减少webpack的路径查询。

2.去除不必要的功能开销

指导思想:减少打包过程中要做的额外的工作

我们的目的就是优化打包速度,那么与这个无关的不必要的功能可以先暂停掉,用到时再开。

关掉source map。

sourcemap有以下几个配置值:

eval: 生成代码 每个模块都被eval执行,并且存在@sourceURL

cheap-eval-source-map: 转换代码(行内) 每个模块被eval执行,并且sourcemap作为eval的一个dataurl

cheap-module-eval-source-map: 原始代码(只有行内) 同样道理,但是更高的质量和更低的性能

eval-source-map: 原始代码 同样道理,但是最高的质量和最低的性能

cheap-source-map: 转换代码(行内) 生成的sourcemap没有列映射,从loaders生成的sourcemap没有被使用

cheap-module-source-map: 原始代码(只有行内) 与上面一样除了每行特点的从loader中进行映射

source-map: 原始代码 最好的sourcemap质量有完整的结果,但是会很慢

当我们不需要调试时,可以关掉sourcemap或降低sourcemap的级别来加快打包的速度。

3.优化打包方式:并行

指导思想:并行打包速度当然快。

1.UglifyJSPlugin并行

这个比较好配置,UglifyJSPlugin插件下加一个属性parallel设为true即可。

new UglifyJSPlugin({
        parallel: true
        ......
})

还可以设置打包缓存,具体见下面的配置

UglifyJSPlugin

2.Happypack

Happypack通过多进程模型,来加速代码构建。
比如说以前使用vue-loader处理vue文件,以前是串行处理,现在利用happypack可以并行使用vue-loader处理vue文件。

  1. 首先安装HappyPack
    npm install --save-dev happypack
  2. 修改webpack.base.config.js
const HappyPack = require('happypack');
const vueLoaderConfig = require('./vue-loader.conf')
exports.module = {
  rules: [
    {
      test: /\.vue$/,
      //vue-loader替换为happypack/loader,如果遇到vue文件就用happypack,id指定为vue
      loader: 'happypack/loader?id=vue'
    },
    {
        test: /\.js$/,
      //babel-loader替换为happypack/loader,如果遇到js文件就用happypack,id指定为js
        loader: 'happypack/loader?id=js'
    }
    ......
  ]
};
 
exports.plugins = [
  new HappyPack({
    id:'vue',
    //同时开多少线程进行打包,也可以用ThreadPool控制
    threads: 4,
    loaders: [{
        //这是真实的处理loader,具体配置和rules里原本的一致,options也照搬过来就行
        loader:'vue-loader',
        options:vueLoaderConfig
    }]
  }),
  new HappyPack({
    id: 'js',
    threads: 3,
    loaders: [{
        loader:'bable-loader',
    }]
  })
  ......
];

经过以上配置,我们就可以使用happypack愉快的进行打包了。

更多高级配置可以看文档:Happypack文档

另外,想了解happypack原理的可以看淘宝团队的这篇文章:happypack 原理解析

4.升级打包工具

指导思想:鸟枪换大炮,升级打包工具。

  1. 升级node
  2. 升级webpack
    webpack4比3快,3比2快,推荐webpack至少升到3以上,4还不太稳定,强行升级坑较多。
  3. 升级各种loader

很多时候,大神们在冥冥之中已经帮我们在底层做了优化,我们根本不需要做什么配置,我们只需要升级工具即可,当然,升级的同时要保证项目的健壮性。

最后

一图胜千言,这是经过优化后的打包时间:

优化后的时间

打包时间从原来的的120s减少到了现在的34s,优化率70%以上。再也不用每次npm run 一下就先去上个厕所了。。。

参考文章:
使用 webpack 定制前端开发环境
webpack打包优化解决方案