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