一、根據(jù)可視化工具查看項目打包
webpack-bundle-analyzer可視化工具
Webpack進行打包,到底打了多少包,每個包有多大?webpack-bundle-analyzer這款插件可以幫助我們清晰展示。針對多余的包文件過大,剔除首次影響加載的效率問題進行剔除修改。

模塊功能:
- 意識到你的文件打包壓縮后中真正的內(nèi)容
- 找出哪些模塊組成最大的大小
- 找到錯誤的模塊
- 優(yōu)化它!
- 最好的事情是它支持縮小捆綁!它解析它們以獲得實際大小的捆綁模塊。它也顯示他們的gzipped大??!
安裝和使用:
npm install --save-dev webpack-bundle-analyzer
//在webpack.config.js中:
let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [new BundleAnalyzerPlugin()]
}
在vue-cli3中配置如下
//vue.config.js
let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
]
},
}
默認的可選配置對象:
new BundleAnalyzerPlugin({
// 可以是`server`,`static`或`disabled`。
// 在`server`模式下,分析器將啟動HTTP服務器來顯示軟件包報告。
// 在“靜態(tài)”模式下,會生成帶有報告的單個HTML文件。
// 在`disabled`模式下,你可以使用這個插件來將`generateStatsFile`設(shè)置為`true`來生成Webpack Stats JSON文件。
analyzerMode: 'server',
// 將在“服務器”模式下使用的主機啟動HTTP服務器。
analyzerHost: '127.0.0.1',
// 將在“服務器”模式下使用的端口啟動HTTP服務器。
analyzerPort: 8888,
// 路徑捆綁,將在`static`模式下生成的報告文件。
// 相對于捆綁輸出目錄。
reportFilename: 'report.html',
// 模塊大小默認顯示在報告中。
// 應該是`stat`,`parsed`或者`gzip`中的一個。
// 有關(guān)更多信息,請參見“定義”一節(jié)。
defaultSizes: 'parsed',
// 在默認瀏覽器中自動打開報告
openAnalyzer: true,
// 如果為true,則Webpack Stats JSON文件將在bundle輸出目錄中生成
generateStatsFile: false,
// 如果`generateStatsFile`為`true`,將會生成Webpack Stats JSON文件的名字。
// 相對于捆綁輸出目錄。
statsFilename: 'stats.json',
// stats.toJson()方法的選項。
// 例如,您可以使用`source:false`選項排除統(tǒng)計文件中模塊的來源。
// 在這里查看更多選項:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
statsOptions: null,
logLevel: 'info' 日志級別??梢允?信息','警告','錯誤'或'沉默'。
})
啟動服務:
生產(chǎn)環(huán)境查看:npm run build --report 或 正常build 即可啟動查看器
開發(fā)環(huán)境查看:webpack -p --progress 或啟動正常devServer服務即可啟動查看器!
Speed-Measure-Plugin可視化工具
通過這個插件,我們可以清楚的看到,打包整體的時間,各plugin,loader處理時間,以有利于我們針對打包速度取做優(yōu)化。

安裝和使用:
npm install --save-dev speed-measure-webpack-plugin
//webpack配置
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const webpackConfig = smp.wrap({
plugins: [
new MyPlugin(),
new MyOtherPlugin()
]
});
官方請看:Speed Measure Plugin
analyse
先使用 Webpack 打包指令生成 Webpack stats 分析文件
webpack --profile --json > stats.json
然后到官方提供的網(wǎng)頁上傳stats.json
就可以通過一些可視化資料來分析打包結(jié)果

