# 优化构建结果

# 2.1 构建结果分析

借助插件 webpack-bundle-analyzer (opens new window)我们可以直观的看到打包结果中,文件的体积大小、各模块依赖关系、文件是够重复等问题,极大的方便我们在进行项目优化的时候,进行问题诊断。

  • 安装
$ npm i -D webpack-bundle-analyzer
  • 配置插件
// 引入插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin


const config = {
  // ...
  plugins:[ 
    // ...
    // 配置插件 
    new BundleAnalyzerPlugin({
      // analyzerMode: 'disabled',  // 不启动展示打包报告的http服务器
      // generateStatsFile: true, // 是否生成stats.json文件
    })
  ],
};
  • 修改启动命令
 "scripts": {
    // ...
    "analyzer": "cross-env NODE_ENV=prod webpack --progress --mode production"
  },

执行编译命令 npm run analyzer

打包结束后,会自行启动地址为 http://127.0.0.1:8888 的 web 服务,访问地址就可以看到

如果,我们只想保留数据不想启动 web 服务,这个时候,我们可以加上两个配置

new BundleAnalyzerPlugin({
   analyzerMode: 'disabled',  // 不启动展示打包报告的http服务器
   generateStatsFile: true, // 是否生成stats.json文件
})

这样再次执行打包的时候就只会产生 state.json 的文件了

# 2.2 压缩 CSS

  • 安装 optimize-css-assets-webpack-plugin
$ npm install -D optimize-css-assets-webpack-plugin 

  • 修改 webapck.config.js 配置
// 压缩css
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
// ...

const config = {
  // ...
  optimization: {
    minimize: true,
    minimizer: [
      // 添加 css 压缩配置
      new OptimizeCssAssetsPlugin({}),
    ]
  },
 // ...
}

// ...

  • 查看打包结果

# 2.3 压缩 JS

在生成环境下打包默认会开启 js 压缩,但是当我们手动配置 optimization 选项之后,就不再默认对 js 进行压缩,需要我们手动去配置。

因为 webpack5 内置了terser-webpack-plugin 插件,所以我们不需重复安装,直接引用就可以了,具体配置如下

const TerserPlugin = require('terser-webpack-plugin');

const config = {
  // ...
  optimization: {
    minimize: true, // 开启最小化
    minimizer: [
      // ...
      new TerserPlugin({})
    ]
  },
  // ...
}

# 2.4 清除无用的 CSS

purgecss-webpack-plugin (opens new window) 会单独提取 CSS 并清除用不到的 CSS

  • 安装插件
$ npm i -D purgecss-webpack-plugin
  • 添加配置
// ...
const { PurgeCSSPlugin } = require('purgecss-webpack-plugin')
const glob = require('glob'); // 文件匹配模式
// ...

function resolve(dir){
  return path.join(__dirname, dir);
}

const PATHS = {
  src: resolve('src')
}

const config = {
  plugins:[ // 配置插件
    // ...
    new PurgeCSSPlugin({
      paths: glob.sync(`${PATHS.src}/**/*`, {nodir: true})
    }),
  ]
}
  • index.html 新增节点
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ITEM</title>
</head>
<body>
  <p></p>
  <!-- 使用字体图标文件 -->
  <i class="iconfont icon-member"></i>
  <div id="imgBox"></div>
  
   <!-- 新增 div,设置 class 为 used -->
  <div class="used"></div>
</body>
</html>

  • 在 sass.scss 中添加样式
.used {
  width: 200px;
  height: 200px;
  background: #ccc;
}

.unused {
  background: chocolate;
}

  • 执行一下打包

我们可以看到只有 .used 被保存下来 如何证明是这个插件的作用呢?注释掉再打包就可以看到,.unused 也会被打包进去,由此可证...

# 2.5 Tree-shaking

Tree-shaking 作用是剔除没有使用的代码,以降低包的体积

webpack 默认支持,需要在 .bablerc 里面设置 model:false,即可在生产环境下默认开启

了解更多 Tree-shaking 知识,推荐阅读 👉🏻 从过去到现在,聊聊 Tree-shaking (opens new window)

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        module: false,
        useBuiltIns: "entry",
        corejs: "3.9.1",
        targets: {
          chrome: "58",
          ie: "11",
        },
      },
    ],
  ],
  plugins: [    
    ["@babel/plugin-proposal-decorators", { legacy: true }],
    ["@babel/plugin-proposal-class-properties", { loose: true }],
  ]
};

# 2.6 Scope Hoisting

Scope Hoisting 即作用域提升,原理是将多个模块放在同一个作用域下,并重命名防止命名冲突,通过这种方式可以减少函数声明和内存开销。

  • webpack 默认支持,在生产环境下默认开启
  • 只支持 es6 代码