谈谈CommonsChunkPlugin抽取公共模块

引言

webpack插件 CommonsChunkPlugin 的主要作用是抽取webpack项目入口 chunk 的公共部分,具体的用法就不做过多介绍,不太了解可以参考 webpack官网 介绍;

该插件是webpack项目常用的一个优化功能,几乎在每个webpack项目中都会用到。使用该插件带来的好处:

  • 提升webpack打包速度和项目体积:将webpack入口的chunk文件中所有公共的代码提取出来,减少代码体积;同时提升webpack打包速度。

  • 利用缓存机制:依赖的公共模块文件一般很少更改或者不会更改,这样独立模块文件提取出可以长期缓存。

但是在项目中,若插件打开方式不正确的话,上面的第二点其实是无法实现,因为这种情况下:

没有被修改过的公有代码或库代码打包出的Entry Chunk,会随着其他业务代码的变化而变化,导致页面上的长缓存机制失效。

那么,下面就来开启 CommonsChunkPlugin 正确的打开方式。

CommonsChunkPlugin不正确用法

假如将我们项目的公共库如react、react-dom、react-router与业务代码隔离,将其提取为vendor chunk,webpack配置如下:

const webpack = require("webpack");
const path = require('path');
module.exports = {
  entry: {
    app: "./app.js",
    vendor: ["react","react-dom", "redux", "react-redux", "react-router-redux"]
  },
  output: {
    path: path.resolve(__dirname, 'output'),
    filename: "[name].[chunkhash].js"
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({names: ["vendor"]})
  ]
};

上面将项目一些基础库打包成一个名为 vendor 的chunk中,并将业务相关的代码打包到一个名为app的chunk中;

webpack打包编译后的结果如下:

我们对其中的业务代码app.js进行修改后,重新编译结果如下:

可以发现,在CommonsChunkPlugin这种配置下,当业务代码app发生变化,而库代码也跟着变化,vender的chunkhash也跟着变化,这样vendor的引用的名称跟着变化,导致浏览器端的长缓存机制失效。

引起问题的原因

引起webpack每次打包编译时vendor跟着变化的原因:

webpack每次build的时候都会生成一些运行时代码。当只有一个文件时,运行时代码直接塞到这个文件中。当有多个文件时,运行时代码会被提取到公共文件中,也就是上面CommonsChunkPlugin配置的vendor chunk中。

webpack每次编译时产生的运行时代码,包括全局 webpackJsonp 方法的定义和维护模块依赖关系,具体可以参考 这里的commons.js

所以,上面webpack的CommonsChunkPlugin配置中,每次编译时这些代码都会打包到vendor中,导致每次vendor的 chunkhash 每次都会变化。

那么,我们可以在对vendor chunk进行配置,抽取其中的公共代码,即webpack运行时代码,这样就可以将项目依赖的基础库模块与业务模块隔离开来,因为不会对这些文件进行修改,所以这些文件可达到长缓存的作用。具体配置如下:

module.exports = {
  entry: {
    app: "./app.js",
    vendor: ["react","react-dom", "redux", "react-redux", "react-router-redux"]
  },
  ....
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({names: ["vendor"]}),
    new webpack.optimize.CommonsChunkPlugin({
        name: 'manifest',
        chunks: ['vendor']
    })
  ]
};

这样,即使修改业务app代码,项目依赖的基础库vendor chunk也不会发生变化;只是抽取的manifest chunk每次还会变化,但是这个文件体积非常小,相比vendor来说这种方式的收益更大。如下图:

修改app代码后的打包编译结果如下,可以看到vendor的chunkhash没有变化

在webpack中配置CommonsChunkPlugin时需要注意一点:

配置webpack的output项时,其 filenamechunkFilename 必须使用 chunkhash 。不要使用 hash ,否则即使按照上面的配置也不能达到预期的效果。至于hash与chunkhash的区别,可参考 github的回答

参考

1、 webpack之CommonsChunkPlugin正确打开方式

2、 webpack 填坑之路–提取独立文件(模块)

3、 webpack代码分割技巧

4、 听说你用webpack处理文件名的hash?那么建议你看看你生成的hash对不对

5、 chunkhash

6、 multiple-commons-chunks

博客园精华区责编内容来自:博客园精华区 (源链) | 更多关于

阅读提示:酷辣虫无法对本内容的真实性提供任何保证,请自行验证并承担相关的风险与后果!
本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 前端开发 » 谈谈CommonsChunkPlugin抽取公共模块

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录