看了一下我司官網的webpack打包出來的大小狀況,發現有不少能夠優化的點,好比 lodash、moment.js、antd等等;
本文主要圍繞webpack的打包優化,並根據業務狀況適當的作減法。html
優化前必定要有一個界面能記錄目前的打包狀況,推薦用webpack-bundle-analyzer這個包, 它能夠看到打包後每一個模塊的大小,還能給出gizp壓縮後的大小,在生產環境中加載的模塊都是通過gzip壓縮過的,能夠做爲真實訪問的大小依據。
安裝也很簡單:前端
// cli npm install --save-dev webpack-bundle-analyzer
注意生產環境(production)是表明線上真實的環境,因此analyzer要對生產環境的包進行分析的,因此我配置了一下本地打包生產環境的構建配置,在package.json加入下面的配置:react
"scripts": { ... "local_production": "cross-env NODE_ENV=local_production npm run build" }
而後在webpack配置裏面判斷process.env.NODE_ENV === 'local_production'
,構建production環境的構建而且加入analyzer分析生產環境打包出來的狀況。webpack
// webpack.config.js const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; if(process.env.NODE_ENV === 'local_production') { webpack_config.plugins.push( new BundleAnalyzerPlugin( { analyzerMode: 'server', analyzerHost: '127.0.0.1', analyzerPort: 8889, reportFilename: 'report.html', defaultSizes: 'parsed', openAnalyzer: true, generateStatsFile: false, statsFilename: 'stats.json', statsOptions: null, logLevel: 'info' } ) ); }
這裏是個人項目用analyzer生成出來的包大小狀況(打包前)
git
主要看index.xxxx.js,它包含了全部的公共依賴,咱們要作的就是減小沒必要要的公共資源的體積,能夠減小大量沒必要要的代碼。github
從上面的能夠看出來antd.less佔了很大部分面積,由於我要在項目中自定義theme,可是官方的那套配置的形式來自定義theme只能修改變量,不能改組件,因此我先加載全部的antd.less再在後面接着加載一個theme.less用於修改主題變量和修改antd組件樣式。web
移除了antd以後index包小了三百多k,這還遠遠不夠,接着看下面的優化點npm
lodash也是須要優化按需加載的方式的,推薦這篇教程Webpack按需打包Lodash的幾種方式, 按照教程改進後,lodash 小了500多k。json
其實moment引進來的時候會帶有不少語言包的,咱們只用到了其中一箇中文的包,因此其餘語言包均可以去掉,網絡
plugins: [ new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/), ]
後來又發現項目中只用到了moment().format()這個方法,因爲moment.js只有一個大的moment.js模塊,沒有按模塊分開寫,沒法按需打包,那麼其實咱們能夠本身實現個簡易版的moment來替代moment.js,下面是我找到的實現簡易版moment代碼:
// 簡易版moment代替moment.js class Moment { private date:Date; constructor(arg = new Date().getTime()) { this.date = new Date(arg); } padStart(num) { num = String(num); if (num.length < 2) { return '0' + num; } else { return num; } } unix() { return Math.round(this.date.getTime() / 1000); } static unix(timestamp) { return new Moment(timestamp * 1000); } format(formatStr) { const date = this.date; const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); const week = date.getDay(); const hour = date.getHours(); const minute = date.getMinutes(); const second = date.getSeconds(); const weeks = ['一', '二', '三', '四', '五', '六', '日']; return formatStr.replace(/Y{2,4}|M{1,2}|D{1,2}|d{1,4}|h{1,2}|m{1,2}|s{1,2}/g, (match) => { switch (match) { case 'YY': return String(year).slice(-2); case 'YYY': case 'YYYY': return String(year); case 'M': return String(month); case 'MM': return this.padStart(month); case 'D': return String(day); case 'DD': return this.padStart(day); case 'd': return String(week); case 'dd': return weeks[week]; case 'ddd': return '周' + weeks[week]; case 'dddd': return '星期' + weeks[week]; case 'h': return String(hour); case 'hh': return this.padStart(hour); case 'm': return String(minute); case 'mm': return this.padStart(minute); case 's': return String(second); case 'ss': return this.padStart(second); default: return match; } }); } } export const moment = (arg) => { return new Moment(arg); };
這樣就直接能夠把moment.js 幹掉了,包體積又小了很多。
下面是優化後的analyzer生成出來的包大小狀況
包體從2.7M優化到了1.7M,gzip從297k減少到212k,訪問雖然只是快了一點點,但在低網速環境下訪問仍是看獲得區別的。
接下來說一個跟包大小無關又很重要的優化點,就是單頁應用的第一個入口html,正常狀況下入口html只是用來加載js包,等js加載完以後才渲染出相關界面出來,這個入口html自己沒有內容展現,但它是整個網站的第一個請求,取到這個入口html以後纔開始加載js,等到加載完js纔開始渲染界面,這段時間是佔網站總體加載時間最多的,以下圖:
第一個請求只要128ms,直到加載完公共js渲染出界面須要1s左右,這時候若是入口index沒內容的話那就是純粹的白屏時間了,因此咱們應該好好利用這個入口index.html,能夠作一個骨架屏或者loading動畫,能讓用戶在等白屏時間裏可以有個界面能看到,停留時間會更長一些,也能讓用戶覺得這個網站一下就刷出來看到東西的感受。
對於這個入口index的利用,我是加入了頂部導航欄進去的,讓用戶能夠第一眼看到導航欄知道有什麼導航項,並且也是能夠點進去的,而內容區對於不一樣的路徑訪問會有不一樣的界面,因此我就簡單的弄個loading便可。
至此,這一版優化減小了加載的時間,同時合理利用了入口index做爲loading頁,提升用戶體驗。
前端優化工做是一個長期且複雜的工做,有不少能夠考慮的地方,能夠根據網絡環境、框架、用戶羣體、業務狀況、代碼結構等多個方面合理地安排選擇優化方案,本文只是我對於現有公司官網的優化的一部分,在這裏分享給你們,若是以爲有用就點個贊吧👍