webpack打包优化配置

文章目录

  • 前言
  • 不进行任何打包配置
  • 代码分离
    • splitChunk
    • runtimeChunk
    • 动态导入
  • css文件处理
    • css文件提取
    • css文件压缩
    • css实现Tree Shaking
  • js实现Tree shaking
  • Terser
  • scope Hoisting
  • 打包优化没效果
  • 打包界面显示分析
  • 总结


前言

之前使用webpack进行项目搭建配置时,都是操作一些基础的loader、基础插件配置与开发环境配置,没怎么考虑过打包配置。所以想整一下生产环境的配置,加深自己的理解。

不进行任何打包配置

当不进行任何打包配置时,使用的是production环境下webapck默认的配置。我将自己之前用webpack搭建的前端项目掏了出来,npm run build 进行打包,打出的包如下:
webpack打包优化配置_第1张图片
由图可以看出,打出的包中bundle.js文件很大。默认情况下所有的同步导入模块中的js代码会打包进bundle.js文件中,首页加载时会加载全部js代码,影响加载性能。下面对其进行优化。

代码分离

代码分离的作用是将代码打包进不同的bundle中,使每个bundle文件的体积减小,可以实现按需加载,提升加载性能。
常见的代码分离方法有配置多入口、splitChunk与动态导入等实现方式。多入口配置相对简单,可以自行配置,我这里用不到,主要说一下后面两种方式。

splitChunk

有大佬具体分析过:https://juejin.cn/post/6844903891922862093

先说一下splitChunk分包模式,需要使用SplitChunksPlugin实现(webpack已内置此插件)。
此方法默认处理异步导入的import的模块,将使用到的公共模块进行拆分,将公共的chunk拆成一些小的chunks,供各异步模块使用,实现按需加载chunk。
在production环境下webpack已对其进行默认配置,可以不进行其它额外配置,也可以手动更改配置。在开发环境也可以进行相应的配置,大型项目推荐开发环境也进行配置。

相关的配置项有:

  • chunks:默认值为async,表示异步导入处理;还可以取值initial,all。
  • minSize:拆分包的大小至少为minSize,如果一个包拆分出来达不到minSize,那么这个包就不会拆分。
  • maxSize:将大于maxSize的包,拆分为不小于minSize的包。
  • minChunks:至少被引入的次数,默认是1,没达到引入次数不会被拆分。
  • name:设置拆包的名称,可以不写,不写时在cacheGroups中要设置。
  • cacheGroups:用于对拆分的包就行分组。比如lodash在拆分之后,并不会立即打包,而是会等到有没有其他符合规则的包一起来打包。
optimization: {
    splitChunks: {                 // 这里一般不手动配置,最多平常只配置个 chunks: "all"
      chunks: "async",               
      minSize: 20000,
      maxSize: 20000,
      minChunks: 1,
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,  //匹配规则,匹配模块是否属于node_modules文件夹中
          filename: "[id]_vendors.js",
          priority: -10                    // 优先级
        },
        default: {                          
          minChunks: 2,                     //匹配规则
          filename: "common_[id].js",
          priority: -20
        }
      }
   },
}

搞完重新打包后发现哈哈哈没啥变化,bundle.js文件还是大,因为只处理了异步导入模块,不影响打包后的bundle.js文件。
webpack打包优化配置_第2张图片

runtimeChunk

配置runtime相关的代码是否抽取到一个单独的chunk中。抽离出来后,有利于浏览器缓存的策略。
这个production环境中应该有默认配置,懒得搞了随便设个name值。

optimization: {
  runtimeChunk: {
     name: 'runtime'
  }
},

动态导入

动态导入通常是一定会打包成独立的文件的,所以并不会再cacheGroups中进行配置。命名通常会在output中,通过 chunkFilename 属性来命名。
这里有个chunkIds配置,让webpack使用什么算法生成打包出的独立文件的id,一般使用webpack的默认值即可。开发环境下的默认值为named,生产环境下的默认值为deterministic。

output: {
  chunkFilename: "js/[name].[contenthash:6].chunk.js",
},

代码分离一套流程搞完后发现体积还是没有减小,但是打包的产物文件变了。
webpack打包优化配置_第3张图片

css文件处理

下面接着处理css等样式资源,有以下处理流程:

  • css文件提取
  • css文件压缩
  • css文件实现Tree Shaking

css文件提取

主要使用mini-css-extract-plugin插件实现,将css提取到独立的css文件中,该插件需要在webpack4+才可以使用,且在生产环境才使用。

  1. 安装: npm install mini-css-extract-plugin -D
  2. 这里有个注意点,开发环境才会使用style-loader,生产环境要使用MiniCssExtractPlugin.loader,且需配合插件使用。
  3. 下面代码中的isProduction是我自己传的参数,如何判断开发环境还是生产环境根据项目自行处理。
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          isProduction ? MiniCssExtractPlugin.loader: "style-loader", // style-loader最好只在开发环境使用
          {
            loader: "css-loader",
            options: {
              importLoaders: 1
            }
          },
          'postcss-loader'
        ]
      },
   ]
},
// production环境下的配置
plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: "css/[name].[contenthash:6].css"
    }),
  ]

css文件压缩

主要使用插件css-minimizer-webpack-plugin实现,但是功能有限,只能去除一些无用的空格等,很难去修改选择器、属性的名称、值等,也是在生产环境使用。

