摘要:的英文含義是名單種技術的確都是把當做清單使用緩存清單清單打包資源路徑清單打包清單只不過是在不同的場景中使用特定的清單來完成某些功能所以,學好英文是多么重要,這樣才不會傻傻分不清到底是干啥的
在前端,說到manifest,其實是有歧義的,就我了解的情況來說,manifest可以指代下列含義:
html標簽的manifest屬性: 離線緩存(目前已被廢棄)
PWA: 將Web應用程序安裝到設備的主屏幕
webpack中webpack-manifest-plugin插件打包出來的manifest.json文件,用來生成一份資源清單,為后端渲染服務
webpack中DLL打包時,輸出的manifest.json文件,用來分析已經打包過的文件,優化打包速度和大小
下面我們來一一介紹下
html屬性Document
瀏覽器解析這段html標簽時,就會去訪問tc.mymanifest這個文件,這是一個緩存清單文件
tc.mymanifest
# v1 這是注釋 CACHE MANIFEST /theme.css /main.js NETWORK: * FALLBACK: /html5/ /404.html
CACHE MANIFEST指定需要緩存的文件,第一次下載完成以后,文件都不會再從網絡請求了,即使用戶不是離線狀態,除非tc.mymanifest更新了,緩存清單更新之后,才會再次下載。標記了manifest的html本身也被緩存
NETWORK指定非緩存文件,所有類似資源的請求都會繞過緩存,即使用戶處于離線狀態,也不會讀緩存
FALLBACK指定了一個后備頁面,當資源無法訪問時,瀏覽器會使用該頁面。
比如離線訪問/html5/目錄時,就會用本地的/404.html頁面
緩存清單可以是任意后綴名,不過必須指定content-type屬性為text/cache-manifest
那如何更新緩存?一般有以下幾種方式:
用戶清空瀏覽器緩存
manifest 文件被修改(即使注釋被修改)
由程序來更新應用緩存
需要特別注意:用戶第一次訪問該網頁,緩存文件之后,第二次進入該頁面,發現tc.mymanifest緩存清單更新了,于是會重新下載緩存文件,但是,第二次進入顯示的頁面仍然執行的是舊文件,下載的新文件,只會在第三次進入該頁面后執行!!!
如果希望用戶立即看到新內容,需要js監聽更新事件,重新加載頁面
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);
建議對tc.mymanifest緩存清單設置永不緩存
不過,manifest也有很多缺點,比如需要手動一個個填寫緩存的文件,更新文件之后需要二次刷新,如果更新的資源中有一個資源更新失敗了,將導致全部更新失敗,將用回上一版本的緩存
HTML5規范也廢棄了這個屬性,因此不建議使用
PWA為了實現PWA應用添加至桌面的功能,除了要求站點支持HTTPS之外,還需要準備 manifest.json文件去配置應用的圖標、名稱等信息
{ "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" } ] }
通過一系列配置,就可以把一個PWA像APP一樣,添加一個圖標到手機屏幕上,點擊圖標即可打開站點
基于webpack的react開發環境本文默認你已經了解最基本的webpack配置,如果完全不會,建議看下這篇文章
我們首先搭建一個最簡單的基于webpack的react開發環境
源代碼地址: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", // 根據browserslis填寫的瀏覽器,自動添加polyfill "corejs": 2, } ], "@babel/preset-react" // 編譯react ], "plugins": [] }
新建postcss.config.js
module.exports = { plugins: [ require("autoprefixer") // 根據browserslis填寫的瀏覽器,自動添加css前綴 ] }
新建.browserslistrc
last 10 versions ie >= 11 ios >= 9 android >= 6
新建webpack.dev.js(基本配置不再詳細介紹)
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" },
最后,運行npm run dev,應該可以看見效果
新建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"
運行npm run build,可以看見打包出來的dist目錄
html,js,css都多帶帶分離出來了
至此,一個基于webpack的react環境搭建完成
webpack-manifest-plugin通常情況下,我們打包出來的js,css都是帶上版本號的,通過HtmlWebpackPlugin可以自動幫我們在index.html里面加上帶版本號的js和css
learn dll
但是在某些情況,index.html模板由后端渲染,那么我們就需要一份打包清單,知道打包后的文件對應的真正路徑
安裝插件webpack-manifest-plugin
npm i webpack-manifest-plugin -D
修改webpack.prod.js
const ManifestPlugin = require("webpack-manifest-plugin"); module.exports = { // ... plugins: [ new ManifestPlugin() ] };
重新打包,可以看見dist目錄新生成了一個manifest.json
{ "main.css": "main.198b3634.css", "main.js": "main.d312f172.js", "index.html": "index.html" }
比如在SSR開發時,前端打包后,node后端就可以通過這個json數據,返回正確資源路徑的html模板
const buildPath = require("./dist/manifest.json"); res.send(`代碼分割ssr `);
我們之前的打包方式,有一個缺點,就是把業務代碼和庫代碼都統統打到了一個main.js里面。每次業務代碼改動后,main.js的hash值就變了,導致客戶端又要重新下載一遍main.js,但是里面的庫代碼其實是沒改變的!
通常情況下,react react-dom之類的庫,都是不經常改動的。我們希望多帶帶把這些庫代碼提取出來,生成一個vendor.js,這樣每次改動代碼,只是下載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" } } };
重新打包,發現新生成了一個vendor.js文件,公用的一些代碼就被打包進去了
重新修改src/Home.js,然后打包,你會發現vendor.js的hash沒有改變,這也是我們希望的
DLL打包上面的打包方式,隨著項目的復雜度上升后,打包速度會開始變慢。原因是,每次打包,webpack都要分析哪些是公用庫,然后把他打包到vendor.js里
我們可不可以在第一次構建vendor.js以后,下次打包,就直接跳過那些被打包到vendor.js里的代碼呢?這樣打包速度可以明顯提升
這就需要DllPlugin結合DllRefrencePlugin插件的運用
dll打包原理就是:
把指定的庫代碼打包到一個dll.js,同時生成一份對應的manifest.json文件
webpack打包時,讀取manifest.json,知道哪些代碼可以直接忽略,從而提高構建速度
我們新建一個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"] // 手動指定打包哪些庫 }, 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"), // 生成對應的manifest.json,給webpack打包用 name: "[name]", }), ], }
添加一條命令:
"build:dll": "webpack --config webpack.dll.js"
運行dll打包
npm run build:dll
發現生成一個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,分析哪些代碼跳過 }), new CleanWebpackPlugin(), new ManifestPlugin() ], optimization: { splitChunks: { chunks: "all" } } };
重新npm run build,發現dist目錄里,vendor.js沒有了
這是因為react,react-dom已經打包到dll.js里了,webpack讀取manifest.json之后,知道可以忽略這些代碼,于是就沒有再打包了
但這里還有個問題,打包后的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加進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,分析哪些代碼跳過 }), new CleanWebpackPlugin(), new ManifestPlugin() ], optimization: { splitChunks: { chunks: "all" } } };
重新npm run build,可以看見dll.js也被打包進dist目錄了,同時index.html也正確引用
小結learn dll
我們介紹了4種manifest相關的前端技術。manifest的英文含義是名單, 4種技術的確都是把manifest當做清單使用:
緩存清單
PWA清單
打包資源路徑清單
dll打包清單
只不過是在不同的場景中使用特定的清單來完成某些功能
所以,學好英文是多么重要,這樣才不會傻傻分不清manifest到底是干啥的!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104443.html
摘要:今天同事小英童鞋問了我一個問題小英童鞋認為的原型對象是,所以會繼承的屬性,調用相當于調用,但結果不是一個方法。構造函數創建對象實例函數有兩個不同的內部方法和。如果不通過關鍵字調用函數,則執行函數,從而直接執行代碼中的函數體。 今天同事小英童鞋問了我一個問題: function Foo(firstName, lastName){ this.firstName = firstNam...
摘要:選擇器相鄰兄弟選擇器作用于緊跟其后的兄弟節點。注意事項有共同的父級必須緊跟其后,中間隔個啥都不行。注意事項要有共同的父級點擊查看大氣的,作用的范圍廣,限制少選擇器后代選擇器注意事項只作用于第一層后代點擊查看只作用于第一層后代 +選擇器(相鄰兄弟選擇器) 作用于緊跟其后的兄弟節點。 注意事項: 1.有共同的父級 2.必須緊跟其后,中間隔個啥都不行。 3.只作用于緊跟其后的元素...
摘要:選擇器相鄰兄弟選擇器作用于緊跟其后的兄弟節點。注意事項有共同的父級必須緊跟其后,中間隔個啥都不行。注意事項要有共同的父級點擊查看大氣的,作用的范圍廣,限制少選擇器后代選擇器注意事項只作用于第一層后代點擊查看只作用于第一層后代 +選擇器(相鄰兄弟選擇器) 作用于緊跟其后的兄弟節點。 注意事項: 1.有共同的父級 2.必須緊跟其后,中間隔個啥都不行。 3.只作用于緊跟其后的元素...
摘要:損失代價的減小是一件好事只有在數據很龐大的時候在機器學習中,幾乎任何時候都是,我們才需要使用,,迭代這些術語,在這種情況下,一次性將數據輸入計算機是不可能的。 你肯定經歷過這樣的時刻,看著電腦屏幕抓著頭,困惑著:「為什么我會在代碼中使用這三個術語,它們有什么區別嗎?」因為它們看起來實在太相似了。為了理解這些術語有什么不同,你需要了解一些關于機器學習的術語,比如梯度下降,以幫助你理解。這里簡單...
閱讀 3455·2019-08-30 15:55
閱讀 2054·2019-08-30 15:44
閱讀 1460·2019-08-30 12:47
閱讀 746·2019-08-30 11:05
閱讀 1633·2019-08-30 10:54
閱讀 659·2019-08-29 16:07
閱讀 3572·2019-08-29 14:17
閱讀 2230·2019-08-23 18:31