CommonsChunk
CommonsChunk
插件的作用就是提取代码中的公共代码,然后将公共模块打包到一个独立的文件中,以便在其它的入口和模块中使用,原理就是把多个入口共同的依赖都给定义成一个新入口
多种打包情况:
单一入口,模块单一引用
webpack.config.js
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry:
{
main:'./main.js',
},
output: {
path:__dirname+'/dist',
filename: 'build.js'
},
plugins: [
]
};
main.js
require("jquery");
jquery
模块被一起打包到 build.js
单一入口,模块重复引用
相同的模块重复引用,webpack
只打包一份
webpack
打包的原理为,在入口文件中,对每个 require
资源文件进行配置一个 id
,也就是说,对于同一个资源,就算是 require
多次,它的 id
也是一样的,所以无论在多少个文件中 require
,它都只会打包一份
即内部的 __webpack_require__
函数传入统一 id
时,不会导入新的模块,直接返回
我的理解是,只有在多入口,模块重复引用时,使用 CommonsChunkPlugin
才能提取出重复打包的模块。当然,也可以在单入口时,提取出某些框架的代码,减少请求次数
单一入口,提取框架模块
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry:
{
main:'./main.js',
vendor: ["react", "react-dom", '其他模块'],//插件中 name,filename 以这个key为值
},
output: {
path:__dirname+'/dist',
filename: '[name].js'//不使用[name],并且插件中没有filename,
},
plugins: [
new CommonsChunkPlugin({
name: 'vendor'
// filename:"vendor.js"//忽略则以name为输出文件的名字,否则以此为输出文件名字
})
]
};
打包出不变的框架模块,可以缓存在客户端,服务端更新后客户端只需要获取新的 main.js
,减少了获取框架模块的一次请求
不过 CNode 上有篇文章提出了 Hash 会变的问题 https://cnodejs.org/topic/58396960c71e606e36aed1db
多入口,模块重复引用,分文件输出
多入口就是分别执行的单入口,彼此之间互不影响,而该插件的原理就是把多个入口共同的依赖都给定义成一个新入口
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
main: './main.js',
main1: './main1.js',
common1: ['jquery'],
common2: ['vue']
},
output: {
path: __dirname + '/dist',
filename: '[name].js'//不使用[name],并且插件中没有filename,
//这输出文件中只用chunk.js的内容,main.js的内容不知跑哪里去了
},
plugins: [
new CommonsChunkPlugin({
name: ["chunk","common1","common2"],//浏览器页面上使用的时候 common2 必须最先加载
// filename:"chunk.js"//忽略则以name为输出文件的名字,
//否则以此为输出文件名字
minChunks: 2 //默认值
})
]
};
jquery
被打包到 common1.js
,vue
被打包到 common2.js
,chunk.js
打包的是公共的业务模块(webpack用插件CommonsChunkPlugin进行打包的时候,将符合引用次数(minChunks)的模块打包到 name
参数的数组的第一个块里(chunk
),然后数组后面的块依次打包(查找 entry
里的 key,没有找到相关的 key 就生成一个空的块),最后一个块包含 webpack
生成的在浏览器上使用各个块的加载代码,所以页面上使用的时候最后一个块必须最先加载)
可以看看是插件处理后的源码
common2.js
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ var parentJsonpFunction = window["webpackJsonp"];
/******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) {
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
在全局变量上定义了一个 webpackJsonp
函数
在 main.js 中
webpackJsonp([0],[
/* 0 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(1);
/***/ },
使用了上面定义的全局函数,所以在浏览器中加载必须先加载 common2.js
,在这里加载了我们的入口模块0
在 main1.js 中
webpackJsonp([1],{
/***/ 0:
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(8);
在这里加载了我们的入口模块1
此时,我们提取出去的公共模块和我们的入口模块又重新走到了一起,而且只有一份,在两个入口中引用(__webpack_require__
)的是同一个 id