# Webpack 优化

# tree shanking优化 (opens new window)

移除JavaScript上下文中的未引用代码(dead-code)。它只支持es6中的import和export语法,所以并不会应用到require语法中

webpack生成环境模式是开启的,引起esModule的时候确保按需引入。

# 代码分离

常用的代码分离方法有三种:

  • 入口起点:使用 entry 配置手动地分离代码。
  • 防止重复:使用 Entry dependencies 或者 SplitChunksPlugin 去重和分离 chunk。
  • 动态导入:通过模块的内联函数调用来分离代码。

使用 Entry dependencies 去重和分离 chunk。

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  entry: {
    index: {
      import: './src/index.js',
      dependOn: 'lodash',
    },
    another:{
      import: './src/another-module.js',
      dependOn: 'lodash'
    },
    lodash: 'lodash'
  },
  devServer: {
    contentBase: './dist'
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

SplitChunksPlugin 去重和分离 chunk。


// webpack.config.js
optimization: {
  splitChunks: {
    // 代码分割的类型,可以设置为'all','async','initial',默认是'async`
    // 'all': 对同步和异步引入模块都进行代码分割
    // 'async: 只对异步引入模块进行代码分割
    // 'initial': 只对同步代码进行代码分割
    chunks: 'all',
    // 代码分割模块的最小大小要求,不满足不会进行分割,单位byte
    minSize: 30000,
    // 如果分割模块大于该值,还会再继续分割,0表示不限制大小
    maxSize: 0,
    // 最小被引用次数,只有在模块上述条件并且至少被引用过一次才会进行分割
    minChunks: 1,
    // 最大的异步按需加载次数
    maxAsyncRequests: 5,
    // 最大的同步按需加载次数
    maxInitialRequests: 3,
    // 分割模块打包chunk文件名分割符:'~'
    automaticNameDelimiter: '~',
    automaticNameMaxLength: 30,
    // 分割文件名,设置为true会自动生成
    name: true,
    cacheGroups: { // 缓存组
      vendors: {
        // 分割模块匹配条件
        test: /[\\/]node_modules[\\/]/,
        // 权重
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        // 是否使用已有的chunk,设置为true表示如果使用到的文件已经被分割过了
        // 就不会再进行分割,生成新的分割文件
        reuseExistingChunk: true
      }
    }
  }
}
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

动态导入(dynamic import)

function getComponent() {
  return import('lodash')
    .then(({ default: _ }) => {
      const element = document.createElement('div');

      element.innerHTML = _.join(['Hello', 'webpack'], ' ');
      return element;
    })
    .catch((error) => 'An error occurred while loading the component');
 }

setTimeout(() => {
  getComponent().then((component) => {
    document.body.appendChild(component);
  });
}, 50000);

// async

async function getComponent() {
    const element = document.createElement('div');
    const { default: _ } = await import('lodash');
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    return element;
 }
setTimeout(() => {
  getComponent().then((component) => {
    document.body.appendChild(component);
  });
}, 50000);

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

# Prefetching和PreLoading

// preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。 // preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。 // preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。

prefetch: 加载的内容可能会在未来的任何时间被使用,它会在主文件加载完毕并且利用浏览器的空闲时间来进行资源请求

preloading: 加载的内容会被主文件立即用到,拥有中等程度的资源加载优先权,并且会在页面加载时立即和主文件平行使用浏览器提供的资源。

# MiniCssExtractPlugin拆分css代码