摘要:原文發布與抹橋的博客翻譯向指南上前置定義代碼包代碼塊安裝代碼分割代碼分割是中最引人注目的功能之一。回調函數一個回調函數會被執行一次當所有依賴都被加載以后。對象的實現作為一個參數傳遞給這個回調函數。
前置定義原文發布與 抹橋的博客 -【翻譯向】webpack2 指南(上)
Bundle 代碼包
Chunk 代碼塊
npm install webpack --save-dev
代碼分割代碼分割是 webpack 中最引人注目的功能之一。它允許你把代碼分割成各種可以根據需求載入的代碼包,就像一個用戶瀏覽器去匹配路由一樣,或者一個用戶發出的事件。這允許你小的模塊,允許你控制資源的載入優先級,如果使用得當的話,可以大大影響(降低)你應用的加載時間。
緩存和并行加載的資源分割 第三方代碼分割一個典型的應用會依賴很多第三方的框架和庫文件。不像應用代碼本身,這些第三方代碼的變更非常頻繁。
如果我們保持這些庫在它本身的代碼包中,從應用代碼本身分離出來,那么我們就可以使用瀏覽器的緩存策略去在一個長時間內把這些代碼緩存到最終用戶的機器上。
為了達到這個效果,第三方代碼的 verndor 包的 hash 部分必須保持不變,不管應用代碼如何變化。學習 如何通過 CommonsChunkPlugin 來分割 verndor/libray 代碼。
CSS 分割你可能也想把樣式文件分割成為一個多帶帶的包,從應用邏輯總獨立出來。這可以增強樣式文件的可緩存性,并且允許瀏覽器在加載應用代碼時并行加載你的樣式文件,因此也可以避免 FOUC (一個無樣式內容的閃屏)。
學習 如何去分割 CSS 通過使用 ExtractTextWebpackPlugin.
雖然前面的資源分割需要用戶在配置文件中預先指定分割點,但是也可以在應用代碼中創建動態的分割點。
這個功能在有很多細微顆粒代碼塊時會很有用,舉個例子,每一個應用的路由或者按照用戶的預測行為。這可以使用戶按需加載需要的資源。
通過 require.ensure() 來分割代碼require.ensure 是一個 CommonJS 風格的方式去異步加載資源。通過添加 require.ensure([
代碼分割 - CSSTODO System.import()
在 webpack 中,當你使用 css-loader 并且在 JavaScript 中引入 CSS 文件,那么 CSS 文件會被打包在你的 JavaScript 文件中。這有一個不好的地方,就是你無法使用瀏覽器異步并行加載 CSS 的能力。相反,你的頁面會等到整個 JavaScript 文件加載完成,才完成了樣式文件的加載。Webpack 可以通過使用 extract-text-webpack-plugin 和 css-loader 來把樣式文件分離出來去解決這個問題。
使用 css-loader引入 css 到你的 JavaScript 中,需要使用 css-loader 去配置 webpack 的配置文件。
//webpack.config.js modules.exports = function(env){ entry: "..", ... module: { rules: [{ test: /.css$/, exclude: /node_modules/, loader: "css-loader" }] } ... }使用 extract-text-webpack-plugin - ExtractTextPlugin
安裝:
npm I --save-dev extract-text-webpack-plugin
要使用這個 ExtractTextPlugin,需要通過兩個步驟配置在 webpack.config.js 中。
在 lodaer 里面從之前的 css-loader 中適配,我們應該如下添加 ExtractTextPlugin.
loader: ExtractTextPlugin.extract("css-loader?sourceMap") //Can be used without sourcemaps too.在 plugin 里面
new ExtractTextPlugin({ filename: "bundle.css", disable: false, allChunks: true })
通過這兩步,就可以生成一個新的包含所有 CSS 模塊的代碼包,然后把他們添加到 index.html 的 heade 中去。可以通過 ExtractTextPlugin 去了解關于它 api 的更多信息。
完整的配置文件如下:
var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = function () { return { entry: "./main.js", output: { path: "./dist", filename: "bundle.js" }, module: { rules: [{ test: /.css$/, exclude: /node_modules/, loader: ExtractTextPlugin.extract({ loader: "css-loader?sourceMap" }) }] }, devtool: "source-map", plugins: [ new ExtractTextPlugin({ filename: "bundle.css", disable: false, allChunks: true }) ] } }代碼分割-庫文件
一個典型的應用會依賴很多第三方來提供框架或功能支持。項目中使用的固定版本的庫/框架文件的代碼一般不會有變動,然而應用本身的業務邏輯代碼卻經常會有變動。
把應用代碼和庫文件的代碼打包在一起是一件非常低效的事情。這是因為瀏覽器可以根據緩存頭緩存這些資源文件到本地而不用每次都去服務端或者 cdn 上去發請求重新獲取,如果文件內容沒有變動的話。為了能夠享受這個好處,我們需要保持第三方文件的 hash 不變,無論應用本身的代碼如何變化。
我們只有把應用代碼和第三方代碼分離開才可以達到這樣的效果。
我們考慮一個一個簡單的應用,它使用了 momentjs ,一個通常用來時間格式化的庫。
安裝 moment :
npm install --save moment
Index 文件會引用 moment 作為一個依賴并且打印當前的時間:
Index.js
var moment = require("moment"); console.log(moment().format());
我們可以通過如下這個配置文件來打包這個應用
Webapck.config.js
module.exports = function(env) { return { entry: "./index.js", output: { filename: "[chunkhash].[name].js", path: "./dist" } } }
當運行 webapck 命令的時候,如果你檢查打包后的文件,你會發現 moment 和 index.js 都被打包在了 bundle.js 中。
這不是一個很好的解決方案。如果 index.js 修改了,那么這打包文件會重新構建,瀏覽器就需要重新去加載這個文件,即使 moment.js 文件并沒有任何改動。
多個入口讓我們緩和這個問題,我們給 moment 添加一個新的入口命名為 vendors.
Webpack.config.js
module.exports = function(env) { return { entry: { main: "./index.js", vendor: "moment" }, output: { filename: "[chunkhash].[name].js", path: "./dist" } } }
現在執行 webpack 命令,我們會看到兩個打包后的文件。如果你檢查里面代碼的話,你會看到 moment 的代碼同時出現在兩個代碼包中。
為了解決這個問題,我們需要使用 CommonsChunkPlugin.
CommonsChunksPlugin這是一個相當復雜的插件。它從根本上允許你從不同的代碼包中提取出所有的相同模塊并且把它們加入到共同的代碼包中。如果這個相同的代碼包不存在,那么就創建一個新的。
我們可以修改 webpack 的配置文件來使用這個 CommonsCunksPlugin
Webpack.config.js
var webpack = require("webpack"); module.exports = function(env) { return { entry: { main: "./index.js", vendor: "moment" }, output: { filename: "[chunkhash].[name].js", path: "./dist" }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: "vendor" // Specify the common bundle"s name. }) ] } }
這樣的話, moment 的代碼就只會出現在 vendor 代碼包中了。
清單文件(Manifest File)但是,如果我們可以修改應用的代碼并且再次執行 webpack 命令,我們看到 vendors 文件的 hash 還是變化了。即使我們已經分離了 vendor 和 main 代碼包,但是當應用代碼發生修改的時候 vendor 還是變化了。 這意味著我們依舊不能享受瀏覽器緩存帶來的好處,因為每一次重新編譯都會修改 vendors 的 hash 值。
這個問題是因為每一次編譯,webpack 生成一些 webpack 運行時代碼,用來幫助 webpack 來做它的工作。當那里存在一個多帶帶的代碼包,運行時會駐留在其中。但當多個代碼包被生成的時候,運行時代碼會被提取到公共的模塊中,就是這個 vendor 文件。
為了阻止這個,我們需要提取出運行時到一個分離的清單文件(Manifest File)。雖然我們又多創建另一個代碼包,但它的開銷也被我們在 vendor 文件上獲得的長期緩存所帶來的好處所抵消了。
Webpack.config.js
var webpack = require("webpack"); module.exports = function(env) { return { entry: { main: "./index.js", vendor: "moment" }, output: { filename: "[chunkhash].[name].js", path: "./dist" }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ names: ["vendor", "manifest"] // Specify the common bundle"s name. }) ] } };
通過上面這個配置文件,我們會看到三個代碼包被生成。vendor,main 和 manifest. 這樣當應用代碼修改的時候,重新打包后,修改的就只有 main 和 manifest 了。 manifest 被修改是因為里面有對生成文件 hash 值的引用。
代碼分割-使用 RequireJS在這個章節,我們討論 webpack 如何通過 require.ensure() 分割代碼。
require.ensure()Webpack 靜態分析給 require.ensure() 在代碼中當構建和添加模塊到分離的代碼塊中。這個新的代碼塊會被 webpack 在需要的時候通過 jsonp 引入。
它的語法如下:
require.ensure(dependencies: String[], callback: function(require), chunkName: String)依賴(dependencies)
這是一個字符串數組,用來聲明所有需要在執行回掉函數之前就需要預先加載好且可用的模塊。
回調函數(callback)一個回調函數會被 webpack 執行一次當所有依賴(dependencies)都被加載以后。Require 對象的實現作為一個參數傳遞給這個回調函數。這樣,我們可以更進一步 require 需要的依賴(dependencies)和其他需要執行的模塊。
代碼塊名字(chunkName)代碼塊名字是一個用來命名通過 require.ensrue() 創建的代碼塊。通過給不同的 require.ensure() 創建的代碼分割點分割出來的代碼塊一個相同的名字,我們可以確保所有的依賴都被打包到同一個代碼塊中。
我們來看一下如下結構的一個項目
file structure | js --| | |-- entry.js | |-- a.js | |-- b.js webpack.config.js | dist
// entry.js require("a"); require.ensure([], function(require){ require("b"); }); // a.js console.log("***** I AM a *****"); // b.js console.log("***** I AM b *****");
// webpack.config.js module.exports = function(env) { return { entry: "./js/entry.js", output: { filename: "bundle.js", path: "./dist" } } }
當運行 webpack 命令的時候,我們發現 webpack 創建了兩個新的代碼包,bundle.js 和 0.bundle.js.
entry.js 和 a.js 被打包到了 bundle.js 中。
b.js 被打包到了 0.bundle.js
require.ensure() 的陷阱 空數組作為一個參數require.ensure([], function(require){ require("./a.js"); });
上面的代碼確保一個分割點被創建, a.js 會被 webpack 多帶帶的打包成一個文件。
依賴作為參數require.ensure(["./a.js"], function(require) { require("./b.js"); });
上面的代碼,a.js 和 b.js 會被一起打包并且從主代碼包中分離出來。但是只有 b.js 的內容被執行了。 a.js 的內容只是是可用的但并沒有被執行。為了執行 a.js, 我們需要 require 它作為一個同步的方式比如 require("./a.js) ,這樣 JavaScript 就可以執行它了。
依賴管理? es6 module ? Commonjs ? Amd表達式依賴(require with expression)
當你通過表達式去引入一個模塊的時候,就會創建一個上下文,所以當編譯的時候我們并不知道準確的模塊是哪個。
例:
require("./template/" + name + ".ejs");
Webpack 解析 require() 的調用,并且提取出來一些信息:
Directory:./template Regularexpression:/^.*.ejs$/上下文模塊(context module)
一個上下文模塊被生成。它包含了在這個文件夾下所有可以被上面的正則匹配所匹配到的模塊的引用。上下文模塊包含了一個把請求解釋到模塊 id 的 map.
例:
{ "./table.ejs": 42, "./table-row.ejs": 43, "./directory/folder.ejs": 44 }
上下文模塊同樣包含了一些運行時代碼用來訪問這個 map.
這意味著動態的引用可以被支持,但是會導致所有可能被用到的模塊都被打包到了最終的代碼包中。
require.context你可以通過 require.context() 方法創建你自己的上下文。它允許你傳入一個用來查詢的文件夾,一個用來決定是否遞歸查找子文件夾的標識,還有一個用來匹配文件的正則表達式。
Webpack 會在代碼打包的時候解析 require.context()
它的語法如下:
require.context(directory, useSubdirectories = false, regExp = /^.//)
例:
require.context("./test", false, /.test.js$/); // a context with files from the test directory that can be required with a request endings with `.test.js`.
require.context("../", true, /.stories.js$/); // a context with all files in the parent folder and descending folders ending with `.stories.js`.上下文模塊API(context module API)
一個上下文模塊暴露一個方法,它接收一個參數:請求的內容。
暴露出來的函數有三個屬性:resolve,key,id
? `resolve` 是一個函數,執行后返回解析后的請求內容的模塊 id ? `keys`是一個函數,執行后返回一個數組,包含所有可能被上下文模塊所請求的所有的模塊的 id 當你想要通過正則匹配引入一個文件夾下所有模塊時,這會非常有用:
function importAll (r) { r.keys().forEach(r); } importAll(require.context("../components/", true, /.js$/))
var cache = {}; function importAll (r) { r.keys().forEach(key => cache[key] = r(key)); } importAll(require.context("../components/", true, /.js$/)); // At build-time cache will be polulated with all required modules.
? `id` 是上下文模塊生成的模塊 id. 當使用 `module.hot.accept` 時,這會非常有用。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81399.html
摘要:一些有用的一些有用的,包括轉換小箭頭三角形媒體查詢等中文指南是當下最熱門的前端資源模塊化管理和打包工具。 nodejs 入門 nodejs 入門教程,大家可以在 github 上提交錯誤 2016 年最好用的表單驗證庫 SMValidator.js 前端表單驗證工具分享 淺談前端線上部署與運維 說到前端部署,可能大多數前端工程師在工作中都是使用的公司現成的部署系統,與SRE對接、一起完...
摘要:一些有用的一些有用的,包括轉換小箭頭三角形媒體查詢等中文指南是當下最熱門的前端資源模塊化管理和打包工具。 nodejs 入門 nodejs 入門教程,大家可以在 github 上提交錯誤 2016 年最好用的表單驗證庫 SMValidator.js 前端表單驗證工具分享 淺談前端線上部署與運維 說到前端部署,可能大多數前端工程師在工作中都是使用的公司現成的部署系統,與SRE對接、一起完...
摘要:我們先假設設置為從安裝然后就可以執行的命令了上面的命令會自動打開你的瀏覽器并指定到修改一下你的文件并保存。比如,類似與解析等都是共通的功能,需要放在基礎配置文件里面然后使用來合并特定環境變量下指定的配置文件。 原文發布與抹橋的博客-【翻譯向】webpack2 指南(中) 動態模塊替換(Hot Module Repalcement -React) 就像之前 理念頁面 中解析的細節那樣,動...
摘要:名稱后自動自動補全的功能將被移除在配置時,官方不再允許省略擴展名,的配置寫法上將逐步趨于嚴謹。使用自定義參數作為配置項傳入方式將做調整如果你隨意將自定義參數通過傳入到配置項中,如你會發現這將不會被允許,的執行將會遵循更為嚴格的標準。 歷時多日,webpack2.2正式版終于趕在年前發布了,此次更新相對于1.X版本有了諸多的升級優化改進,筆者也在第一時間查閱了官方的文檔,整理和翻譯了由w...
摘要:從再到目前當紅明星,前端模塊打包技術日新月異,在今年月份和月份左右接連更新了和版本為了減少冗余模塊,縮減文件大小,中也加入了關于的特征,可以查看知乎如何評價新引入的代碼優化技術的討論。 從Grunt->gulp->webpack,再到目前當紅明星rollup,前端模塊打包技術日新月異,webpack在今年1月份和6月份左右接連更新了v2和v3版本,為了減少冗余模塊,縮減bundle文件...
閱讀 1382·2021-09-22 10:02
閱讀 1862·2021-09-08 09:35
閱讀 4044·2021-08-12 13:29
閱讀 2594·2019-08-30 15:55
閱讀 2257·2019-08-30 15:53
閱讀 2295·2019-08-29 17:13
閱讀 2753·2019-08-29 16:31
閱讀 2948·2019-08-29 12:24