最近webpack优化的一些总结

前言

最近优化了一些webpack项目的构建体积与速度,结合公司做的一些默认配置,大部分应用打包速度已经快到飞起,在这记录一下自己和公司做的一些webpack优化。

过程

帮助我们分析的插件

下载 webpack-bundle-analyzer 和 speed-measure-webpack-plugin

npm i webpack-bundle-analyzer speed-measure-webpack-plugin

webpack-bundle-analyzer

webpack-bundle-analyzer 可以查看构建前引入包的体积
在这里插入图片描述

stat size: webpack从入口文件打包递归到的所有模块体积
parsed size: 解析与代码压缩优化后输出到dist目录的体积(dist文件夹内代码压缩<UglifyJS>后的js文件)
gzipped size: 开启Gzip之后的体积(文件由a.js变为a.js.gz)

针对 gzipped,我们知道webpack开启gzip,那如何开启呢?

下载 compression-webpack-plugin,并进行配置

额外知识:
线上nginx还需要开启gzip,对代码进行压缩(响应头中会有 content-encoding: gzip)

http {  //在 http中配置如下代码,
   gzip on;
   gzip_disable "msie6"; 
   gzip_vary on; 
   gzip_proxied any;
   gzip_comp_level 8; #压缩级别
   gzip_buffers 16 8k;
   #gzip_http_version 1.1;
   gzip_min_length 100; #不压缩临界值
   gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
 }

为什么webpack对代码进行gzip压缩了,nginx还要再来一次gzip压缩?

将nginx配置开启gzip压缩,nginx会根据配置情况对指定的类型文件,进行压缩。主要针对js与css.如果文件路径中存在与原文件同名(加了个.gz),nginx会获取gz文件,如果找不到,会主动进行gzip压缩。

我们本地服务devServer有一个 compress: true 配置(响应头会携带content-encoding: gzip),这个的作用相当于nginx开启gzip,对本地代码热更新文件进行压缩,热更新及起服务速度更快,这样可以代替线上使用压缩插件nginx配置

speed-measure-webpack-plugin

在这里插入图片描述
上中下三部分 分别代表 文件输出时间、plugin工作时间、loader工作时间
如果显示红色的话,说明耗时时间过长,我们可以找到对应的plugin\loader去查看为什么耗时这么久,进而进行优化。比如sass-loader比较慢,我们看看换成less-loader可不可以。ExtractTextPlugin比较慢,我们可不可以把这个插件copy下来,结合自身业务改写下,让他更快一点。

优化方案

一、对第三方依赖包优化(速度、体积)

部分包替换

首先我们可以针对我们使用的第三方依赖包进行优化,例如非常占内存的moment,我们可以替换为dayjs,但是如果有很多地方使用moment,我们替换的话成本比较大(每个地方),风险也比较高(有地方漏掉替换),我们可以使用webpack中的配置别名来,成本和风险都较低。

// clientChainWebpack中的配置,老webpack配置自行百度
   config.resolve.alias.set('moment', 'dayjs')

这里的意思是识别 代码中moment字段,编译后全部替换为 dayjs 字段

部分包按需加载

我们经常使用loadsh这个包,但是只是使用了它的几个函数。这时候,我们有可能将整个loadsh包都打包了进去,这个时候我们可以用一些webpack的plugin来让他按需加载,例如:

npm i babel-plugin-lodash  lodash-webpack-plugin

第一个为babel的plugin、第二个是webpack的plugin

我们也经常使用elementUI这种UI库,这种UI库的组件是非常占打包体积的。elementUI官网也为我们提供了babel插件 babel-plugin-component,让我们引入需要的组件。官方也为我们提供了一些方法,让我们按需加载在使用的组件。

很多第三方包都提供了按需加载的webpack插件或babel插件。

额外知识:
plugin和loader和babel有什么区别?

首先plugin和loader都是对webpack功能的拓展。

loader
loader主要是将某种格式的文件(包括css\js\ts\less\jsx\jpg等等)转化成webpack支持打包的模块。
比如style-loader、css-loader、less-loader、sass-loader、postcss-loader、url-loader(指定文件大小,小于这个指定的大小 转化为base64打进js包,否则文件单独打包)、file-loader、ts-loader、babel-loader(将es6以上浏览器不能识别的js语法转化为浏览器可以识别的js语法)。
可以看出loader的作用是单一的,只针对某项资源和某段流程(比如babel-loader只针对js资源、只针对ES6以上资源 转化 为浏览器可以识别的ES3\4\5或当前浏览器支持的js语法。)。

babel
babel这时的作用也很清晰了,就是 将es6\7\8的语法转化为浏览器可以识别的es3\es4\es5,或者将当前浏览器不能识别的js,转化为可以识别的js。
但是babel和webpack没有任何关系,babel-loader只是一个工具 用来使webpack可以使用babel 进而将es6\7\8的语法转化为浏览器可以识别的es3\es4\es5的或当前浏览器支持的js语法。

关于babel的原理,什么AST、词法分析、语法分析 这些就不再提了。
babel插件的配置,举一个简单的例子, babel-plugin-lodash,可以在.babelrc或webpack中配置

