hello~亲爱的看官老爷们你们好~ 最近一直在学习 webpack
的相关知识。曾几什么时候我总以为 webpack
的体系庞大而难以掌握,一直回避不肯去学。然而伟人鲁迅曾说过: 世上太多事会因没法掌握而使你狂躁不安,最好的解决方法就是硬着头皮开始作! 于是就从比较简单的 CommonsChunkPlugin
开始学起吧~ css
虽然本文比较简单,但仍是须要一点 webpack
知识的,如若彻底没接触过 webpack
,建议先移步 官方文档 与 Webpack 3,从入门到放弃 了解一下 webpack
基础为佳~html
CommonsChunkPlugin
插件,是一个可选的用于创建一个独立文件(又称做 chunk)的功能,这个文件包括多个入口 chunk 的公共模块。经过将公共模块拆出来,最终合成的文件可以在最开始的时候加载一次,便存起来到缓存中供后续使用。这个带来速度上的提高,由于浏览器会迅速将公共的代码从缓存中取出来,而不是每次访问一个新页面时,再去加载一个更大的文件。vue
简单来讲,这有点像封装函数。把不变的与变化的分开,使得不变的能够高效复用,变化的灵活配置。接下来会根据这个原则优化咱们的项目,如今先看看虚拟的项目长成什么样吧~node
新建一个 index.html
模板与入口 index.js
文件,简单配置以下:jquery
index.html
: webpack
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<p>{{ vue_test }}</p>
</div>
<div class="jq_test"></div>
</body>
</html>复制代码
index.js
:git
import Vue from 'vue';
import $ from 'jquery';
new Vue({
el: '#app',
data: {
vue_test: 'vue is loaded!'
}
})
$(function() {
$('.jq_test').html('jquery is loaded!')
})复制代码
为演示起见,代码十分简单,相信不用多加解释。接下来先简单配置一下 webpack.config.js
,代码以下:github
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
entry: {
index: path.join(__dirname, 'index.js')
},
output: {
path: path.join(__dirname, '/dist'),
filename: 'js/[name].[chunkhash].js'
},
resolve: { alias: { 'vue': 'vue/dist/vue.js' } },
plugins: [
new CleanWebpackPlugin(['./dist']),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
new BundleAnalyzerPlugin(),
]
};复制代码
CleanWebpackPlugin
主要用于清除 dist
目录下的文件,这样每次打包就没必要手动清除了。HtmlWebpackPlugin
则是为了在 dist
目录下新建 html
模板并自动插入依赖的 js
。 BundleAnalyzerPlugin
主要是为了生成打包后的 js
文件包含的依赖,如此时进行打包,则生成:web
能够看到生成的 index.js
文件包含了 vue
与 jquery
。vuex
通常而言,咱们项目中的类库变化较少,业务代码却是多变的。须要想办法把类库抽离出来,把业务代码单独打包。这样加伤 hash
后浏览器就能缓存类库的 js
文件,优化用户体验。此时咱们的主角 CommonsChunkPlugin
就正式登场了。咱们在 webpack.config.js
文件的 plugins
中添加 CommonsChunkPlugin
,配置以下:
plugins: [
//...此前的代码
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, './node_modules')
) === 0
)
}
}),
]复制代码
上述配置,是经过 CommonsChunkPlugin
生成一个名为 vendor
的 js
文件,它抽取入口文件也就是 index.js
中来源于 node_modules
的依赖组成。此例中就是 vue
与 jquery
。打包出来画风是这样的:
此时看上去解决了咱们的问题,将依赖的类库抽取抽来独立打包,加上缓存就能被浏览器缓存了。然而事情没那么简单,不行你随意改一下入口的 index.js
代码,再次打包:
绝望地发现 vendor.js
文件的 hash
改变了。简单说,这是由于模块标识产生了变化所致使的,更具体的缘由能够查看相关的中文文档~修正的方法其实也挺简单,就是再使用 CommonsChunkPlugin
抽取一次模块,将不变的类库沉淀下来,将变化的抽离出去。于是添以下代码:
plugins: [
//...此前的代码
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, './node_modules')
) === 0
)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor', 'index']
})
]复制代码
打包后, dist/js
目录下多出一个名为 manifest
的 js
文件,此时你不管如何改变 index.js
的代码,打包后的 vendor.js
的 hash
都再也不会改变了。
然而稍等,当你想拍拍手收工的时候,思考一下这样的场景:随着项目不断迭代,vendor
中的依赖不断被添加与删除,使得它的 hash
会不断变化,这显然不符合咱们的利益,这到底如何解决呢?
既然 CommonsChunkPlugin
是能够按照咱们的需求抽取模块,而依赖的外部模块多是不断变化的,那么为什么不将基础的依赖模块抽取出来做为一个文件,其余的依赖如插件等做为另外一个文件呢?
简单说,如咱们的项目中 vue
是基本的依赖,必须用到它,而 jquery
等则是后加的类库,以后可能变动。那么将 vue
独立打包一个文件,有利于浏览器缓存,由于不管此后添加更多的类库或删去 jquery
时, vue
文件的缓存依然是生效的。于是咱们能够这么作,首先新建一个入口:
entry: {
index: path.join(__dirname, 'index.js'),
vendor: ['vue'],
},复制代码
此处主要是用于指明须要独立打包的依赖有哪些。以后在 plugins
中作以下修改:
plugins: [
//...此前的代码
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: function(module) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, './node_modules')
) === 0
)
},
chunks: ['index'],
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor', 'common', 'index']
})
]复制代码
插件 HashedModuleIdsPlugin
,是用于保持模块引用的 module id
不变。而 CommonsChunkPlugin
则提取入口指定的依赖独立打包,minChunks: Infinity,
的用意是让插件别管其余,就按照设置的数组提取文件就好。以后修改一下原来的 vendor
,重命名为 common
,指定它从入口 index.js
中抽取来自 node_modules
的依赖。最后就是抽取 webpack
运行时的函数及其模块标识组成 manifest
。运行一下 webpack
,构建出来如图:
能够看到 vue
与 jquery
被分开打包成了两个文件,咱们尝试添加一下新的依赖 vuex
,打包后结果以下:
如此一来,咱们的优化目的就达到了,不变的都提取出来,变化的能够动态配置~
webpack
插件 CommonsChunkPlugin
就介绍到这里了,然而优化仍是有不少的,好比开启压缩,去除注释等。而当项目体积逐渐增大时,CommonsChunkPlugin
就不必定是提取代码的最优解了。在打包速度与控制构建的精细程度来讲,结合 DLLPlugin
会有更好的表现。根据不一样的场景组合不一样的插件以达到咱们的目的,原本就是 webpack
的魅力之一。
感谢各位看官大人看到这里,知易行难,但愿本文对你有所帮助,全部的代码均会被上传到 github 上,滚求 star
~谢谢!