【翻译】Webpack 4 course – part four. Code splitting with SplitChunksPlugin

Webpack 4 课程 - 第4部分 - 使用SplitChunksPlugin进行代码拆分(Code splitting)

本文翻译自wanago.io的Webpack 4 course – part four. Code splitting with SplitChunksPlugin 的文章。
自学用,翻译超垃圾

Webpack4给我们带来了众多变化。在这些变化之中,比如在快速打包方面,新版Webpack引入了SplitChunksPlugin属性,废弃了CommonsChunksPlugin。本篇文章,你将学习到如何拆分你的输出代码来改善应用程序的性能。

代码拆分(code splitting)思想

首先:webpack的代码拆分到底是什么?它允许你将代码拆分成多个文件。如果使用得当,这将大大提升应用程序的性能。其中的原因是,浏览器会缓存你的代码。当你每次更改代码的时候,包含了被更改代码的文件就会被访问你网站的所有浏览者重新下载。但是,你也有可能不会更改你代码里的依赖模块。如果你将依赖模块拆分到一个单独的文件里,那么浏览者将不会再次下载没有被更改的这些文件。

使用webpack生成一个或多个bundles,每个bundle包含了我们源代码最终的生成的版本。bundles由多个chunk组成。

入口(Entry)

Entry属性要填入一个文件地址,这个文件就是我们应用程序开始执行的地方,当然也是webpack进行打包的一个开始点。你可以只定义一个入口(比如针对Single-Page Application进行开发),也可以定义多个入口(比如针对Multiple-Page Application进行开发)。

当定义一个入口时,将会生成一个chunk。如果你使用字符串定义一个入口时,打包生成的文件名将被命名为main。如果你使用对象定义多个入口,打包生成的文件名将会被命名为对象里面的键值。如下的例子是等价的:

entry : './src/index.js'
entry : {
    main : './src/index.js'
}

输出(output)

Output对象是关于webpack怎样打包以及打包代码到哪里的一个配置项。尽管entry可以配置多个,但是output只能有一个。这里的output就是我们命名chunk的重要地方。你可以为最终bundle输出指定一个具体的文件名,但是我们想要拆分代码的话,就最好不要这样做。你可以使用[name]来生成一个模板,该模板可以生成我们输出文件的文件名:

output : {
    filename : '[name].[chunkhash].bundle.js',
    path : path.resolve(__dirname, 'dist')
}

值得一提的是这里的[chunkhash] :它是基于你文件的内容生成的chunk专属hash值。当你的文件内容改变时,这个hash值也会跟着改变。由于浏览器会以不同的方式缓存文件。如果文件名改变,浏览器就会知道该文件需要重新加载。举个例子,一个chunkhash值类似于:0c553ebfd158e16da428

我们上面入口定义的main chunk就会被打包进一个命名为main.[chunkhash].bundle.js 的文件里头。

SplitChunksPlugin

有了SplitChunksPlugin,你可以移动你应用程序的特定代码部分到单独的文件中。如果一个模块被多个chunk引用,那么它可以很容易的在这些chunk中进行共享。这是webpack的默认行为。

utilities/users.js
export default [
  { firstName: "Adam", age: 28 },
  { firstName: "Jane", age: 24 },
  { firstName: "Ben",  age: 31 },
  { firstName: "Lucy", age: 40 }
]
a.js
import _ from 'lodash';
import users from './users';

const adam = _.find(users, { firstName: 'Adam' });
b.js
import _ from 'lodash';
import users from './users';

const lucy = _.find(users, { firstName: 'Lucy' });
webpack.config.js
module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  }
};

如果运行如上代码,你会发现webpack会生成两个文件:a.[chunkhash].bundle.jsb.[chunkhash].bundle.js ,这两个文件都包含了lodash库模块:这样并不好!我以前说过,为共享的库创建单独的文件是webpack的默认行为,但是这涉及到async chunks,意味着我们需要异步导入这些文件。在介绍懒加载(lazy loading)的时候,我们将会介绍更多这样的话题。为了包含所有的类型的chunk,我们需要更改一下我们webpack的配置:

扫描二维码关注公众号,回复: 17142989 查看本文章
webpack.config.js
module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  }
};

现在我们看到多了一个文件vendors~a~b.[chunkhash].bundle.js ,该文件包含了lodash库。这由于webpack的一些开箱即用的默认值:

splitChunks: {
    chunks: "all",
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      }
    }
  }

配置里第一个vendors包含了从node_modules拆分的文件。default是用来拆分其他的共享模块文件。这就有一点冗余的问题。a.[chunkhash].bundle.jsb.[chunkhash].bundle.js 都包含了users.js。这是因为,splitchunksplugin拆分chunk时,默认只拆分大于30kb的文件。我们可以容易更改这个大小:

webpack.config.js
module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all",
      minSize: 0
    }
  }
};

运行上面查看结果,发现新生成一个名为a~b.[chunkhash].bundle.js ,这是一个默认缓存组。由于我们的users.js文件远小于30kb,如果没有minSize属性的话,它将不会单独拆分到一个文件里。事实上,这是利大于弊的,因为拆分进单独文件中,并不会提升性能,反而还会强迫浏览器为小容量代码增加请求数量,使得性能降低。

我们还可以专门为utilities目录做更多:

webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        utilities: {
          test: /[\\/]src[\\/]utilities[\\/]/,
          minSize: 0
        }
      }
    }
  }
};

现在我们的bundle包含了4个文件:a.[chunkhash].bundle.js, b.[chunkhash].bundle.js, vendors~a~b.[chunkhash].bundle.jsutilities~a~b.[chunkhash].bundle.js 。即使我们现在在splitchunks对象里设置全局的minSize:0 , default缓存组也不会被创建。这是因为所有被涉及到的文件被我们创建的utilities组给覆盖掉了。并且有一个默认为0的优先权(priority)属性,这个更高于default缓存组。如果你注意到了会发现,default缓存组已经设置了-20的优先权(priority)。

其实你也可以更改其他的默认参数,具体可以查看SplitChunksPlungin文档

总结

即使你只有一个入口点(比如针对大部分的单页面应用),把你的依赖拆分到单独的文件是个很好的选择。并且使用webpack4很容易做到,只要在你的splitChunks配置里,设置chunks为all就可能满足你的需求。如果想让我介绍其他方面,请告诉我。稍后我们将会学习到如何使用懒加载继续改善应用程序的性能,敬请期待!

猜你喜欢

转载自blog.csdn.net/sinat_25259461/article/details/81484663