官方請看:webpack
二、webpack外部擴展
列出了項目中較大的包,剩下的事情就是想辦法如何減小這些包的體積(將一個大包拆成多個小包)。
項目中產(chǎn)生較大的包的原因可以從兩個方面去考慮:
1. 項目中引入的依賴包過于龐大;
2. 業(yè)務代碼集中在一塊寫,或者是業(yè)務代碼寫的比較繁瑣;
對于這兩個問題,我們可以從兩個方面著手解決:
1. 抽離項目中公共依賴的、不常變動的、體積較大的包;
2. 將一個較大的業(yè)務代碼文件,拆成多個較小的文件,異步加載(或者優(yōu)化業(yè)務代碼)。
我們來討論第一種方法,在不改動業(yè)務代碼的情況下,如何減小公共依賴。
要知道這些依賴是我們需要的,不可能排除不引入。
但是他們都是全局依賴的,萬年不變的,可以使用瀏覽器自己的緩存來實現(xiàn)不重復加載。
具體做法就是:
將項目中需要的一些公共依賴包,并且不常變動的,單獨取出,不再每次都打包編譯(如React,Redux等)。
而是通過使用script標簽形式cdn引入,這樣在有緩存的情況下,這些資源均走緩存,不必加載。
具體做法:
總結(jié)需要抽離的公共依賴
這些依賴需要滿足一定的條件:
* 體積較大;
* 不常更新;
* 依賴較多;
* 是前置依賴;
常見的滿足這類條件的包有:
* react
* react-dom
* redux
* react-redux
* moment
* jquery
另外一些包文件如 Antd庫文件,整個包較大,但是每次用什么取什么的話,庫文件也會按需加載,不必單獨取出。
還有這類庫文件不建議單獨取出,因為里面可能會有bug,需要更新。
使用CDN引入資源
將抽離出來文件放到cnd上,注意,這些文件要是壓縮版本,并且是用ES5編寫的,否則瀏覽器報錯。
<head>
<title>React Starter Kit</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 體積較大的包 -->
<script src="https://cdn.bootcss.com/react/15.0.0/react-with-addons.min.js"></script>
<script src="https://cdn.bootcss.com/react/15.0.0/react-dom.min.js"></script>
<script src="https://cdn.bootcss.com/react-router/3.0.0/ReactRouter.min.js"></script>
<script src="https://cdn.bootcss.com/redux/3.6.0/redux.min.js"></script>
<script src="https://cdn.bootcss.com/react-redux/5.0.1/react-redux.min.js"></script>
<script src="https://cdn.bootcss.com/history/4.5.0/history.min.js"></script>
</head>
配置webpack.conf.js
資源已經(jīng)引入,接下來需要配置webpack,使其打包的時候不在將這些資源打包。
const webpackConfig = {
name: 'client',
target: 'web',
devtool: config.compiler_devtool,
resolve: {
root: paths.client(),
extensions: ['', '.js', '.jsx', '.json'],
},
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'react-router': 'ReactRouter',
'redux': 'Redux',
'history': 'History'
},
module: {},
}
這里externals告訴webpack那些資源從哪里尋找。
該對象的鍵表示 require 或者 import 時候的字符串
值表示的當前環(huán)境下的變量,比如引入React之后,React被作為全局對象,webpack就回去尋找React對象。
如果其中有一個找不到,打包就會失敗。
配置vendor.js
接下來配置vendor,使vendor也不打包該些JS
compiler_vendors : [
// 'react',
// 'react-redux',
// 'react-router',
// 'redux',
],
三、DLL方式
dll 全稱是:dynamic link library(動態(tài)鏈接庫)
dll方式也就是通過配置,告訴webpack指定庫在項目中的位置,從而直接引入,不將其打包在內(nèi)。
上面介紹的方式是將包放到cdn上,build的時候不在引入對應的包;
dll方式就是指定包在項目中,build的時候不在打包對應的包,使用的時候引入。
webpack通過webpack.DllPlugin與webpack.DllReferencePlugin兩個內(nèi)嵌插件實現(xiàn)此功能。
新建webpack.dll.config.js
const webpack = require('webpack');
module.exports = {
entry: {
bundle: [
'react',
'react-dom',
//其他庫
],
},
output: {
path: './build',
filename: '[name].js',
library: '[name]_library'
},
plugins: [
new webpack.DllPlugin({
path: './build/bundle.manifest.json',
name: '[name]_library',
})
]
};
webpack.DllPlugin選項:
* path:manifest.json文件的輸出路徑,這個文件會用于后續(xù)的業(yè)務代碼打包;
* name:dll暴露的對象名,要跟output.library保持一致;
* context:解析包路徑的上下文,這個要跟接下來配置的 webpack.config.js 一致。
運行:
webpack --config webpack.dll.config.js
生成兩個文件,一個是打包好的bundlejs,另外一個是bundle.mainifest.json,大致內(nèi)容如下:
{
"name": "bundle_library",
"content": {
"./node_modules/react/react.js": 1,
"./node_modules/react/lib/React.js": 2,
"./node_modules/process/browser.js": 3,
"./node_modules/object-assign/index.js": 4,
"./node_modules/react/lib/ReactChildren.js": 5,
"./node_modules/react/lib/PooledClass.js": 6,
"./node_modules/react/lib/reactProdInvariant.js": 7,
//其他引用
}
配置webpack.config.js
const webpack = require('webpack');
var path = require('path');
module.exports = {
entry: {
main: './main.js',
},
output: {
path: path.join(__dirname, "build"),
publicPath: './',
filename: '[name].js'
},
module: {
loaders:[
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'},
{
test: /\.jsx?$/,
loaders: ['babel-loader?presets[]=es2015&presets[]=react'],
include: path.join(__dirname, '.')
}
]
},
plugins: [
new webpack.DllReferencePlugin({
context: '.',
manifest: require("./build/bundle.manifest.json"),
}),
]
};
webpack.DllReferencePlugin的選項中:
* context:需要跟之前保持一致,這個用來指導webpack匹配
* manifest.json中庫的路徑;
* manifest:用來引入剛才輸出的manifest.json文件。