npm install css-minimizer-webpack-plugin -D

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
plugins: [
    new CssMinimizerPlugin()
]

css实现Tree Shaking

主要使用PurgeCSS插件来实现,用来删除未使用的CSS样式。

注意:这个方法慎用!我将产物部署到我的服务器上,发现部分样式缺失,给我删掉了

npm install purgecss-webpack-plugin -D

const PurgeCssPlugin = require('purgecss-webpack-plugin');
const glob = require('glob');  // webpack内置插件
plugins: [
    new PurgeCssPlugin({
      // 检测src文件夹下的所有文件夹中的所有文件,这是glob库中的固定写法
      // {nodir: true} 表示不检测文件夹,只检测文件
      paths: glob.sync(`${resolveApp("./src")}/**/*`, {nodir: true}),
      safelist: function() {
        return {
          standard: ["body", "html"]      // 保留html和body的样式
        }
      }
    })
]

这些操作整完发现bundle包变小一些了。
webpack打包优化配置_第4张图片

js实现Tree shaking

主要用来消除未调用的代码。
方式一:usedExports属性:通过标记某些函数是否被使用,之后通过Terser来进行优化的,这个在后面会讲到。还有这个生产环境webpack配了默认值了,一般不需手动修改。
还有一个方式可自行去了解,我不喜欢用。

Terser

可以压缩、丑化代码,让bundle(代码包)变得更小。在production模式下,默认就是使用TerserPlugin来处理我们的代码的,可以使用默认值,也可以手动配置。相关配置参数的含义可自行去了解。

局部安装: npm install terser

optimization: {
    usedExports: true, // 通过标记某些函数是否被使用,之后通过Terser来进行优化
    minimize: true, // 对js代码进行压缩,默认production模式下已经打开了
    minimizer: [
      // 由Terser将未使用的函数, 从我们的代码中删除
      new TerserPlugin({
        parallel: true,
        extractComments: false,  // 使用这个插件主要是删除build文件夹中的一个注释文件
        terserOptions: {
          output: {
            comments: false,  // 打包时去掉注释
          },
          compress: {
            arguments: false,
            dead_code: true,
            pure_funcs: ['console.log']  // 打包时清除掉无用的console.log
          },
          mangle: true,
          toplevel: true,
          keep_classnames: true,
          keep_fnames: true
        }
      })
    ]
  },

打包成果物中有个注释文件,如果想去掉这个文件,可以配置 extractComments: false
webpack打包优化配置_第5张图片

scope Hoisting

主要是对作用域进行提升,并且让webpack打包后的代码更小、运行更快。
webpack打包会有很多的函数作用域,需要执行一系列的函数,scope Hoisting主要将函数合并到一个模块中来运行。
生产环境中该模块自启动,无需配置,开发环境可以自己配置。

const webpack = require('webpack');
plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
]

打包优化没效果

上面优化流程全部走完了,发现打包优化的还是不行。我就只能在splitChunk上下功夫了。
webpack打包优化配置_第6张图片
还记得上面的配置中,splitChunks只是处理了异步导入模块吗。现在将splitChunks的chunks默认属性值改为all,就是不止对异步导入做处理了,同步与异步导入都做处理进行代码分离。再打包一次发现有效果了,每个bundle的体积都小了很多,但是还有一个文件警告,显示为538kib大小。我实在不知怎搞了,这个文件包分析也看不懂。
webpack打包优化配置_第7张图片

打包界面显示分析

针对上面遗留的问题,想进行一个可视化的分析,主要使用webpack-bundle-analyzer插件,可以非常直观查看包大小与依赖关系。

npm install webpack-bundle-analyzer -D

const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
new BundleAnalyzerPlugin()

添加完成配置后,我直接运行打包,发现报错,报错理由在网上搜了一下说是8888端口被占用。
因为这个插件是帮助我们打开一个8888端口上的服务,方便我们可以直接的看到每个包的大小。
webpack打包优化配置_第8张图片

网上的处理方式都是什么在任务管理器中杀死8888端口的服务,太凶残了,我选择给它换个端口使用。

new BundleAnalyzerPlugin({analyzerPort:7777})

然后重新打包后打包成功,并给我开启一个服务,展示包的依赖关系与体积大小。
webpack打包优化配置_第9张图片

从图上可看出那个最大的包是我引入的element-ui,我说我怎么解决不掉。这个原因是我直接将element-ui全部引入了,后面进行按需引入可以解决,就是使用到哪些控件就引入哪些控件。

总结

对于webpack打包优化,感觉内容很多也很杂,这里做一下总结:

  1. 进行打包优化时,无法分析出包体积大的原因时,可使用可视化打包工具来协助分析;
  2. 在开发环境中,一般不会注意打包优化这些的,基本用不到;
  3. 在生产环境中,对于打包优化webpack也进行了一些默认配置,平常使用默认配置即可,有特殊需求时可以手动更改配置;
  4. 文中使用到的scope Hoisting,js的Tree shaking,Terser等,平常开发使用默认配置即可,如有在生产环境中要去掉全部的console.log等需求,可对Terser再进行额外配置;
  5. 如需严格控制打包的每个文件的体积,就可以对splitChunk动刀子,代码分离就完事。

你可能感兴趣的:(webpack,javascript,webpack)