美文网首页
webpack —— 优化开发体验

webpack —— 优化开发体验

作者: 黎明的叶子 | 来源:发表于2021-06-08 14:58 被阅读0次

webpack 优化从两个方面入手。
一、优化开发体检。包括优化构建速度和优化使用体验
二、优化输出质量,包括减少用户能感知到的加载时间(首屏加载时间)和提升流畅度(提升代码性能)。参考链接优化输出质量

项目背景:我目前的项目,功能巨多,业务庞大。打包上面的确有很多不合理的地方以致于打包时间最长有过20分钟的情况。平均正常也得800-900秒。在另一个同事的积极推动建议下,开启了打包优化之旅。我的主要目标是优化构建速度。所以这块验证的比较多。其他的知识点算是总结了。我主要参考的是深入浅出webpack这本书。

优化构建速度

是按我自己项目中的构建优化时间从大到小排列的。

  • 通过 Node.js API 启动 Webpack,构建时间减少了一半。减少到400-500秒
    无意中发现的方式。因为本身项目比较老,没有用脚手架工具。参考用脚手架create-react-app工具搭建的项目的配置。发现他们启动的方式是通过Node.jsAPI启动的。当时做的时候,不知道命名,是看了参考书,才知道原来有这个定义。参考 通过 Node.js API 启动 Webpack
    书上这样介绍:通过 API 去调用并执行 Webpack 比直接通过可执行文件启动更加灵活,可用在一些特殊场景(没有介绍具体的使用场景,但是发现脚手架都是这样的用的)
    总结:webpack执行的两种方式:

    1. Webpack 其实是一个 Node.js 应用程序,它全部通过 JavaScript 开发完成。 在命令行中执行 webpack 命令其实等价于执行 node ./node_modules/webpack/bin/webpack.js。
     // package.json
     "scripts": { 
          "start": "webpack", 
      },
    
    1. 通过 Node.js API 启动 Webpack。
      const config = require('webpack.config.js')
      const webpack = require('webpack')
      const compiler = webpack(config)
      compiler.run((err, stats) => {
        // console.log(err, stats)
      })
      

    这块没有理解为啥通过Node.jsAPI的方式会快这么多。猜测应该是直接webpack的时候,做了一些判断啥,然后才走的webpack-cli。然而Node.jsAPI是直接走到webpack-cli。代码少了一部分。因而时间少。不过没有证实,也不确定少走什么代码,时间这么大的差异。(如果有知道的,欢迎补充,我会再更新。如果我后续看懂了源码,也会再补充。

  • 使用 ParallelUglifyPlugin 多进程压缩,构建时间减少了200s左右,平均值在250秒
    代码构建的时候,需要先经过loader处理,然后再压缩。由于压缩 JavaScript 代码需要先把代码解析成用 Object 抽象表示的 AST 语法树,再去应用各种规则分析和处理 AST,导致这个过程计算量巨大,耗时非常多。这里借鉴使用 HappyPack中介绍过的多进程并行处理的思想引入到代码压缩中。(HappyPack使用 ,在我的项目中,没有减少时间,反而增加了几秒。所以排列在最后面。肯定有他的好处,但是要慎用,因为开启进程也会耗费时间)使用此项配置,时间减少到300秒左右。

const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
module.exports ={
  entry: 'main.js', 
  output: {
    filename: '[name].[chunkhash].js',
    chunkFilename: '[name].[chunkhash].chunk.js'
  },

  plugins: [ 
    // 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
    new ParallelUglifyPlugin({
      // 传递给 UglifyJS 的参数
      uglifyJS: {
        output: {
          // 最紧凑的输出
          beautify: false,
          // 删除所有的注释
          comments: false,
        },
        compress: {
          // 在UglifyJs删除没有用到的代码时不输出警告
          warnings: false,
          // 删除所有的 `console` 语句,可以兼容ie浏览器
          drop_console: true,
          // 内嵌定义了但是只用到一次的变量
          collapse_vars: true,
          // 提取出出现多次但是没有定义成变量去引用的静态值
          reduce_vars: true,
        }
      },
    }), 
  ]
 }
  • 修改压缩图片的loader配置。减少130秒左右,到120秒
    原来loader配置中用了压缩图片的功能,image-webpack-loader,导致时间变长。去掉后时间明显减少。压缩倒是很大。由120kb的图片可以压缩到40kb。但是时间很久。一开始去掉了此配置,换成了 imagemin-webpack-plugin插件做压缩。压缩质量设置成一样的,都是65-90。时间却省了不少。基本跟现在一样。后来修改了loader的原有配置,只剩下quality一项。时间也会减少很多。结论是:两个用哪个都行。image-webpack-loader的配置挺重要的。代码配置如下
// 原来比较慢的配置
  {
      test: /\.(jpg|png|jpeg|gif|pdf|mp3|aac)$/,
      loaders: [
         'file-loader',
        {
           loader: 'image-webpack-loader',
           query: {
             progressive: true,
             optimizationLevel: 7,
             interlaced: false, 
             pngquant: { 
              quality: [0.65, 0.9],
              speed: 4
             }
           }
         }
       ]
  },

// 去掉某些配置后,压缩时间减少了
  {
      test: /\.(jpg|png|jpeg|gif|pdf|mp3|aac)$/,
      loaders: [
         'file-loader',
        {
           loader: 'image-webpack-loader',
           query: { 
             pngquant: { 
              quality: [0.65, 0.9], 
             }
           }
         }
       ]
  }, 
// 用插件的配置 这个也挺快的
   new ImageminPlugin({
        pngquant: {
            quality: '65-90'
        }
    }),
  • 缩小文件搜索范围(只采用了第一项,整体打包时间到50s左右)

    • 优化 loader 配置。减少70秒左右。
      module.exports = {
      module: {
       rules: [
         {
             // 如果项目源码中只有 js 文件就不要写成 /\.jsx?$/,提升正则表达式性能
           test: /\.js$/,
           // babel-loader 支持缓存转换出的结果,通过 cacheDirectory 选项开启
           use: ['babel-loader?cacheDirectory'],
            // 只对项目根目录下的 src 目录中的文件采用 babel-loader
           include: path.resolve(__dirname, 'src'),
         },
       ]
      },
      };
      
    • 优化 resolve.modules 配置(未使用)
      此项也能减少50秒左右。但是此项引发了我项目的bug。参考一个webpack构建速度优化误区。我的项目有用到websocket。按照这篇文章的意思,我觉得可能是最外层的node-modules目录下和插件目录下都存在一个组件。然后修改了此项,改变了组件的引用地址。本来应该用组件下的node-modules里面的某项,结果用了最外层的。由于版本不一致,导致的错误。所以此项没有真实用到项目里面。
       module.exports = {
         resolve: {
         // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
         // 其中 __dirname 表示当前工作目录,也就是项目根目录
           modules: [path.resolve(__dirname, 'node_modules')]
         },
       };
    
    • 优化 resolve.mainFields 配置(未使用)
      减少20-30秒,但是我的项目是允许在浏览器端的。也就是target:web。如果改成以main为先,项目也存在错误。

    resolve.mainFields 的默认值和当前的 target 配置有关系,对应关系如下:
    当 target 为 web 或者 webworker 时,值是 ["browser", "module", "main"]
    当 target 为其它情况时,值是 ["module", "main"]

         // 我原本的是这样
         mainFields: [
             'browser',
             'jsnext:main',
             'main'
        ]
        // 为了缩小查询的步骤 建议改成。但是这种改法,在我们做网站的这种项目中,都是运行在浏览器端的。所以不建议。会出错
         mainFields: [ 
              'main',
              'browser',
             'jsnext:main',
        ]
    
    • 优化 resolve.alias 配置(未使用)
      减少30-40秒。原理是直接引用压缩好的文件,省去了打包。我把react-dom也放到这里,优化时间会多一点,其他的看不太出来。但是react-dom 用了后就报错了。于是也没有真正使用。
    • 优化 resolve.extensions 配置(未使用)
      在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试询问文件是否存在。 resolve.extensions 用于配置在尝试过程中用到的后缀列表,默认是: extensions: ['.js', '.json'] 。这项项目中本来就有。所以没有用。但是通过这项,我觉得应该在平时书写代码的时候加上后缀,也会加快读取。
    • 优化 module.noParse 配置(未使用)
      通过配置 module.noParse 忽略对 没采用模块化的文件的递归解析处理,这样做的好处是能提高构建性能。跟alias类似。忽略掉react-dom,报一样的错误。也没有再用了。
  • 使用 DllPlugin,这项没验证。
    DllPlugin 主要是webpack内置的插件。就是先把某些 不用变动的包 单独打包出去,然后再静态引入,这是我们再配置webpack告诉webpack 哪些包不用再编译了,这样就能很大程度上提高我们的编译速度。 node-module里面的很多我们需要用的包,以vue项目为例,比如vue echart element等,就用这个打包我们需要用的。里面还有很多是webpack的依赖,那些不需要我们打包。

    • 1.建立一个webpack.dll.js的文件 里面放所有提前编译好的文件

      let path = require('path')
      let {CleanWebpackPlugin} =require('clean-webpack-plugin')
      let webpack = require('webpack')
      module.exports = {
          mode: 'production',
          entry: {
              vue:['vue']
          },
          output: {
              filename: 'dll_[name].js',
              path: path.resolve(__dirname, 'dist'),
              library:'dll_[name]'
          },
          plugins: [
              new CleanWebpackPlugin(),
              new webpack.DllPlugin({
                  name: 'dll_[name]',  // name = library
                  path:path.resolve(__dirname,'dist','manifest.json')
              })
          ]
      }
      
    • 2.package.json 中配置编译这些文件的命令

       "scripts": {
            "dev": "webpack-dev-server --config webpack.config.dev.js",
            "build": "webpack --config webpack.config.dev.js",
            "dllVue": "webpack --config webpack.dll.js"
        },
      

      此时 通过启动 npm run dllVue 即可把这些不用每次都编译的文件编译好

    • 3.webpack.config.js 中配置 打包的时候 不去编辑以上打包好的文件

       plugins: [
           new webpack.DllReferencePlugin({
               // 打包编译的时候,先去这个清单中查找 清单中没有再去进行打包
               manifest:path.resolve(__dirname,'dist','manifest.json')
           }),
           new CleanWebpackPlugin({
               // 告诉这个插件 不用清除这些文件 
               cleanOnceBeforeBuildPatterns:['**/*','!dll_*','!mani*']
           }), 
       ],
      
    • 4.本地开发的时候要 查找 已经编译好的文件 这些文件是静态文件 所以要在devServer中设置contentBase

       devServer: {
           port: 8999,
           // hot:true, 
           // 查找到dist里面的文件
           contentBase:'dist',
            <!--DevServer起服务后 文件都是在他的内存中的  然后如果要访问我们本地的文件的话 他是访问不到的  所以要用这个 contentBase指向我们本地的文件夹。也就是把contentBase对应的文件,作成他的服务中的静态文件,这样通过服务就可以访问到文件。-->
       },
    
    • 5.index.html页面要引入这个文件
       <script src="./dll_vue.js"></script> 
    
  • 使用 HappyPack(未使用,使用了时间没减少)
    多进程处理文件,加快速度的。但是开启进程也需要时间。慎重使用。
    happyPack已不再维护,官网推荐的是thread-loader.通过在loader处理之前,拦截开启进程。使用过程时间未减少,反而增了几秒,没有 ParallelUglifyPlugin效果明显。(可能这个说法不准确,只是以我自己的项目为例显示出来的效果)

优化使用体验

  • 使用自动刷新
  • 开启模块热替换

相关文章

  • Webpack优化

    0、写在前面 Webpack优化可以分为优化开发体验和优化输出质量两部分 1、优化开发体验 优化开发体验的目的是为...

  • Webpack性能优化「六」-- 优化打包构建速度 ***

    本篇讲的是 Webpack 对于优化打包构建速度,也就是对于开发体验和效率的优化。有如下几处可以优化: 优化 ba...

  • Webpack 优化开发体验

    Webpack Dev Server 集成了 自动编译 和 自动刷新浏览器 等功能。webpack-dev-ser...

  • webpack 性能优化

    webpack性能优化 开发环境性能优化 生产环境性能优化 开发环境性能优化 优化打包构建速度 优化调试功能 生产...

  • Webpack 优化总结

    webpack优化可以分为两部分: 开发环境性能优化 生产环境性能优化 开发环境性能优化 HMR: 热加载。 so...

  • webpack常见的基本概念

    mode 开发模式 webpack 提供 mode 配置选项,配置 webpack 相应模式的内置优化。 支持以下...

  • webpack 入门的总结和简单配置

    webpack 总结前端模块化编程打包工具可以把模块打包成一个文件,提高访问速度,开发速度,优化用户体验modul...

  • 性能优化+打包构建

    性能优化 webpack-bundle-analyzerwebpack构建优化webpack分包webpack g...

  • Webpack 热更新实现原理分析

    概述 在使用 Webpack 构建开发期时,Webpack 提供热更新功能为开发带来良好的体验和开发效率,那热更新...

  • webpack的性能优化

    webpack项目优化主要分为两个方面的优化,生产环境的代码优化和开发环境的项目构建优化 生产环境的代码优化 第一...

网友评论

      本文标题:webpack —— 优化开发体验

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