在CQM平臺開發時,把demo網站給同事體驗,都紛紛反饋第一次打開頁面的時候需要等待很久,頁面一直在轉菊花。作爲一個爲韓國頭部廠商提供優質服務的網站,接到這種反饋,這不是啪啪打臉嗎。
代碼是在以前的老框架上寫的(必須堅定把鍋甩出去,手動捂臉)。喝杯咖啡鎮定下,找找什麼問題。趕緊打開chrome (disable cache):
哇,嚇了一跳,這打包出來的JS辣麼大:lib.js 2.3M(花了14s 才加載完)、app.js 1.2M(花了9s多加載完),難怪反饋頁面響應慢。
- 1、祭出神器把Bundle分析利器拿出來:
webpack-bundle-analyzer是一個基於webpack的插件,能夠用zoomable treemap可視化webpack輸出文件的大小(
Visualize size of webpack output files with an interactive zoomable treemap)
不慌,喝口白開水,裝上webpack-bundle-analyzer
看看裏面分別是啥。
npm install webpack-bundle-analyzer
在webpack.app.config.js引入webpack-bundle-analyzer
constBundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { output: { //省略 }, entry: { //省略 }, plugins: [ new BundleAnalyzerPlugin(), ], };
很簡單吧,這樣我們就配好了webpack-bundle-analyzer
- 2、優化app.js文件
項目的package.json文件如下:
{ "private": true, "scripts": { "dev": "npm run development", "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", //開發環境生成 app.js及頁面js "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=webpack.app.config.js", "watch-poll": "npm run watch -- --watch-poll", "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", "prod": "npm run production", //生成環境打包 app.js及頁面js "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=webpack.app.config.js", //單獨打包 lib.js "build-lib": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=webpack.lib.config.js", "build-online": "gulp pack --env production" }, "devDependencies": { //省略 }, "dependencies": { // } }
運行下npm run watch,Webpack會自動打開瀏覽器,在127.0.0.1:8888上顯示如下:
ps: npm run watch 對應的配置文件webpack.app.config.js,打包的app.js及頁面js的各組成的大小(面積越大,表示比重越大)。可以看到,app.js裏面大頭分別是vue、vue-router、vue-i18n組件(好傢伙,這些組件都是在app.js裏面import進來的)。我們將他們踢出去:
a、在webpack.app.config.js裏面添加externals參數,這樣即使我們沒將這幾個組件打包到app.js中,我們依然能將其import進來並use:
module.exports = { externals : { 'vue':'Vue', 'vue-router':'VueRouter', 'vue-i18n': 'VueI18n', }};
b、接着在index.html中:
<scriptsrc="//cdn.bootcss.com/vue/2.3.3/vue.min.js"></script> <script src="//cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script> <scriptsrc="https://unpkg.com/[email protected]/dist/vue-i18n.js"></script>
爲什麼要這麼做呢?因爲vue和vue-router在cdn上都提供了min版的js,已經是壓縮精簡版的,而vue-i18n.js的官方網站也建議使用cdn方式引入,沒必要將都打包到app.js中。
對比優化前的app.js大小1.2M,以及下圖單獨引入vue.min.js、vue-i18n.js、vue-router.min.js的大小,分別爲78K、38K、24K。效果十分明顯
c、除了拆分依賴包,另一個重要的優化就是壓縮代碼,這裏使用的是uglifyjs-webpack-plugin,同樣在webpack.app.config.js的plugin裏面添加
constUglifyJsPlugin= require('uglifyjs-webpack-plugin'); module.exports = { plugins:[ new UglifyJsPlugin({ uglifyOptions: { output: { beautify: false, comments: false, }, compress: { warnings: false, drop_debugger: true, drop_console: true, pure_funcs: ['console.log', '(e = console).log' ] }, sourceMap: false } }) ]};
這樣之後效果如下,app.js從1.2M縮減到200kb,達到了可觀的效果
- 3、優化lib.js文件
導致我們頁面響應慢另一個大文件是 lib.js(這裏介紹下,在我們工程裏,對常用的第三方UI組件、繪圖組件、編輯組件,項目裏將其統一打包到lib.js裏面,不用每次構建都重新打包lib.js,這樣可以加快構建速度),對應配置文件webp.lib.config.js。同樣用webpack-bundle-analyzer,如圖所示:裏面體積最大的分別是element-ui、vue2-editor、highchart、jquery等
以前的webpack.lib.config.js文件如下:
module.exports = { output: { path: path.join(__dirname, './public/js'), filename: '[name].js', library: '[name]', }, entry: { "lib": ['vue','jquery', 'element-ui', 'vue-highcharts', 'vue2-editor', 'lodash'], }, };
對比上面的webpack.app.config.js,vue已經引進了,所以不必重複打包。jquery、element-ui可以通過引入cdn文件解決,vue2-editor目前項目中暫時沒用到,所以去掉唄。再添加上代碼壓縮插件,修改後的webpack.lib.config.js文件如下:
module.exports = { output: { path: path.join(__dirname, './public/js'), filename: '[name].js', library: '[name]', }, entry: { "lib": ['vue-highcharts', 'lodash'], }, newwebpack.optimize.UglifyJsPlugin({ minimize: true }), };
但是在app.js中還使用element-ui,所以在webpack.app.config.js中需要在external添加該項element-ui
和
jquery
:
module.exports = { externals : { 'vue':'Vue', 'vue-router':'VueRouter', 'vue-i18n': 'VueI18n', 'element-ui':'ElementUI', 'jquery': 'jQuery.noConflict()' }};
在index.html中添加jquery.all.js和element-ui,引入的js如下:
<script src="//cdn.bootcss.com/vue/2.3.3/vue.min.js"></script> <script src="//cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script> <script src="//unpkg.com/[email protected]"></script> <script src="//unpkg.com/[email protected]/lib/umd/locale/en.js"></script> <script> ELEMENT.locale(ELEMENT.lang.en) </script> <script src="https://unpkg.com/[email protected]/dist/vue-i18n.js"></script> <script src="/js/lib.js?12124142"></script> <script src="http://iwaibao.qq.com/js/jquery.all.js?v=" language="javascript" type="text/javascript"></script> <script src="{{ mix('js/app.js') }}"></script>
這裏element-ui通過設置external然後引入cdn的js的時候有個坑,打包後老報錯:
索性通過npm uninstall element-ui,將這個組件刪除掉,直接通過cdn引入。執行npm run build-lib 生成,lib.js從2.3M減小到274kB,
最終頁面的js文件如下:
對比優化前,網站訪問流暢了不少(總共花了3s多加載完成)。雖然還不能做到如絲般柔滑,但羅馬不是一天建成的(畢竟不能一次優化的太完美,不然後面怎麼提升呢),比如打包速度提升(多線程打包)、頁面代碼分割與混淆等,後面咱們再慢慢優化
- 最後
webpack基本已經成爲前端項目的標配構建工具了,個人感覺大而全,裏面有很多插件。比較贊同知乎網友對其的評價:
webpack充斥着大量名字類似 what-the-fuck-is-this-plugin 的插件,以及這個插件附帶的一千種配置和一萬種副作用,以至於每次出現打包的問題都會產生哲學三問:
這個插件幹了什麼?
我的配置有錯誤嗎?
這個插件真的沒有bug嗎?
比如UglifyJsPlugin刪除生產環境裏console.log的選項drop_console死活不生效,最後只能通過vue-loader中的preLoader預加載選項,利用strip-loader將vue文件中的console去掉
let rules = [ { test: /\.vue$/, loader: 'vue-loader', options: { preLoaders: Mix.inProduction ? {js: 'strip-loader?strip[]=console.log,strip[]=console.warn'}:{}, loaders: //省略 } ]
最後的最後再加一條:這個插件版本對嗎?(手動哭臉)