作者:劉軼斌,騰訊應用開發 工程師
商業轉載請聯絡騰訊WeTest獲得授權,非商業轉載請註明出處。
原文連結:wetest.qq.com/lab/view/34…
WeTest 導讀
此文總結了筆者在Web靜態資源方面的一些優化經驗。
一、如何優化
使用者在訪問網頁時, 最直觀的感受就是頁面內容出來的速度,我們要做的優化工作, 也主要是為了這個目標。那麼為了提高頁面載入(或者渲染)速度呢?一般來說有三個方面:
1、程式碼邏輯:優秀的程式碼邏輯結構可以有效減少渲染頁面使用的記憶體和速度(比如虛擬DOM),此方面不在本文討論範圍內。
2、SSR伺服器渲染,也就是所謂的“直出”。將首屏所有內容在伺服器端渲染成html靜態程式碼後,直接輸出給瀏覽器,可以有效加快使用者訪問站點時首屏的載入時間。不過此方面也不在本文討論範圍內。
3、提升靜態檔案的載入速度,這是本文會討論的點,而這方面大致又可分為下面幾點:
— 加快靜態檔案下載速度
— 減少靜態檔案的檔案大小
— 減少靜態檔案請求數量,從而減少發起請求的次數(對於移動端頁面來說,請求的開銷比網速的開銷要大)
(一)程式碼壓縮
最常規的優化手段之一。
我們在平時開發的時候,JS指令碼檔案和CSS樣式檔案中的程式碼,都會依據一定的程式碼規範(比如javascript-standard-style)來提高專案的可維護性,以及團隊之間合作的效率。
但是在專案釋出現網後, 這些程式碼是給客戶端(瀏覽器)識別的,此時程式碼的命名規範、空格縮排都已沒有必要,我們可以使用工具將這些程式碼進行混淆和壓縮,減少靜態檔案的大小
這裡我們選擇使用 Webpack,具體會在後面介紹。
(二)檔案合併
在npm流行的今天,前端在進行專案開發的時候,往往會使用很多第三方程式碼庫,比如jQuery,axios,weixin-js-sdk,lodash,bootstrap等等,每個庫都有屬於自己的指令碼或者樣式檔案。
按照最老的方式的話,我們會用<script>
標籤或者<style>
標籤分別引入這些庫檔案,導致在開啟一個頁面的時候會發起幾十個請求,這對於移動端來說是不可接受的。
在減少檔案請求數量方面大致有以下三方面:
1、合併js指令碼檔案
2、合併css樣式檔案
3、合併css引用的圖片,使用sprite雪碧圖。
對於 雪碧圖 ,我們可以把頁面上用到的多個細碎的小圖片合併成一個大圖片,把N個圖片請求合併成了一個。然後在css樣式中指定圖片偏移,來實現顯示不同的圖片,如下圖:
這裡我們繼續選擇使用Webpack,具體會在後面介紹。
(三)gzip
我們的檔案在壓縮合並之後,檔案大小和檔案數量都有了客觀的減少。但是一旦站點業務邏輯多了,或者引入的第三方庫多了之後,對於移動端來說,檔案大小還是不太樂觀。
這個時候就是gzip壓縮登場的時候啦~我們在webpack的配置中增加gzip壓縮配置:
上面程式碼會對檔案大小大於10240,並且壓縮率好於0.8的js、css檔案進行gzip壓縮,執行打包程式碼後生成結果檔案如下:
我們可以看到除了原有的js和css檔案外,我們還得到了壓縮後的gz檔案。
把所有這些檔案一起部署到伺服器上。(當然也可以直接nginx或其他web server配置gzip壓縮)
我們可以看到vendor.[hash].js檔案的大小顯著減少,從318kb減少到了不到100kb。
(四)CDN和快取
為什麼使用CDN?
CDN 是一個全球(或者只有國內,具體看供應商)分散式網路,它把網站內容更快地傳遞給服務範圍內的一個具體位置,而往往這個具體的位置離實際的內容伺服器距離很遠。舉個極端點的例子,你的網站主機在愛爾蘭(海南),而你的使用者則在澳大利亞(漠河)訪問。這時當你的使用者訪問你的網站的時候,延遲會很大,把你的(靜態)資料用 CDN 放到澳大利亞(漠河)則會很大程度上提高使用者訪問網站的體驗。
如果沒有CDN服務,我們可以新增Expires頭,減少DNS查詢,配置ETag,使AjaX可快取。
(五)安全方面: CSP
web前端對於xss安全漏洞一定不陌生。我們知道Javascript語句甚至是css表示式都可能導致xss攻擊,現在很多前端會使用CSP策略來進行指令碼源的限制防禦。
而我們由於使用的cdn域名和業務域名不一樣:
cdn域名:cdn.xxx.qq.com
業務域名:xxx.qq.com
我們可以:
- 在index.html靜態入口檔案的meta http-equiv頭中做配置;
伺服器端直接返回相應的HTTP response header頭資訊;
例如:
這裡除了指定了cdn的域名源,告訴瀏覽器從這個域名載入的js檔案都是可信的。同時因為我們使用的webpack打包壓縮程式碼後的一些特性,我們還需要加上'unsafe-inline'標識。
使用CSP策略我們可以指定瀏覽器安全解析script、css、fonts、media等資源的源與方式。
參考資料有:
Content Security Policy Reference
二、webpack2.0
使用webpack2最重要的地方就是使用它tree-shaking的特性。這個特性對於ES6的module管理有著非常優美的優化,大概能減少30%左右的包體積。
ES module和CommonJS的require模組管理不同,前者是基於靜態的,而後者是動態的。
CJS:
允許動態同步 require()
匯出僅在模組執行後才知道
匯出可以在模組初始化後新增,替換和刪除
ES module:
只允許靜態同步 import
在模組執行之前,匯入和匯出已經關聯
匯入和匯出是不可變的
現在我們來看一下如何使用webpack:
程式碼壓縮
我們自己寫的程式碼因為在開發時需要遵循一定的程式碼規範,所以會有很多多餘的換行和空格字元,甚至是便於閱讀的長變數名,這些其實對於機器(瀏覽器)來說,都不是必要的。所以我們可以把這些都幹掉。比如我們寫的程式碼可能是這樣的:
接著我們就使用Webpack來進行壓縮。首先,需要在工程根目錄的package.json(相信使用過npm包管理的前端同學一定不陌生)檔案中新增webpack的依賴配置:
各個工程應該按需引入需要的loader和webpack-plugin庫。有一點需要注意的是:webpack本身是沒有對各個型別的檔案進行分析處理的能力的,這個時候我們需要使用各種第三方庫的loader,比如css-loader等(當然我們也可以自己編寫loader)。同時webpack也有強大的第三方Plugin外掛供我們對檔案進行進一步處理。
接下來我們就可以在scripts中指向的指令碼檔案裡編寫webpack對應的構建程式碼了。
例如在webpackConfig配置中的plugins屬性陣列中,我們可以新增以下配置:
而最終生成的檔案結構如下:
我們可以看到所有樣式程式碼被壓縮後抽離到了一個app.[hash].css檔案中,所有js邏輯程式碼按照業務邏輯和第三方庫被抽離到了app.[hash].js和vendor.[hash].js檔案中。
被打包檔案的內容也已經被webpack壓縮混淆,減少了載入檔案的Content Size。
關於其他的webpack用法配置,可以查詢官方文件和中文文件,這裡就不一一詳細說明了
目前webpack3 和webpack4使用了新的方式打包程式碼,可以進一步提升js在瀏覽器中的執行效率。
三、題外話
跨域方面: CORS
我們知道由於現代瀏覽器安全策略的不斷完善,對跨域請求的限制也是各種各樣。
當我們儲存在靜態資原始檔中的script對其他域名發起請求時就會遇到跨域問題,如果沒有做任何措施,請求會被瀏覽器攔截。
當前主流的跨域解決方案主要是JSONP和CORS
由表可見,隨著前端不斷髮展,CORS跨域是大趨勢。
CORS需要被請求端根據請求者的host,與白名單比對後返回正確的HTTP response header頭資訊。
詳情內容建議閱讀MDN的官方文件
四、優化效果的驗證
為了能夠對前端優化效果有一個系統的驗證,憑藉肉眼來感受頁面響應速度肯定是遠遠不夠的,我們可以通過一些針對伺服器效能測試的產品來驗證頁面的響應時間,這裡推薦一個“壓測大師”。可以通過配置訪問過程中的最大人數,獲取訪問後的效能效果,如圖:
騰訊WeTest壓測大師對包含Web,H5等頁面準備了針對性的方案,解決了多數壓測人員Web頁面壓測的問題。
壓測大師服務了包括王者榮耀、龍之谷手遊、軒轅傳奇手遊、火影忍者等多款高星級手遊,也包括QQ、NOW直播等明星產品,通過基於真實業務場景和使用者行為進行壓力測試,幫助開發者發現伺服器端的效能瓶頸,進行鍼對性的效能調優,降低伺服器採購和維護成本。
為了讓外部更多產品能夠享受到簡單易用的壓測產品,騰訊WeTest決定將這份伺服器測試能力產品化,以產品”壓測大師“的形式,正式對外開放。目前更有低至四折的時效資源包優惠,歡迎大家使用!
點選連結:wetest.qq.com/gaps/ 即可使用。
如果對使用當中有任何疑問,歡迎聯絡騰訊WeTest企業QQ:800024531