# webpack 打包优化

# 目的:

  • 减小打包后的文件大小
  • 优化 webpack 打包时间
  • 加快首屏加载

# 优化方式

# 按需加载

# 路由按需加载

const OtherRouter = [
  {
    path: "/test",
    name: "Test",
    component: () => import(/* webpackChunkName: "test" */ "@/views/Test.vue"),
  },
  {
    path: "/config",
    name: "config",
    component: () => import("@/views/other/config.vue"),
  },
];
1
2
3
4
5
6
7
8
9
10
11
12

# 第三方组件和插件,按需引入第三方组件

import Vue from "vue";
import { Button, Select } from "element-ui";
import App from "./App.vue";

Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
1
2
3
4
5
6

# 对于一些插件,如果只是个别组件中使用到就不要在main.js或者main.ts中引入了

- import Vditor from 'vditor'
- Vue.use(Vditor)
//组件内
+ import Vditor from 'vditor'
1
2
3
4

# 优化 loader 配置

  • 优化正则匹配
  • 通过 cacheDirectory 选项开启缓存
  • 通过 include、exclude 来减少被处理的文件

# 优化文件路径

  • extension 配置之后可以不用在 require 或是 import 的时候加文件扩展名,会依次尝试添加扩展名进行匹配。
  • mainFiles 配置后不用加入文件名,会依次尝试添加的文件名进行匹配
  • alias 通过配置别名可以加快 webpack 查找模块的速度

vue

  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
1
2
3
4
5
6
7

angular

tsconfig.json

 "paths": {
      "@service/*": ["app/service/*"],
      "@pipes/*": ["app/pipes/*"]
    },
1
2
3
4

# 生产环境关闭 sourceMap

  • sourceMap 本质上是一种映射关系,打包出来的 js 文件中的代码可以映射到代码文件的具体位置,这种映射关系会帮助我们直接找到在源代码中的错误
  • 打包速度减慢,生产文件变大,所以开发环境使用 sourceMap,生产环境则关闭

# 代码压缩

  • UglifyJS: vue-cli 默认使用的压缩代码方式,它使用的是单线程压缩代码,打包时间较慢
  • ParallelUglifyPlugin: 开启多个子进程,把对多个文件压缩的工作分别给多个子进程去完成
npm i -D webpack-parallel-uglify-plugin
1

webpack.prod.js文件配置如下

const path = require("path");
const webpackConfig = require("./webpack.config.js");
const WebpackMerge = require("webpack-merge");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
// const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const ParallelUglifyPlugin = require("webpack-parallel-uglify-plugin");

module.exports = WebpackMerge(webpackConfig, {
  mode: "production",
  devtool: "cheap-module-source-map",
  plugins: [
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, "../public"),
        to: path.resolve(__dirname, "../dist"),
      },
    ]),
  ],
  optimization: {
    minimizer: [
      // new UglifyJsPlugin({//压缩js
      //   cache:true,
      //   parallel:true,
      //   sourceMap:true
      // }),
      new ParallelUglifyPlugin({
        cacheDir: ".cache/",
        uglifyJS: {
          output: {
            comments: false,
            beautify: false,
          },
          compress: {
            drop_console: true,
            collapse_vars: true,
            reduce_vars: true,
          },
        },
      }),
      new OptimizeCssAssetsPlugin({}),
    ],
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        libs: {
          name: "chunk-libs",
          test: /[\\/]node_modules[\\/]/,
          priority: 10,
          chunks: "initial", // 只打包初始时依赖的第三方
        },
      },
    },
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 引入 webpack-bundle-analyzer 分析打包后的文件

webpack-bundle-analyzer将打包后的内容束展示为方便交互的直观树状图,让我们知道我们所构建包中真正引入的内容

npm i -D webpack-bundle-analyzer
1

webpack.prod.js中加入代码

const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

 plugins:[
  ...,
  new BundleAnalyzerPlugin({
      analyzerHost:'127.0.0.1',
      analyzerPort: 8889
    })
  ],
1
2
3
4
5
6
7
8
9

在 package.json 中加入配置

"analyz": "NODE_ENV=production npm_config_report=true npm run build"
1

windows 请安装

npm i -D cross-env
"analyz": "cross-env NODE_ENV=production npm_config_report=true npm run build"
1
2

# CDN 加速

随着应用越做越大,第三方包越来越多,构建的文件肯定随之越来越大,加上又是单页应用,就会导致网速过慢或者贷款有限的情况会由于较长时间的白屏

vue,vue-router,vuex,axios....

目前常用的 cdn 加速网站 UNPKG (opens new window)

# 使用HappyPack多进程解析

  • 由于运行在 Node.js 之上的 Webpack 是单线程模型的,所以 Webpack 需要处理的事情需要一件一件的做,不能多件事一起做。
  • HappyPack 就能让 Webpack 把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程
  • HappyPack 对 file-loader、url-loader 支持的不友好,所以不建议对该 loader 使用。

使用方法

1、HappyPack 插件安装: npm i -D happypack 2、webpack.base.conf.js 文件对 module.rules 进行配置

module: {
  rules: [
    {
      test: /\.js$/,
      use: ["happypack/loader?id=babel"],
      include: [resolve("src"), resolve("test")],
      exclude: path.resolve(__dirname, "node_modules"),
    },
    {
      test: /\.vue$/,
      use: ["happypack/loader?id=vue"],
    },
  ];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

3、在生产环境 webpack.prod.conf.js 文件进行配置

const HappyPack = require("happypack");
// 构造出共享进程池,在进程池中包含5个子进程
const HappyPackThreadPool = HappyPack.ThreadPool({ size: 5 });
plugins: [
  new HappyPack({
    // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
    id: "babel",
    // 如何处理.js文件,用法和Loader配置中一样
    loaders: ["babel-loader?cacheDirectory"],
    threadPool: HappyPackThreadPool,
  }),
  new HappyPack({
    id: "vue", // 用唯一的标识符id,来代表当前的HappyPack是用来处理一类特定的文件
    loaders: [
      {
        loader: "vue-loader",
        options: vueLoaderConfig,
      },
    ],
    threadPool: HappyPackThreadPool,
  }),
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# TreeShaking

这里单独提一下tree-shaking,是因为这里有个坑。tree-shaking的主要作用是用来清除代码中无用的部分。目前在webpack4我们设置modeproduction的时候已经自动开启了tree-shaking。但是要想使其生效,生成的代码必须是 ES6 模块。不能使用其它类型的模块如CommonJS之流。如果使用Babel的话,这里有一个小问题,因为Babel的预案(preset)默认会将任何模块类型都转译成CommonJS类型。修正这个问题也很简单,在.babelrc文件或在webpack.config.js文件中设置modules: false就好了

最后更新时间: 2/4/2021, 12:52:07 AM