親,若是你還在爲你沒網打開不網頁而煩惱嗎?
親,你還在爲你web服務器複雜的配置項而蛋疼嗎?
不要998,manifest抱回家~
manifest自H5橫空出世以來給前端網頁的瀏覽帶來了翻天覆地的變化,之前咱們的網頁必須在有網的前提下打開(主要仍是打開HTML), 可是如今,咱們能夠offline 瀏覽。 能夠算是實現web app的一個特技。
manifest的兼容性 IE9+. 因爲是現代的技術,IE9如下的古老瀏覽器是不支持的。因此,manifest主要應用是針對現代瀏覽器或者手機端更多一些。javascript
瀏覽器檢測你是否使用manifest特技時,是檢測html標籤.css
<html lang="en" manifest="usable.manifest">
當解析你的HTML時,發現存在manifest文件時,則會進行以下的操做:
(from alloy team)
manifest文件能夠是任意後綴好比. usable.manifest||usable.mf等,可是他的MIMEtype必須設置正確.
記住,這個時候manifest會將HTML文件也一併保存,這須要注意。html
一個簡單的demo:前端
CACHE MANIFEST #version 1.3 /public/static/index.css /public/static/header.css NETWORK: * FALLBACK: /userInfo/ /404.html #額外須要添加的緩存文件 CACHE: images/logo1.png images/logo2.png
基本樣式就是上述java
第一行必須是指定頭即, "CACHE MANIFEST"(不能有其餘的). 表示哪些文件須要緩存。若是是相對路徑則是,在manifest文件所在的目錄下。並且,不能使通配符!!!(tm 你是還不是傻). 因此通常而言只能一個一個配置.nginx
CACHE MANIFEST #相對於manifest文件所在的目錄 ./index.css
註釋: 註釋使用#+"info"
能夠對緩存文件性質進行適當的說明。緩存後的文件,就會被帶上Expires的頭,表示能夠不通過服務器驗證直接使用本地文件。因此,返回status Code 爲 200.
另外,CACHE 定義的文件內容,和CACHE MANIFEST 是一個效果,只是跟在CACHE MANIFEST以後,就能夠省略書寫CACHE,你添加上也能夠。git
CACHE MANIFEST #version 1.3 CACHE: /favicon.ico
並且CACHE能夠放在文中的任意位置,不過通常都是放開頭,或者省略.github
CACHE MANIFEST # 緩存文件 index.html css/style.css NETWORK: * # 額外的須要緩存的文件 CACHE: images/logo1.png images/logo2.png images/logo3.png
這裏設置不使用緩存的文件,可使用通配符"*"等。
* 表示,除了CACHE MANIFEST定義的文件以外的文件都不能被緩存。
固然也能夠手動指定文件:web
NETWORK * http://www.example.com/index.html http://www.example.com/header.png http://www.example.com/blah/blah
這些瀏覽器都不能直接使用緩存,即,可能會要求你從新驗證,或者直接使用服務器文件。ajax
這個tag,可用可不用。 用來表示,指定文件沒法加載時,使用另外的文件代替。參數有兩部分構成,第一部分是指定資源(可能存在文件未加載),第二部分是替代資源
FALLBACK: /index.html /404.html /static/* /404.html /images/* /NotFound.jpg
當index.html沒法加載時,使用404.html代替. 這裏有個要求,兩個路徑必須使用相對路徑而且與清單文件同源。
這算是一個附加屬性吧。一般設置內容就只有:
SETTINGS: prefer-online
表示,在有網的狀況下,會先訪問服務器的文件,看有沒有更新,至關於設置了Cache-Control:max-age=0,must-revalidate; + ETag||Last-modified. 不過,比較stupid的是,只有FF(Opera 12)支持.
而在服務器端,須要對manifest文件的MIME設置正確。這裏以nginx爲例, 具體設置一下MIME type
type{ image/gif gif; image/jpeg jpeg jpg; application/x-javascript js; }
詳情能夠參考: manifest文件配置
這裏以gulp爲例。 能夠在npm裏面很容易找到gulp-manifest這個生成插件.
直接下載:
npm install gulp-manifest --save-dev
而後在gulpfile裏面配置:
gulp.task('manifest', function(){ gulp.src(['build/**'], { base: './' }) .pipe(manifest({ hash: true, preferOnline: true, network: ['*'], fallback:['/images/* /404.html'] filename: 'app.manifest', exclude: 'app.manifest' //不保存manifest,不過有沒有效果同樣 })) .pipe(gulp.dest('./')); });
接着就會在目錄下生成app.manifest文件,裏面就是一些基本的文件格式了。另外若是你想查看你電腦有多少網頁是manifest,能夠直接訪問 chrome://appcache-internals/.
manifest對於單頁應用可謂是如魚得水,可是,到了多頁應用的層面,他的bug真的是暴露無遺。
1.頁面保存的複雜度, 2.文件的及時更新, 3.緩存文件的設置, 4.死都會保存HTML, 5.文件下載出錯,則此次更新緩存失敗, 6.覆蓋全部緩存頭,除了Cache-Control:no-store 7.在Android 4.4的webview裏,關閉以後會丟失cache 8.IE10不能很好的支持FALLBACK部分.
因此,appCache的bug也是很是多的。
例如,長尾更新問題,當你的頁面保持在線的時候,是沒法檢測文件已經更新,除非你reload頁面,可是用戶並不知道你已經更新,因此這裏咱們須要引進js的提供的緩存檢測API.
這是前端可以摸到緩存最真實的API。咱們能夠經過這個API接口獲取到咱們不少想要的東西:
var appcache = window.applicationCache; console.log(appcache.status); //檢查當前緩存狀態 console.log(appcache.IDLE); //緩存狀態常量,下面解釋
屬性名 | explanation |
---|---|
status | 當前緩存狀態,爲Number類型. 爲0~5 |
UNCACHED(0) | 瀏覽器未緩存文件 |
IDLE(1) | 空閒狀態,瀏覽器已經所有緩存 |
CHECKING(2) | 頁面正在檢查當前離線緩存是否須要更新 |
DOWNLOADING(3) | 頁面正在下載須要更新的緩存文件 |
UPDATEREADY(4) | 頁面緩存更新完畢 |
OBSOLETE(5) | 緩存已通過期 |
window.applicationCache.update() //update方法調用時,頁面會主動與服務器通訊,檢查頁面當前的緩存是否爲最新的,如不是,則下載更新後的資源 window.applicationCache.swapCache() //updateready後,更新到最新的應用緩存
一般結合上述兩個方法和相應的屬性咱們能夠手動觸發文件的更新(前提是 manifest文件改動).
var appCache = window.applicationCache; appCache.update(); //檢查更新 if (appCache.status == window.applicationCache.UPDATEREADY) { //若是存在更新,而且已經下載ok,則替換瀏覽器緩存 appCache.swapCache(); }
可是,此時頁面並不能用上最新的文件,只是瀏覽器的緩存已經改變,網頁實際內容仍是原來的內容,還須要手動進行reload,才能進行更新文件
window.addEventListener('load', function(e) { window.applicationCache.addEventListener('updateready', function(e) { if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { if (confirm('文件有更新,手否從新加載文件')) { window.location.reload(); } } else { //若是,拒絕則不刷新網頁 } }, false); }, false);
相關事件有: checking,downloading,updateready,obsolete,cached,error,noupdate,progress.
對照上述的status就能夠很容易知道每一個事件對應的效果是神馬。 須要說的就是:
progress: 當瀏覽器在下載資源時,每下載成功一次,就會觸發一次 noupdate:當瀏覽器檢查更新以後發現沒有資源更新的時候觸發這個事件 error: 更新出錯時會觸發,好比文件沒法正常下載,manifest文件被刪除.
其實,使用manifest的時候,無外乎就是3種經常使用狀態
第一次訪問頁面時
再次訪問頁面時,沒有更新
再次訪問頁面時,有更新
每次,觸發的事件順序爲:
行爲 | 事件順序 |
---|---|
第一次訪問頁面 | checking->downloading->progress(屢次)->cached |
再次訪問時,沒有更新 | checking->noupdate |
再次訪問時,有更新 | checking->downloading->progress(屢次)->updateready |
上面看不懂不要緊,咱們能夠看看更直觀的Console的內容。
第一次訪問頁面時
checking->downloading->progress(屢次)->cache
2\. 再次訪問頁面時,沒有更新
checking->noupdate
3\. 再次訪問頁面時,有更新
checking->downloading->progress(屢次)->updateready
其實,manifest就是爲了離線應用而生的,可是因爲設計之初,沒有很好的規範,致使如今manifest的bug,真的超級多。
看到whatwg上面說的一句話,真的更加蛋疼.
This feature is in the process of being removed from the Web platform. (This is a long process that takes many years.) Using any of the offline Web application features at this time is highly discouraged. Use service workers instead.
意思就是讓你不要用manifest,應該他早晚要被fire的,可是,這一天還有不少年,不少年。 另一個替代方案就是使用SS,可是兼容性,真的極其差。幾乎如今的瀏覽器都沒有實現(除了佈道師FF實現了部分). 如今咱們真的很尷尬,不過,目前的狀況而言,in my opinion, 是十分推薦使用的(也沒有其餘的辦法了). 那該怎麼作,才能將manifest的Bug減到最低呢?推薦的作法是將邏輯頁面和用戶數據給分離開。 邏輯頁面使用app cache,而用戶數據能夠保存在web Storage || indexDB 等瀏覽器數據庫裏,動態更新data時,使用web Socket,ajax,SSE等技術.