美文网首页
【实战篇】基于vue-cli4创建的项目进行打包优化

【实战篇】基于vue-cli4创建的项目进行打包优化

作者: Equicy_前端开发 | 来源:发表于2021-08-02 20:59 被阅读0次

    一、前言

    阅读完该文章大概需要2.5min。

    • 读完该篇文章你能学到

      1. vue-cli默认做了哪些优化?
      2. 在cli的基础上我们又能做哪些优化?
      3. vue.config.js中如何配置一些常用的pluginloader
    • vue-cli的出现,让我们省掉了配置webpack的时间。也就是说,一个不懂webpack的人,也能直接上手开发。比如file-loader, url-loader会提前为我们配置好。

    • 性能方面vue-cli也默认尽可能多的帮我们做了优化,比如cache-loader会在项目中预先做了配置。我们可以在控制台输入vue inspect > webpack.config.js,即可在webpack.config.js文件中查看cli预先定义好的基础配置。我们今天就在vue-cli搭建好的项目基础上聊一聊可优化的点。

    二、项目源码

    本文所用到的项目源码

    三、量化指标

    1. build时间

    speed-measure-webpack-plugin插件可以在build的时候看到webpack的loader和plugin所用的时间,配置非常简单。如下:

    // vue.config.js
    module.exports = {
    chainWebpack: config => {
       config.plugin('speed')
       .use(SpeedMeasureWebpackPlugin)
     }
    }
    

    顺便看一下效果


    屏幕快照 2021-07-31 下午4.57.58.png

    2.build后包的大小以及包的多少

    webpack-bundle-analyzer插件可以帮我们可视化的展示build时的每个包的大小以及依赖。vue-cli也帮我们做了默认的配置,我只需要在build的后面加一个参数--report即可。

    // package.json
    {
      "name": "dll-vue",
      "version": "0.1.0",
      "private": true,
      "scripts": {
        "serve": "vue-cli-service serve",
        "build": "vue-cli-service build",
        "report": "vue-cli-service build --report",
      }
    }
    

    npm run report 之后,dist目录下就多了一个report.html文件,我们用浏览器打开这个文件看一下,右上角那个小蓝块是我们的vue代码,接下来我们主要来优化小蓝块之外的代码

    屏幕快照 2021-07-31 下午9.51.03.png

    四、开始优化

    1. include/exclude

    我们通常配置include和exclude,来达到使loader仅仅处理匹配到的文件,像这样

    // webpack.config.js
    module.exports = {
      module: { 
          rules: [ 
              { 
                  test: /\.js[x]?$/, 
                  use: ['babel-loader'], 
                  include: [path.resolve(__dirname, 'src')] 
              }
             ] 
      },
    }
    

    而vue的transpileDependencies属性默认情况下 babel-loader 会忽略所有 node_modules 中的文件,其实已经满足了我们大部分需求。

    2. resolve

    resolve: 配置 webpack如何寻找模块所对应的文件,比如import * from 'xxx',xxx模块应该优先从node_modules中找,我们通过vue inspect > webpack.config.js导出的文件中在modules字段中可以清晰的看到已经将node_modules设置为优先寻找的模块

    resolve: {
        // ...
        modules: [
          'node_modules',
          ...
        ]
        // ...
     }
    

    3. happypack-plugin/thread-loader

    一般来说,我们可以通过happack-plugin或者thread-loader开启多线程打包。vue-cli的parallel属性的含义是:是否为 Babel 或 TypeScript 使用 thread-loader,默认值为cpu的内核数,也就是说如果你系统是3核cpu,则build的时候,会自动在babel-loader和ts-loader执行时候开启3个线程。如果你想试着自己的配置一下,可以像下面这样。(不过我试着自己配置了之后,似乎没什么效果。也许是我配置的不对,欢迎大家来指正)

    config.module.rule('vue')
              .use('thread-loader')
              .loader('thread-loader')
              .before('vue-loader')
    

    4. noParse

    如果一些第三方模块没有AMD/CommonJS规范版本,可以使用 noParse 来标识这个模块,这样 Webpack 会引入这些模块,但是不进行转化和解析,从而提升 Webpack 的构建性能 ,例如:jquerylodash,vue.config.js中可以这样配置:

    // vue.config.js
    module.exports = {
       //...
       configureWebpack:{
        module: {
          noParse: /^(lodash|moment)$/
        }
      }
      //...
    }
    

    5. ContextReplacementPlugin

    一些依赖,我们也许只是用到了一部分,没必要全部解析,比如moment中的语言包,我们一般只用中文包就够了,所以可以这样配置:

    // vue.config.js
    module.exports = {
       //...
       configureWebpack:{
           plugins: [
               new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/)
           ]
      }
      //...
    }
    

    我们通过一张图片来体验一下, 左边为去掉语言包的效果

    moment.png

    6. externals

    一般来说像jQuery这些第三方的包,我们采用CDN的方式来引入,像这样

    <-- public/index.html -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.> js"></script>
    

    在使用的时候,我们希望通过import的方式引入,像这样

    // App.vue\
    import $ from 'jquery'
    $('.today').text = 'today'
    

    这就造成一个问题,build的时候就会将jquery再打包一次 我们可以配置externals来达到build时忽略掉指定的依赖

    // vue.config.js
    module.exports = {
       //...
       configureWebpack:{
        config.externals = {
          jquery: 'jQuery'
        }
      }
      //...
    }
    

    7. uglifyjs-webpack-plugin

    在build的时候可以压缩代码的大小,有几个常用的配置可以单独提一下,比如去掉console.log,比如进行多进程压缩。可以这样:

    // vue.config.js
    module.exports = {
       //...
       configureWebpack:{
        config.optimization.minimizer = [
          new UglifyJsPlugin({
           uglifyOptions: {
            compress: {
             drop_console: true, // 去掉console
            }
            parallel: true, //默认并发运行数:os.cpus().length - 1
           }
          })
         ]
      }
      //...
    }
    

    8. compression-webpack-plugin

    我们可以将代码压缩为.gz文件,浏览器也是可以识别的。可以这样配置

    //vue.config.js
    module.exports = {
       //...
       configureWebpack:{
        plugins: [
            new CompressionWebpackPlugin()
        ]
      }
      //...
    }
    

    9. DllPlugin 和 DllReferencePlugin

    • 对于变化几率很小的一些第三方包,其实没必要build的时候都要打包一次, 可以把这些第三方包单独抽离出来,提前打包好。
    • webpack本身是要体现出模块间的依赖关系,当我们将一些包抽离出来后,维护之前的依赖关系就需要manifest.json这个文件。让我们从接下来的实战中来学习它。

    <1> 新建一个配置文件webpack.dll.config.js

    // webpack.dll.config.js
    module.exports = {
      mode: 'production',
      entry: {
        vue_vendor: ['vue/dist/vue.runtime.esm.js', 'vuex',  'vue-router', 'element-ui'],
        other_vendor: ['lodash', 'moment']
      },
      output: {
        filename: '[name].dll.js',
        path: path.resolve(__dirname, './public/dll'),
        library: '[name]_[hash]'
      },\
      plugins: [
        new webpack.DllPlugin({
          name: '[name]_[hash]',
          path: path.resolve(__dirname, '[name].manifest.json')
        })
      ]
    }
    

    <2> 为了方便,我们将读取该配置文件的命令写到package.json文件中,像这样。(需要安装webpack-cli)

    // package.json
    {
      .....
      "scripts": {
        .....
        "dll": "webpack --config ./webpack.dll.config.js"
      }
      .....
    }
    

    <3> 执行npm run dll后可以看到生成两个manifest文件,像这样

    屏幕快照 2021-08-02 下午8.06.25.png

    <4> 修改vue.config.js,引入依赖文件,并自动将dll下的文件插入到index.html中(这里我们引入一个插件add-asset-html-webpack-plugin

    module.exports = {
      chainWebpack: config => {
        // 多个manifest.json文件就需要写多次
        config.plugin('vendorDll1')
        .use(webpack.DllReferencePlugin, [
          {
            context: __dirname,
            manifest: require('./public/manifest/other_vendor.manifest.json')
          }
        ])
    
        config.plugin('vendorDll2')
        .use(webpack.DllReferencePlugin, [
          {
            context: __dirname,
            manifest: require('./public/manifest/vue_vendor.manifest.json')
          }
        ])
    
        // 将dll下的文件自动插入到index.html中
        config.plugin('asset')
        .use(AddAssetHtmlWebpackPlugin, [
          [
            {
              filepath: path.resolve(__dirname, 'public/dll/vue_vendor.dll.js'),
              outputPath: 'dll',
              publicPath: '/dll'
            },
            {
              filepath: path.resolve(__dirname, 'public/dll/other_vendor.dll.js'),
              outputPath: 'dll',
              publicPath: '/dll'
            }
          ]
        ])
      }
    }
    

    10. optimization.splitChunks

    抽离公共代码,通过配置splitChunks可抽离公共的代码,防止重复,我没有在自己的项目中用,

    //vue.config.js
    module.exports = {
       //...
       chainWebpack: config => {
          config.optimization.splitChunks({
              chunks: 'all',
              cacheGroups: {}
          })
       }
      //...
    }
    

    五、效果展示

    section1.png section2.png all.png

    六、补充几个不需要配置的优化点

    1. extensions

    当我们导入模块时,假如没有指定后缀,期望优先匹配的文件格式,我们直接看vue-cli默认的配置extensions: ['.mjs', '.js', '.jsx', '.vue', '.json', '.wasm']

    2. tree-shaking

    我们通过import方式引入,webpack会自动移除掉没有用到的模块代码

    3. Scope hosting

    作用域提升:比如

    let a = 1
    let b = 2
    let c = a + b
    
    // webpack自动优化为
    c = 3
    

    4. 路由懒加载

    通过() => import('xxx')方式引入,可达到路由懒加载的效果

    六、总结

    • 该文章为最近优化团队项目的webpack打包速度,做的总结。

    • 如果有不对的地方欢迎大家在讨论区纠正

    • 欢迎关注公众号:前端小卡

    • 如果觉得有用,欢迎点个赞啦

    相关文章

      网友评论

          本文标题:【实战篇】基于vue-cli4创建的项目进行打包优化

          本文链接:https://www.haomeiwen.com/subject/wfwjvltx.html