摘要:的英文含義是名單種技術(shù)的確都是把當(dāng)做清單使用緩存清單清單打包資源路徑清單打包清單只不過(guò)是在不同的場(chǎng)景中使用特定的清單來(lái)完成某些功能所以,學(xué)好英文是多么重要,這樣才不會(huì)傻傻分不清到底是干啥的
在前端,說(shuō)到manifest,其實(shí)是有歧義的,就我了解的情況來(lái)說(shuō),manifest可以指代下列含義:
html標(biāo)簽的manifest屬性: 離線緩存(目前已被廢棄)
PWA: 將Web應(yīng)用程序安裝到設(shè)備的主屏幕
webpack中webpack-manifest-plugin插件打包出來(lái)的manifest.json文件,用來(lái)生成一份資源清單,為后端渲染服務(wù)
webpack中DLL打包時(shí),輸出的manifest.json文件,用來(lái)分析已經(jīng)打包過(guò)的文件,優(yōu)化打包速度和大小
下面我們來(lái)一一介紹下
html屬性Document
瀏覽器解析這段html標(biāo)簽時(shí),就會(huì)去訪問(wèn)tc.mymanifest這個(gè)文件,這是一個(gè)緩存清單文件
tc.mymanifest
# v1 這是注釋 CACHE MANIFEST /theme.css /main.js NETWORK: * FALLBACK: /html5/ /404.html
CACHE MANIFEST指定需要緩存的文件,第一次下載完成以后,文件都不會(huì)再?gòu)木W(wǎng)絡(luò)請(qǐng)求了,即使用戶不是離線狀態(tài),除非tc.mymanifest更新了,緩存清單更新之后,才會(huì)再次下載。標(biāo)記了manifest的html本身也被緩存
NETWORK指定非緩存文件,所有類似資源的請(qǐng)求都會(huì)繞過(guò)緩存,即使用戶處于離線狀態(tài),也不會(huì)讀緩存
FALLBACK指定了一個(gè)后備頁(yè)面,當(dāng)資源無(wú)法訪問(wèn)時(shí),瀏覽器會(huì)使用該頁(yè)面。
比如離線訪問(wèn)/html5/目錄時(shí),就會(huì)用本地的/404.html頁(yè)面
緩存清單可以是任意后綴名,不過(guò)必須指定content-type屬性為text/cache-manifest
那如何更新緩存?一般有以下幾種方式:
用戶清空瀏覽器緩存
manifest 文件被修改(即使注釋被修改)
由程序來(lái)更新應(yīng)用緩存
需要特別注意:用戶第一次訪問(wèn)該網(wǎng)頁(yè),緩存文件之后,第二次進(jìn)入該頁(yè)面,發(fā)現(xiàn)tc.mymanifest緩存清單更新了,于是會(huì)重新下載緩存文件,但是,第二次進(jìn)入顯示的頁(yè)面仍然執(zhí)行的是舊文件,下載的新文件,只會(huì)在第三次進(jìn)入該頁(yè)面后執(zhí)行!??!
如果希望用戶立即看到新內(nèi)容,需要js監(jiān)聽(tīng)更新事件,重新加載頁(yè)面
window.addEventListener("load", function (e) { window.applicationCache.addEventListener("updateready", function (e) { if (window.applicationCache.status == window.applicationCache.UPDATEREADY) { // 更新緩存 // 重新加載 window.applicationCache.swapCache(); window.location.reload(); } else { } }, false); }, false);
建議對(duì)tc.mymanifest緩存清單設(shè)置永不緩存
不過(guò),manifest也有很多缺點(diǎn),比如需要手動(dòng)一個(gè)個(gè)填寫(xiě)緩存的文件,更新文件之后需要二次刷新,如果更新的資源中有一個(gè)資源更新失敗了,將導(dǎo)致全部更新失敗,將用回上一版本的緩存
HTML5規(guī)范也廢棄了這個(gè)屬性,因此不建議使用
PWA為了實(shí)現(xiàn)PWA應(yīng)用添加至桌面的功能,除了要求站點(diǎn)支持HTTPS之外,還需要準(zhǔn)備 manifest.json文件去配置應(yīng)用的圖標(biāo)、名稱等信息
{ "name" : "Minimal PWA" , "short_name" : "PWA Demo" , "display" : "standalone" , "start_url" : "/" , "theme_color" : "#313131" , "background_color" : "#313131" , "icons" : [ { "src": "images/touch/homescreen48.png", "sizes": "48x48", "type": "image/png" } ] }
通過(guò)一系列配置,就可以把一個(gè)PWA像APP一樣,添加一個(gè)圖標(biāo)到手機(jī)屏幕上,點(diǎn)擊圖標(biāo)即可打開(kāi)站點(diǎn)
基于webpack的react開(kāi)發(fā)環(huán)境本文默認(rèn)你已經(jīng)了解最基本的webpack配置,如果完全不會(huì),建議看下這篇文章
我們首先搭建一個(gè)最簡(jiǎn)單的基于webpack的react開(kāi)發(fā)環(huán)境
源代碼地址:https://github.com/deepred5/l...
mkdir learn-dll cd learn-dll
安裝依賴
npm init -y npm install @babel/polyfill react react-dom --save
npm install webpack webpack-cli webpack-dev-server @babel/core @babel/preset-env @babel/preset-react add-asset-html-webpack-plugin autoprefixer babel-loader clean-webpack-plugin css-loader html-webpack-plugin mini-css-extract-plugin node-sass postcss-loader sass-loader style-loader --save-dev
新建.bablerc
{ "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage", // 根據(jù)browserslis填寫(xiě)的瀏覽器,自動(dòng)添加polyfill "corejs": 2, } ], "@babel/preset-react" // 編譯react ], "plugins": [] }
新建postcss.config.js
module.exports = { plugins: [ require("autoprefixer") // 根據(jù)browserslis填寫(xiě)的瀏覽器,自動(dòng)添加css前綴 ] }
新建.browserslistrc
last 10 versions ie >= 11 ios >= 9 android >= 6
新建webpack.dev.js(基本配置不再詳細(xì)介紹)
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { mode: "development", devtool: "cheap-module-eval-source-map", entry: { main: "./src/index.js" }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name].js", chunkFilename: "[name].chunk.js", }, devServer: { historyApiFallback: true, overlay: true, port: 9001, open: true, hot: true, }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, loader: "babel-loader" }, { test: /.css$/, use: ["style-loader", "css-loader", "postcss-loader" ], }, { test: /.scss$/, use: ["style-loader", { loader: "css-loader", options: { modules: false, importLoaders: 2 } }, "sass-loader", "postcss-loader" ], }, ] }, plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html" }), // index打包模板 ] }
新建src目錄,并新建src/index.html
learn dll
新建src/Home.js
import React from "react"; import "./Home.scss"; export default () =>home
新建src/Home.scss
.home { color: red; }
新建src/index.js
import React, { Component } from "react"; import ReactDom from "react-dom"; import Home from "./Home"; class Demo extends Component { render() { return () } } ReactDom.render( , document.getElementById("app"));
修改package.json
"scripts": { "dev": "webpack-dev-server --config webpack.dev.js" },
最后,運(yùn)行npm run dev,應(yīng)該可以看見(jiàn)效果
新建webpack.prod.js
const path = require("path"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { mode: "production", entry: { main: "./src/index.js" }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name].[contenthash:8].js", chunkFilename: "[name].[contenthash:8].chunk.js", }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, loader: "babel-loader" }, { test: /.css$/, use: [MiniCssExtractPlugin.loader, // 多帶帶提取css文件 "css-loader", "postcss-loader" ], }, { test: /.scss$/, use: [MiniCssExtractPlugin.loader, { loader: "css-loader", options: { modules: false, importLoaders: 2 } }, "sass-loader", "postcss-loader" ], }, ] }, plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html" }), new MiniCssExtractPlugin({ filename: "[name].[contenthash:8].css", chunkFilename: "[id].[contenthash:8].css", }), new CleanWebpackPlugin(), // 打包前先刪除之前的dist目錄 ] };
修改package.json,添加一句"build": "webpack --config webpack.prod.js"
運(yùn)行npm run build,可以看見(jiàn)打包出來(lái)的dist目錄
html,js,css都多帶帶分離出來(lái)了
至此,一個(gè)基于webpack的react環(huán)境搭建完成
webpack-manifest-plugin通常情況下,我們打包出來(lái)的js,css都是帶上版本號(hào)的,通過(guò)HtmlWebpackPlugin可以自動(dòng)幫我們?cè)?b>index.html里面加上帶版本號(hào)的js和css
learn dll
但是在某些情況,index.html模板由后端渲染,那么我們就需要一份打包清單,知道打包后的文件對(duì)應(yīng)的真正路徑
安裝插件webpack-manifest-plugin
npm i webpack-manifest-plugin -D
修改webpack.prod.js
const ManifestPlugin = require("webpack-manifest-plugin"); module.exports = { // ... plugins: [ new ManifestPlugin() ] };
重新打包,可以看見(jiàn)dist目錄新生成了一個(gè)manifest.json
{ "main.css": "main.198b3634.css", "main.js": "main.d312f172.js", "index.html": "index.html" }
比如在SSR開(kāi)發(fā)時(shí),前端打包后,node后端就可以通過(guò)這個(gè)json數(shù)據(jù),返回正確資源路徑的html模板
const buildPath = require("./dist/manifest.json"); res.send(`代碼分割ssr `);
我們之前的打包方式,有一個(gè)缺點(diǎn),就是把業(yè)務(wù)代碼和庫(kù)代碼都統(tǒng)統(tǒng)打到了一個(gè)main.js里面。每次業(yè)務(wù)代碼改動(dòng)后,main.js的hash值就變了,導(dǎo)致客戶端又要重新下載一遍main.js,但是里面的庫(kù)代碼其實(shí)是沒(méi)改變的!
通常情況下,react react-dom之類的庫(kù),都是不經(jīng)常改動(dòng)的。我們希望多帶帶把這些庫(kù)代碼提取出來(lái),生成一個(gè)vendor.js,這樣每次改動(dòng)代碼,只是下載main.js,vendor.js可以充分緩存(也就是所謂的代碼分割code splitting)
webpack4自帶代碼分割功能,只要配置:
optimization: { splitChunks: { chunks: "all" } }
webpack.prod.js
const path = require("path"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const ManifestPlugin = require("webpack-manifest-plugin"); module.exports = { mode: "production", entry: { main: "./src/index.js" }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name].[contenthash:8].js", chunkFilename: "[name].[contenthash:8].chunk.js", }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, loader: "babel-loader" }, { test: /.css$/, use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader" ], }, { test: /.scss$/, use: [MiniCssExtractPlugin.loader, { loader: "css-loader", options: { modules: false, importLoaders: 2 } }, "sass-loader", "postcss-loader" ], }, ] }, plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html" }), new MiniCssExtractPlugin({ filename: "[name].[contenthash:8].css", chunkFilename: "[id].[contenthash:8].css", }), new CleanWebpackPlugin(), new ManifestPlugin() ], optimization: { splitChunks: { chunks: "all" } } };
重新打包,發(fā)現(xiàn)新生成了一個(gè)vendor.js文件,公用的一些代碼就被打包進(jìn)去了
重新修改src/Home.js,然后打包,你會(huì)發(fā)現(xiàn)vendor.js的hash沒(méi)有改變,這也是我們希望的
DLL打包上面的打包方式,隨著項(xiàng)目的復(fù)雜度上升后,打包速度會(huì)開(kāi)始變慢。原因是,每次打包,webpack都要分析哪些是公用庫(kù),然后把他打包到vendor.js里
我們可不可以在第一次構(gòu)建vendor.js以后,下次打包,就直接跳過(guò)那些被打包到vendor.js里的代碼呢?這樣打包速度可以明顯提升
這就需要DllPlugin結(jié)合DllRefrencePlugin插件的運(yùn)用
dll打包原理就是:
把指定的庫(kù)代碼打包到一個(gè)dll.js,同時(shí)生成一份對(duì)應(yīng)的manifest.json文件
webpack打包時(shí),讀取manifest.json,知道哪些代碼可以直接忽略,從而提高構(gòu)建速度
我們新建一個(gè)webpack.dll.js
const path = require("path"); const webpack = require("webpack"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = { mode: "production", entry: { vendors: ["react", "react-dom"] // 手動(dòng)指定打包哪些庫(kù) }, output: { filename: "[name].[hash:8].dll.js", path: path.resolve(__dirname, "./dll"), library: "[name]" }, plugins: [ new CleanWebpackPlugin(), new webpack.DllPlugin({ path: path.join(__dirname, "./dll/[name].manifest.json"), // 生成對(duì)應(yīng)的manifest.json,給webpack打包用 name: "[name]", }), ], }
添加一條命令:
"build:dll": "webpack --config webpack.dll.js"
運(yùn)行dll打包
npm run build:dll
發(fā)現(xiàn)生成一個(gè)dll目錄
修改webpack.prod.js
const path = require("path"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const ManifestPlugin = require("webpack-manifest-plugin"); const webpack = require("webpack"); module.exports = { mode: "production", entry: { main: "./src/index.js" }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name].[contenthash:8].js", chunkFilename: "[name].[contenthash:8].chunk.js", }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, loader: "babel-loader" }, { test: /.css$/, use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader" ], }, { test: /.scss$/, use: [MiniCssExtractPlugin.loader, { loader: "css-loader", options: { modules: false, importLoaders: 2 } }, "sass-loader", "postcss-loader" ], }, ] }, plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html" }), new MiniCssExtractPlugin({ filename: "[name].[contenthash:8].css", chunkFilename: "[id].[contenthash:8].css", }), new webpack.DllReferencePlugin({ manifest: path.resolve(__dirname, "./dll/vendors.manifest.json") // 讀取dll打包后的manifest.json,分析哪些代碼跳過(guò) }), new CleanWebpackPlugin(), new ManifestPlugin() ], optimization: { splitChunks: { chunks: "all" } } };
重新npm run build,發(fā)現(xiàn)dist目錄里,vendor.js沒(méi)有了
這是因?yàn)?b>react,react-dom已經(jīng)打包到dll.js里了,webpack讀取manifest.json之后,知道可以忽略這些代碼,于是就沒(méi)有再打包了
但這里還有個(gè)問(wèn)題,打包后的index.html還需要添加dll.js文件,這就需要add-asset-html-webpack-plugin插件
npm i add-asset-html-webpack-plugin -D
修改webpack.prod.js
const path = require("path"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const ManifestPlugin = require("webpack-manifest-plugin"); const webpack = require("webpack"); const AddAssetHtmlPlugin = require("add-asset-html-webpack-plugin"); module.exports = { mode: "production", entry: { main: "./src/index.js" }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name].[contenthash:8].js", chunkFilename: "[name].[contenthash:8].chunk.js", }, module: { rules: [ { test: /.js$/, exclude: /node_modules/, loader: "babel-loader" }, { test: /.css$/, use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader" ], }, { test: /.scss$/, use: [MiniCssExtractPlugin.loader, { loader: "css-loader", options: { modules: false, importLoaders: 2 } }, "sass-loader", "postcss-loader" ], }, ] }, plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html" }), new AddAssetHtmlPlugin({ filepath: path.resolve(__dirname, "./dll/*.dll.js") }), // 把dll.js加進(jìn)index.html里,并且拷貝文件到dist目錄 new MiniCssExtractPlugin({ filename: "[name].[contenthash:8].css", chunkFilename: "[id].[contenthash:8].css", }), new webpack.DllReferencePlugin({ manifest: path.resolve(__dirname, "./dll/vendors.manifest.json") // 讀取dll打包后的manifest.json,分析哪些代碼跳過(guò) }), new CleanWebpackPlugin(), new ManifestPlugin() ], optimization: { splitChunks: { chunks: "all" } } };
重新npm run build,可以看見(jiàn)dll.js也被打包進(jìn)dist目錄了,同時(shí)index.html也正確引用
小結(jié)learn dll
我們介紹了4種manifest相關(guān)的前端技術(shù)。manifest的英文含義是名單, 4種技術(shù)的確都是把manifest當(dāng)做清單使用:
緩存清單
PWA清單
打包資源路徑清單
dll打包清單
只不過(guò)是在不同的場(chǎng)景中使用特定的清單來(lái)完成某些功能
所以,學(xué)好英文是多么重要,這樣才不會(huì)傻傻分不清manifest到底是干啥的!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104443.html
摘要:今天同事小英童鞋問(wèn)了我一個(gè)問(wèn)題小英童鞋認(rèn)為的原型對(duì)象是,所以會(huì)繼承的屬性,調(diào)用相當(dāng)于調(diào)用,但結(jié)果不是一個(gè)方法。構(gòu)造函數(shù)創(chuàng)建對(duì)象實(shí)例函數(shù)有兩個(gè)不同的內(nèi)部方法和。如果不通過(guò)關(guān)鍵字調(diào)用函數(shù),則執(zhí)行函數(shù),從而直接執(zhí)行代碼中的函數(shù)體。 今天同事小英童鞋問(wèn)了我一個(gè)問(wèn)題: function Foo(firstName, lastName){ this.firstName = firstNam...
摘要:選擇器相鄰兄弟選擇器作用于緊跟其后的兄弟節(jié)點(diǎn)。注意事項(xiàng)有共同的父級(jí)必須緊跟其后,中間隔個(gè)啥都不行。注意事項(xiàng)要有共同的父級(jí)點(diǎn)擊查看大氣的,作用的范圍廣,限制少選擇器后代選擇器注意事項(xiàng)只作用于第一層后代點(diǎn)擊查看只作用于第一層后代 +選擇器(相鄰兄弟選擇器) 作用于緊跟其后的兄弟節(jié)點(diǎn)。 注意事項(xiàng): 1.有共同的父級(jí) 2.必須緊跟其后,中間隔個(gè)啥都不行。 3.只作用于緊跟其后的元素...
摘要:選擇器相鄰兄弟選擇器作用于緊跟其后的兄弟節(jié)點(diǎn)。注意事項(xiàng)有共同的父級(jí)必須緊跟其后,中間隔個(gè)啥都不行。注意事項(xiàng)要有共同的父級(jí)點(diǎn)擊查看大氣的,作用的范圍廣,限制少選擇器后代選擇器注意事項(xiàng)只作用于第一層后代點(diǎn)擊查看只作用于第一層后代 +選擇器(相鄰兄弟選擇器) 作用于緊跟其后的兄弟節(jié)點(diǎn)。 注意事項(xiàng): 1.有共同的父級(jí) 2.必須緊跟其后,中間隔個(gè)啥都不行。 3.只作用于緊跟其后的元素...
摘要:損失代價(jià)的減小是一件好事只有在數(shù)據(jù)很龐大的時(shí)候在機(jī)器學(xué)習(xí)中,幾乎任何時(shí)候都是,我們才需要使用,,迭代這些術(shù)語(yǔ),在這種情況下,一次性將數(shù)據(jù)輸入計(jì)算機(jī)是不可能的。 你肯定經(jīng)歷過(guò)這樣的時(shí)刻,看著電腦屏幕抓著頭,困惑著:「為什么我會(huì)在代碼中使用這三個(gè)術(shù)語(yǔ),它們有什么區(qū)別嗎?」因?yàn)樗鼈兛雌饋?lái)實(shí)在太相似了。為了理解這些術(shù)語(yǔ)有什么不同,你需要了解一些關(guān)于機(jī)器學(xué)習(xí)的術(shù)語(yǔ),比如梯度下降,以幫助你理解。這里簡(jiǎn)單...
閱讀 3485·2019-08-30 15:55
閱讀 2071·2019-08-30 15:44
閱讀 1490·2019-08-30 12:47
閱讀 767·2019-08-30 11:05
閱讀 1651·2019-08-30 10:54
閱讀 681·2019-08-29 16:07
閱讀 3599·2019-08-29 14:17
閱讀 2253·2019-08-23 18:31