新聞中心
背景
隨著互聯(lián)網(wǎng)開發(fā)和迭代速度越來越快,網(wǎng)站也變得越來越龐大,存在大量靜態(tài)資源,我們原有管理靜態(tài)資源的方式變得越來越不適用,就如同封面圖一樣,靜態(tài)資源之間的關(guān)系錯綜復(fù)雜,給工程師帶來了很多麻煩:

成都創(chuàng)新互聯(lián)專注于企業(yè)營銷型網(wǎng)站建設(shè)、網(wǎng)站重做改版、從江網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5開發(fā)、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價格優(yōu)惠性價比高,為從江等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
- 人工管理依賴的噩夢,工程師需要頻繁管理和維護(hù)每個頁面需要的 JS & CSS 文件,包括靜態(tài)資源之間的依賴關(guān)系以及加載順序等。
- 性能優(yōu)化成本高且不可持續(xù)性,為了提高網(wǎng)站性能,工程師總是在忙于優(yōu)化頁面靜態(tài)資源的加載,包括動態(tài)加載靜態(tài)資源、按需加載靜態(tài)資源和修改靜態(tài)資源合并策略等,但是過了一段時間性能又降下來了,又需要周而復(fù)始的重復(fù)。
- 靜態(tài)資源差異化的挑戰(zhàn),PC和無線的適配,不同的網(wǎng)絡(luò)和終端需要適配相應(yīng)的靜態(tài)資源;當(dāng)網(wǎng)站需要支持國際化的時候,需要對不同的國家進(jìn)行差異化處理,返回不同的靜態(tài)資源,這些需求對原有的靜態(tài)資源管理方式提出巨大挑戰(zhàn)。
- 缺少快速迭代和試驗(yàn)新功能的有效支持,從開發(fā)到上線流程繁瑣,導(dǎo)致項(xiàng)目迭代周期長
每天工程師都會提交大量的 new feature/bug fixes,每次項(xiàng)目發(fā)布和迭代都面臨著以上的問題,是否可以有一套系統(tǒng)幫助我們管理/調(diào)度靜態(tài)資源來減少人工管理靜態(tài)資源成本和風(fēng)險,來達(dá)到更快、更可靠、低成本的自動化項(xiàng)目交付。在實(shí)際項(xiàng)目開發(fā)中,我們進(jìn)行了大量探索和試驗(yàn),實(shí)現(xiàn)了一套 “靜態(tài)資源管理系統(tǒng)”,對靜態(tài)資源進(jìn)行全流程的管理和調(diào)度:
- 幫助工程師管理靜態(tài)資源間的依賴以及資源的加載
- 管理靜態(tài)資源版本更新與緩存,自動處理CDN
- 自動生成最優(yōu)的靜態(tài)資源合并策略,實(shí)現(xiàn)網(wǎng)站自適應(yīng)優(yōu)化
- 實(shí)現(xiàn)靜態(tài)資源的分級發(fā)布,快速迭代,輕松回滾
- 根據(jù)國際化和終端的差異,送達(dá)不同的資源給不同的用戶
下面本文將會介紹我們是如何通過靜態(tài)資源系統(tǒng)來高效管理靜態(tài)資源的。
架構(gòu)
靜態(tài)資源管理系統(tǒng)主要包含Compile、Sourcemap、Backend-Framework、Frontend-Loader幾個核心模塊:
- Compile,對靜態(tài)資源進(jìn)行編譯處理,包括對靜態(tài)資源進(jìn)行預(yù)處理,url 處理(添加md5戳、添加CDN前綴),優(yōu)化(壓縮、合并),生成 Sourcemap 等
- Sourcemap,在 compile 階段系統(tǒng)會掃描靜態(tài)資源,建立一張靜態(tài)資源關(guān)系表,記錄每個靜態(tài)資源的部署路徑以及依賴關(guān)系等信息
- Backend-Framework,后端運(yùn)行時根據(jù)組件使用情況來調(diào)度靜態(tài)資源,為前端返回頁面渲染需要的資源。
- Frontend-Loader,前端運(yùn)行時根據(jù)用戶的交互行為動態(tài)請求靜態(tài)資源。
靜態(tài)資源管理系統(tǒng)通過自動化工具對靜態(tài)資源進(jìn)行預(yù)處理并產(chǎn)出 Sourcemap,SourceMap 中記錄著靜態(tài)資源的調(diào)度信息,這樣框架在運(yùn)行時會根據(jù) SourceMap 中提供的調(diào)度信息自動為用戶進(jìn)行靜態(tài)資源調(diào)度,不僅可以做到送達(dá)不同資源給不同用戶,還可以自適應(yīng)優(yōu)化靜態(tài)資源合并和加載。
自動管理靜態(tài)資源依賴
靜態(tài)資源管理系統(tǒng)為工程師提供了聲明依賴關(guān)系的語法和規(guī)則,在 compile 階段系統(tǒng)會掃描靜態(tài)資源,建立一張靜態(tài)資源關(guān)系表,記錄每個靜態(tài)資源的部署路徑以及依賴關(guān)系等信息。
在html中聲明依賴
在項(xiàng)目的 index.html 里使用注釋聲明依賴關(guān)系:
在 SourceMap 中則可看到:
- {
- "res" : {
- "demo.css" : {
- "uri" : "/static/css/demo_7defa41.css",
- "type" : "css"
- },
- "demo.js" : {
- "uri" : "/static/js/demo_33c5143.js",
- "type" : "js",
- "deps" : [ "demo.css" ]
- },
- "index.html" : {
- "uri" : "/index.html",
- "type" : "html",
- "deps" : [ "demo.js", "demo.css" ]
- }
- },
- "pkg" : {}
- }
在js中聲明依賴
支持識別 js 文件中的 require 函數(shù),或者 注釋中的 @require 字段 標(biāo)記的依賴關(guān)系,這些分析處理對 html 的 script 標(biāo)簽內(nèi)容 同樣有效。
- //demo.js
- /**
- * @require demo.css
- * @require list.js
- */
- var $ = require('jquery');
在SourceMap中則可看到:
- {
- "res" : {
- ...
- "demo.js" : {
- "uri" : "/static/js/demo_33c5143.js",
- "type" : "js",
- "deps" : [ "demo.css", "list.js", "jquery" ]
- },
- ...
- },
- "pkg" : {}
- }
在css中聲明依賴
支持識別 css 文件 注釋中的 @require 字段 標(biāo)記的依賴關(guān)系,這些分析處理對 html 的 style 標(biāo)簽內(nèi)容 同樣有效。
- //demo.js
- /**
- * @require demo.css
- * @require list.js
- */
- var $ = require('jquery');
在SourceMap中則可看到:
- {
- "res" : {
- ...
- "demo.js" : {
- "uri" : "/static/js/demo_33c5143.js",
- "type" : "js",
- "deps" : [ "demo.css", "list.js", "jquery" ]
- },
- ...
- },
- "pkg" : {}
- }
#p#
按需加載靜態(tài)資源
在靜態(tài)資源管理系統(tǒng)接管了項(xiàng)目中的靜態(tài)資源后,可以知道靜態(tài)資源的運(yùn)行情況以及依賴關(guān)系,然后可以做到自動為頁面按需加載靜態(tài)資源,下面通過一個例子來詳細(xì)講解:
sidebar.tpl 中的內(nèi)容如下,
對項(xiàng)目編譯后,自動化工具會分析依賴關(guān)系,并生成 sourcemap,如下
- "common:widget/sidebar/sidebar.tpl": {
- "uri": "common/widget/sidebsr/sidebar.tpl",
- "type": "tpl",
- "extras": {
- "async": [
- "common:ui/dialog/dialog.async.js"
- ]
- },
- "deps": [
- "common:ui/dialog/dialog.js",
- "common:ui/dialog/dialog.css"
- ]
- }
在 sidebar 模塊被調(diào)用后,靜態(tài)資源管理系統(tǒng)通過查詢 sourcemap 可以得知,當(dāng)前 sidebar 模塊同步依賴 sidebar.js、sidebar.css,異步依賴 sdebar.async.js,在要輸出的 html 前面,生成靜態(tài)資源外鏈,我們得到最終的 html
如上可見,后端模塊化框架將同步模塊的 script url 統(tǒng)一生成到頁面底部,將 css url 統(tǒng)一生成在 head 中,對于異步模塊(require.async)注冊 resourceMap 代碼,框架會通過 {script} 標(biāo)簽收集到頁面所有 script,統(tǒng)一管理并按順序輸出 script 到相應(yīng)位置。
當(dāng)我們想對模塊進(jìn)行打包,只需要使用一個 pack 配置項(xiàng),對網(wǎng)站的靜態(tài)資源進(jìn)行打包,這樣在 SourceMap 中,所有被打包的資源會有一個 pkg 屬性指向該表中的資源,而這個資源,正是我們配置的打包策略。這樣靜態(tài)資源系統(tǒng)可以根據(jù)對應(yīng)信息找到某個資源最終被合并后的 package 的 url,最后把這個 url 返回給頁面。
自動合并靜態(tài)資源
靜態(tài)資源管理系統(tǒng)可以根據(jù)產(chǎn)品線上靜態(tài)資源使用的數(shù)據(jù),自動完成靜態(tài)資源合并工作,對工程師完全透明,解決手工維護(hù)的未及時排除廢棄資源、不可持續(xù)、成本大等問題。
詳情請見 靜態(tài)資源自動合并;
靜態(tài)資源版本更新與緩存
靜態(tài)資源管理系統(tǒng)采用基于文件內(nèi)容的 hash 值來控制靜態(tài)資源的版本更新,如下所示:
其中”_82244e91 ”這串字符是根據(jù) a.js 的文件內(nèi)容進(jìn)行 hash 運(yùn)算得到的,只有文件內(nèi)容發(fā)生變化了才會有更改。這樣做的好處有:
- 線上的 a.js 不是同名文件覆蓋,而是文件名 +hash 的冗余,所以可以先上線靜態(tài)資源,再上線 html 頁面,不存在間隙問題;
- 遇到問題回滾版本的時候,無需回滾 a.js,只須回滾頁面即可;
- 由于靜態(tài)資源版本號是文件內(nèi)容的 hash,因此所有靜態(tài)資源可以開啟永久強(qiáng)緩存,只有更新了內(nèi)容的文件才會緩存失效,緩存利用率大增;
- 修改靜態(tài)資源后會在線上產(chǎn)生新的文件,一個文件對應(yīng)一個版本,因此不會受到構(gòu)造 CDN 緩存形式的攻擊
靜態(tài)資源管理系統(tǒng)會在 compile 階段識別文件中的定位標(biāo)記(url),計(jì)算對應(yīng)文件的 hash,并自動替換為 '文件名 + hash',無需工程師手動修改。
靜態(tài)資源分級控制
靜態(tài)資源管理系統(tǒng)可以對靜態(tài)資源做進(jìn)一步控制(Controlling Access to Features)以達(dá)到分級發(fā)布的效果,主要包括以下兩塊核心功能,
- feature flags, 用來控制 feature 對應(yīng)的靜態(tài)資源是否加載
- feature flippers, 可以靈活控制 feature,不僅僅是 on 或 off, 可以做到類似'3%用戶可以訪問此功能'、'對內(nèi)部所有員工開放' 類似的效果
通過以上的控制我們可以輕松做到發(fā)布一個新功能,讓這個功能只對部分用戶可訪問,當(dāng)功能完善后對所有用戶開放,如果功能出現(xiàn)問題直接一鍵回滾即可。
在項(xiàng)目中的類似代碼如下:
- {if $config.some eq 'Fred'}
- do something new and amazing here.
- {elseif $config.some eq 'Wilma'}
- do the current boring stuff.
- {else}
- whatever you are.
靜態(tài)資源管理系統(tǒng)會根據(jù)配置在運(yùn)行時對 $config.some 進(jìn)行干預(yù).實(shí)現(xiàn)對靜態(tài)資源的訪問權(quán)控制,通過運(yùn)行時的配置(feature flag)來控制靜態(tài)資源,還可以支持“主干開發(fā)”的方式,來達(dá)到更快的迭代速度。
我們還可以實(shí)現(xiàn)國際化的需求,原理同分級發(fā)布,在運(yùn)行時的做一些更細(xì)致的差異化處理
- {if $lang == 'zh-CN'}
- zh-CN
- {/if}
總結(jié)
靜態(tài)資源管理系統(tǒng)的核心是對靜態(tài)資源進(jìn)行調(diào)度,可以很靈活的適應(yīng)各種性能優(yōu)化和差異化處理的場景,來達(dá)到更快、更可靠、低成本的自動化項(xiàng)目交付。但是同時這個系統(tǒng)十分復(fù)雜,承載著各種職責(zé),這個系統(tǒng)本身會成為整個網(wǎng)站的關(guān)鍵節(jié)點(diǎn)和瓶頸。
作者:walter (http://weibo.com/u/1916384703) - F.I.S
網(wǎng)頁標(biāo)題:如何高效地管理網(wǎng)站靜態(tài)資源
文章起源:http://fisionsoft.com.cn/article/dhgjpcg.html


咨詢
建站咨詢
