前言:
最近在優(yōu)化項目的時候,發(fā)現隨著前端項目變得越來越大华嘹,導致vendor.js也隨之變得很大反浓,雖然用了代碼分離和依賴文件按需加載任内,解決了vendor.js單個文件比較大的問題。 但是每次運行打包都需要很久牌里,這個讓人也很痛苦含衔。于是開始研究怎么優(yōu)化這些結構。首先二庵,項目中有很多依賴文件贪染,webpack每次在打包這些文件是很耗時的,但是這些文件在項目開發(fā)過程中是基本上不會變的催享。 這樣每次都打包就顯得很浪費杭隙。
基礎技術框架: vue2.0生成的項目文件結構。webpack@^1.13.2
探索過程:
webpack打包優(yōu)化因妙。于是就找到了webpack 優(yōu)化 體積篇痰憎, 這篇文章,優(yōu)質好文攀涵。 里面提供了兩種方案铣耘, 一種是webpack的external配置依賴; 一種就是本文介紹的 DllPlugin&DllReferencePlugin以故。 前者比較簡單蜗细,使用起來也很方便。但是不夠靈活怒详。 于是作者采用了第二種方案炉媒。
第二種方案的好處就是可以按需將多個依賴打包成一個js文件。 在js中還是可以正常引用昆烁,同時逼格也稍微高一點吊骤, 我承認是因為這一點選擇的這個方案。 但是看了文章中的第二個方案后發(fā)現静尼。我只能把文件打包成js白粉,并不能很完美的在index.html中引入這個js文件传泊。 這個真的很苦惱, 這么明顯掉逼格的方式博主肯定是不會用的鸭巴。于是開始研究解決方案眷细,首先想到的是html-webpack-plugin, 這個插件是webpack中用作將webpack打包后輸出的文件chunks,插入到HTML中的奕扣。 但是有兩個限制條件:
- 我們這里的dll.js 是提前打包好了的薪鹦,而不是在每次build的時候去打包輸出的;這樣才能做到依賴包一次構建惯豆,無限次使用
- vue中webpack輸出的文件名都帶有hash值池磁; 而用dll構建后輸出的文件名是固定的。
博主就想到了一個歪招楷兽, 就是在html-webpack-plugin中添加自定義參數地熄,然后再HTML中使用 ejs語法 htmlWebpackPlugin.options.xx來獲取參數值,來向HTML中注入script標簽芯杀。 后來發(fā)現在本地開發(fā)環(huán)境每次啟動都會編譯失敗端考, 導致script標簽插入不進去。本來就已經絕望了揭厚,要放棄了却特。 但是這個時候其實距離最后的成功已經很近了。html-webpack-plugin中HTML 是支持ejs語法的筛圆,只是沒有從html-webpack-plugin中正確的獲取到參數裂明。 只要能夠將參數通過webpack的配置傳到HTML頁面,就大功告成了太援。
html-webpack-plugin中有句話:webpackConfig: the webpack configuration that was used for this compilation. This can be used, for example, to get the publicPath (webpackConfig.output.publicPath)
就是HTML中可以通過webpackConfig獲取到webpack的配置闽晦。 哈哈, 這就可以了提岔。[注: 此功能在webpack2.0以上不能使用]
=====================================
一個月后
當博主想要自己做一個插件的時候仙蛉,發(fā)現了這個好用的小工具 add-asset-html-webpack-plugin, 正是博主要實現的功能碱蒙, 果斷使用荠瘪。 有個小坑, 在附錄代碼中會說明振亮。
=====================================
下面是主要文件的配置巧还。 有問題歡迎反饋。
操作:
- config/index.js 中配置依賴包
modules.exports = {
…. 原始配置
library: {
'lib_v1_0': ["babel-polyfill", "mqtt"],
'vueBucket_v1_2': [
"vue/dist/vue.esm.js",
"vue-lazyload",
"vue-resource",
"vue-router",
"vuex",
"vuex-router-sync",
]
}
}
- 新建 build/webpack.dll.conf.js
- 這個文件讀取config/index.js 的library 中配置了那些module需要打包
- dll build 導出manifest.json 文件坊秸, 留給 DllReferencePlugin在打包時候識別dll都打包了那些node_module
// webpack.dll.conf.js
const webpack = require('webpack');
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin');
const {build, dev, library} = require('../config')
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? build.assetsSubDirectory : dev.assetsSubDirectory
module.exports = {
// 讀取library.entry 里配置的node_module
entry: library,
// 輸出到static文件夾下面, 補充知識[vue項目目錄之static]
output: {
path: path.resolve(__dirname, '..', assetsSubDirectory),
filename: `[name].dll.js`,
library: '[name]_library'
},
plugins: [
new CleanWebpackPlugin(['static'], { root: path.resolve(__dirname, '..')}),
// 文件輸出到 ./build/manifest.json 中
new webpack.DllPlugin({
path: path.resolve(__dirname, '..', assetsSubDirectory, '[name].manifest.json'),
name: '[name]_library',
}),
// 壓縮打包的文件
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
};
- 解析dll打包的node_module
// webpack.base.conf.js
var path = require('path')
var config = require('../config')
var webpack = require('webpack')
var AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
...
module.exports = {
...
plugins: [
...,
...Object.keys(config.library).map(name => {
return new webpack.DllReferencePlugin({
context: '.',
manifest: require(`../static/${name}.manifest.json`),
})
}),
new AddAssetHtmlPlugin(Object.keys(config.library).map(name => {
return {
filepath: require.resolve(path.resolve(`./static/${name}.dll.js`)),
includeSourcemap: false
}
})),
]
}
- 在
package.json
中配置打包命令
- 運行命令
npm run build:dll
{
"scripts": {
"dev": "node build/dev-server.js",
"build:dll": "webpack --config build/webpack.dll.conf.js"
}
}
-
項目目錄如下
目錄.png
參考知識:
- webpack 優(yōu)化 體積篇澎怒,速度篇褒搔。 優(yōu)質好文
- vue-webpack 解釋vue中static文件夾的含義
- DllPlugin & DllReferencePlugin
- html-webpack-plugin