本文章是在基于webpack多入口配置工程而且项目须要持续迭代做为基础去讨论的,单页面不做讨论。文章适合对webpack有必定了解的人看,主要讨论工程化中关于缓存利用率的问题。css
在webpack中,咱们一般会打包一个vendor和一个common文件做为基础包,vendor一般是将npm中的依赖打包、而common则是让达到必定引用次数的模块进行打包。具体配置以下:html
以上的配置,在持续迭代中,是不利于持久性缓存的,由于须要持续迭代,不可避免的是业务文件的修改,前端作缓存主要依靠的是经过给文件名加上hash值去控制文件缓存,而webpack1中一旦修改了某个文件,会致使总体的文件hash值的变化,包括vendor和common的hash值,可是这一个缺点在webpack2之后就被处理得比较好了,能够用HashedModuleIdsPlugin稳定模块的id,以保证vendor在单个业务文件修改时,其余文件的hash值保持稳定。前端
可是在持续增加的业务中,这样的方式对持久化就是可靠的吗?若是你在增量迭代时,忽然须要引入某一些npm包呢?致使vendor的hash值在这个时候也会发生变化,全部的用户不得不从新下载一个庞大的vendor文件。vue
根据这种场景咱们能够如何去优化这个缓存呢?这里我采用的方案是,将整个项目依赖的基础包,单独放在vendor中进行手动配置打包,在入口配置中加入本身手动配置的vendor列表,这一个列表是整个项目最基础依赖的包。webpack
例如:在一个多入口vue创建的项目中,咱们项目几乎每一个入口页面都要引入vue,那么咱们的vendor列表中就能够配置上vueios
那么vendor包中就只会将vue打包进vendor,而其他的模块则按照引用次数将包打包进common中,这么作的好处是什么?在项目迭代中,vendor的打包是咱们能够控制的,也就是这个列表咱们不修改,则vendor的hash值不变,也就是说在用户不清除缓存的状况下,咱们的vendor包能够一直在缓存中,对于页面的性能来讲是有保证的,变化的模块也仅仅在common模块和其余的业务文件。git
好比,在vue的项目中,咱们集成了vuex、rxjs、axios等库,在多页面开发中这些库基本在每个入口中都会有引用到,那么咱们是否是能够将vendor的列表配置成[ 'vue', 'vuex', 'rxjs', 'axios' ],经过commonPlugin则能够将列表中的模块打包成vendor,在迭代中,其余npm包的引入并不会影响到vendor hash值的改变,等到你须要更新vendor时,则能够手动往列表中添加依赖。程序员
dll文件是在开发时,先对全部的npm包预先打包,每个入口都会引入,以后根据manifest去对npm包资源进行引用,这样作,在开发时就不须要对npm包进行打包构建,节省一部分时间,具体可google。github
这里就会涉及到一个问题,每一次npm依赖更新了,都须要从新进行dll文件的打包。做为一个程序员,很显然,这么作不够偷懒。那咱们能够如何去作dll文件构建的自动化呢?这里提供一下个人思路。web
通常咱们在开始时,一般使用npm script进行项目构建、而dll文件须要单独运行命令,以后再构建项目
webpack --config dll.config.js
webpack-dev-server --config dev.config.js
复制代码
由于涉及到两条命令,因此我选择了使用shell对两个命令合并
// npm run start命令行执行dev.sh脚本
sh bin/dev.sh
复制代码
#!/bin/bash
### 思路
###一、在首次构建时,须要生成依赖的数量,并将数据重定向到文件中,用于二次构建时依赖数量的匹配
###二、二次构建时,会先判断记录了依赖数量的文件是否存在,存在则读取数量进行现有依赖数量的匹配,若依赖数量无变化,则认为dll文件不须要构建,直接运行项目的构建,若依赖数量变化,则从新构建dll文件
### 用于本地开发时自动维护dll文件
rootPath=`pwd`
packagePath=${rootPath}'/package.json'
dllValidatePath=${rootPath}'/build/vendor.dll.validate.txt'
### 读取package.json的dependencies与devDependencies对应的行数
dependenciesRow=`grep -n "dependencies" $packagePath | cut -d ":" -f 1`
devDependenciesRow=`grep -n "devDependencies" $packagePath | cut -d ":" -f 1`
### 依赖行数(以此判断依赖是否增减)
rows=$[$devDependenciesRow-$dependenciesRow]
### 判断vendor.dll.validate.txt文件是否存在
if [ -e $dllValidatePath ]; then
### 获取以前的依赖行数
oldRows=`cat $dllValidatePath`
if [ $oldRows == $rows ]; then
### 依赖数量相等则直接构建
npm run dev
else
echo $rows > $dllValidatePath
### 不等,从新建立vendor.dll.js,并将新的行数写到vendor.dll.validate.txt
npm run dll
npm run dev
fi
else
rm -rf build
mkdir build
touch $dllValidatePath
echo $rows > $dllValidatePath
npm run dll
npm run dev
fi
复制代码
上面是经过依赖数量的变化来作实际上是有点bug的,若是依赖增长了以后再减小到相同数量,dll文件并不会从新构建,这时须要本身手动构建一次,因此,严谨一些应该是要对依赖列表进行先后对比才能够肯定dll是否须要变化shell相应的也会更复杂一些吧,之后有时间优化一下这里的逻辑。
注意:dll文件,最好不要压缩,由于压缩插件会将console打印的语句去除,会致使开发时框架或者库的错误提示或者警告丢失。
不知道你们有没一种状况,就是某一些库,只是那么两三个入口须要使用,可是却被打包进common中。好比一些即时聊天服务,一般须要引入一些script或者css,而你的common配置中,超过两个引用次数就会将包打进common中,致使common过大,而每个入口一般都须要引入common,而且这些外部引用的库会随着common的打包变化而从新下载,这就会致使用户没法持久缓存这部分这种库。
固然,咱们能够经过增长common的模块引用次数下限去将这种库排除在外,的确能够,可是这样对common的控制就会受限,这不是我想的,我想common的配置,与这种业务性很是强的库抽离出来。
先看一下HtmlWebpackPlugin的配置
这里咱们经过这个插件的自定义配置,在html中经过标记将script或者css文件以绝对路径的方式输出到结果中,这样咱们就不须要经过webpack对这种稍微大一些又不想打包进common的包进行引用了,直接经过全局script标签的方式进行引入,以必定的规范放置文件,根据文件的版本作缓存的控制。
以上是我对于webpack多入口配置的一些思考以及建议,若有错误,欢迎及时指正。下面是github项目地址webpack3-vue-cli