.babelrc配置

 {
    'presets': [],
    'plugins': [
      'lodash'  //配置(这里并不是插件全称)
      ]
  }

webpack配置

{
  test: /\.(js|jsx)$/,
  loader: 'babel-loader',
  exclude: /node_modules/,
  include: [resolve('src'), resolve('test')]
  options: {plugins: ['lodash']}//配置(这里并不是插件全称)
}

plugin

从打包优化和压缩,到重新定义环境变量,功能强大到可以用来处理各种各样的任务。
它的配置我应该不用多说了。引入插件,实例化一下,放到webpack plugins里面。

二、图片压缩(体积)

上面我们对一些第三方包进行优化,手段是使用一些plugin、loader、甚至babel-plugin。这里我们也需要使用这些手段,进行优化,比如图片压缩,使用的image-webpack-loader

npm install image-webpack-loader --save-dev

下载完,要在webpack配置文件中配置一下,注意,这里不是babel-loader,不要去babel配置文件中配置了。

{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  use:[
    {
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
      }
    },
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true,
      }
    }
  ]
}

还有file-loader,如果图片体积小于设置的标准,转化为base64打到js包内。大于设置的标准,单独打包。

三、优化loader (速度)

优化loader搜索范围

减少loader的检索时间,比如只针对js进行检索,只在src文件夹下进行检索,不去查找node_modules下的代码等等。

module.exports = {
    module: {
        rules: [
            test: /\.js$/, // 对js文件使用babel
            loader: 'babel-loader',
            include: [resolve('src')],// 只在src文件夹下查找
            // 不去查找的文件夹路径,node_modules下的代码是编译过得,没必要再去处理一遍
            exclude: /node_modules/ 
        ]
    }
}
cache-loader缓存loader处理结果
npm i cache-loader
module.exports = {
  module: {
    rules: [
      {
        // js 文件才使用 babel
        test: /\.js$/,
        use: [
          'cache-loader',
          ...loaders
        ],
      }
    ]
  }
}

那这么说的话,我给每个loader前面都加上cache-loader,然而凡事物极必反,保存和读取这些缓存文件会有一些时间开销,所以请只对性能开销较大的 loader 使用 cache-loader。

四、合理配置(速度)

合理的配置mode参数与devtool参数

mode可设置development production两个参数

如果没有设置,webpack4 会将 mode 的默认值设置为 production
production模式下会进行tree shaking(去除无用代码)和uglifyjs(代码压缩混淆)

缩小文件的搜索范围(配置include exclude alias noParse extensions)
 resolve:{
   alias:{
     'react':'react',
     '@':path.resolve(__dirname,'../src'),
     'components': path.resolve(__dirname,'../src/components'),
     'assets': path.resolve(__dirname,'../src/assets'),
   },
 extensions:['*','.js','.json','.jsx']
 },

extensions:会根据extensions定义的后缀查找文件(频率较高的文件类型优先写在前面,像lru缓存那种)

五、开启多线程(速度)

loader并行运行
受限于Node是单线程运行的,所以 Webpack 在打包的过程中也是单线程的,特别是在执行 Loader 的时候,长时间编译的任务很多,这样就会导致等待的情况。那么我们可以使用一些方法将 Loader 的同步执行转换为并行,这样就能充分利用系统资源来提高打包速度了。

HappyPack和thread-loader这两个包,这块在探索,怀疑公司脚手架有类似的东西,这块要看看。

建议使用thread-loader 建议打包时间很久的可以使用。

 /* 
      thread-loader会对其后面的loader(这里是babel-loader)开启多进程打包。 
      进程启动大概为600ms,进程通信也有开销。(启动的开销比较昂贵,不要滥用)
      只有工作消耗时间比较长,才需要多进程打包
      thread-loader必须最后执行,再次说明loader是从下往上,从右往左的执行顺序,所以想要使用thread-loader优化某项的打包速度,必须放在其后执行
    */

六、DLL(速度)

作用: 
我们使用的一些第三方包依赖(node_modules中的,比如loadsh),因为代码不会变化,打包的时候不在重复打包。(减少打包时间)

原理是:
打包的时候,将第三方不需要重复打包的依赖,做成一个映射,放到manifest.json(dist文件夹下的)这个文件中。然后在webpack配置中的plugins中,引入这个映射

plugins: [
  new webpack.DllReferencePlugin({
   context: __dirname,
   manifest: require('./manifest.json'),
  }),
],

这样下次打包就不会重新打包第三方依赖了

七、hard-source-webpack-plugin(速度)

这个我看是代替dll的技术方案

    config
      .plugin('hard-source-webpack-plugin')
      .use(require('hard-source-webpack-plugin'))

webpack的plugin插件,缓存方案

八、externals(体积、速度)

externals详解
就是不把对应的第三方包打到js文件里去,然后线上使用cdn

九、treeshking(速度、体积)

生产环境默认开启,不多说

十、devtool设置none

生产环境默认none,不多说,没有sourceMap打包速度更快,体积更小

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值