柚子快報邀請碼778899分享:再學(xué)webpack
柚子快報邀請碼778899分享:再學(xué)webpack
1 優(yōu)化 webpack 打包體積的思路
優(yōu)化 webpack 打包體積的思路包括:
提取第三方庫或通過引用外部文件的方式引入第三方庫:將第三方庫單獨(dú)打包,并通過 CDN 引入,減少打包體積。使用代碼壓縮插件:例如 UglifyJsPlugin,可以壓縮 JavaScript 代碼,減小文件體積。啟用服務(wù)器端的 Gzip 壓縮:通過服務(wù)器端配置 Gzip 壓縮,減少傳輸體積。按需加載資源文件:使用 require.ensure 或動態(tài)導(dǎo)入(import())的方式按需加載資源文件,避免一次性加載所有資源,優(yōu)化加載速度和體積。優(yōu)化 devtool 中的 source-map:選擇合適的 devtool 配置,確保在開發(fā)階段能夠提供足夠的錯誤追蹤信息,但不會增加過多的打包體積。剝離 CSS 文件:將 CSS 文件單獨(dú)打包,通過 標(biāo)簽引入,利用瀏覽器的并行加載能力。去除不必要的插件:檢查 webpack 配置中的插件,移除不必要的插件或根據(jù)環(huán)境區(qū)分開發(fā)環(huán)境和生產(chǎn)環(huán)境的配置,避免將開發(fā)環(huán)境的調(diào)試工具打包到生產(chǎn)環(huán)境中。
除了上述優(yōu)化思路,還可以考慮以下幾點(diǎn):
使用 Tree Shaking:通過配置 webpack,將未使用的代碼在打包過程中消除,減少打包體積。使用模塊化引入:合理使用 ES6 模塊化語法或其他模塊化方案,按需引入模塊,避免不必要的全局引入。按需加載第三方庫:對于較大的第三方庫,可以考慮按需加載,而不是一次性全部引入。優(yōu)化圖片資源:壓縮圖片,使用適當(dāng)?shù)膱D片格式,盡量減小圖片體積。優(yōu)化字體文件:如果使用了大量的字體文件,可以考慮只引入需要的字體文件,避免全部引入。使用緩存:通過配置合適的緩存策略,利用瀏覽器緩存機(jī)制,減少重復(fù)加載資源。
綜合以上優(yōu)化思路,可以有效減小 webpack 打包生成的文件體積,提升應(yīng)用性能和加載速度。需要根據(jù)具體項目情況和需求,選擇合適的優(yōu)化策略和配置。
2 優(yōu)化 webpack 打包效率的方法
使用增量構(gòu)建和熱更新:在開發(fā)環(huán)境下,使用增量構(gòu)建和熱更新功能,只重新構(gòu)建修改過的模塊,減少整體構(gòu)建時間。避免無意義的工作:在開發(fā)環(huán)境中,避免執(zhí)行無意義的工作,如提取 CSS、計算文件 hash 等,以減少構(gòu)建時間。配置合適的 devtool:選擇適當(dāng)?shù)?devtool 配置,提供足夠的調(diào)試信息,但不會對構(gòu)建性能產(chǎn)生太大影響。選擇合適的 loader:根據(jù)需要加載的資源類型選擇高效的 loader,避免不必要的解析和處理過程。啟用 loader 緩存:對于耗時較長的 loader,如 babel-loader,可以啟用緩存功能,避免重復(fù)處理同一文件。采用引入方式引入第三方庫:對于第三方庫,可以通過直接引入的方式(如 CDN 引入)來減少打包時間。提取公共代碼:通過配置 webpack 的 SplitChunks 插件,提取公共代碼,避免重復(fù)打包相同的代碼,提高打包效率。優(yōu)化構(gòu)建時的搜索路徑:指定需要構(gòu)建的目錄和不需要構(gòu)建的目錄,減少搜索范圍,加快構(gòu)建速度。模塊化引入需要的部分:使用按需引入的方式,只引入需要的模塊或組件,避免加載不必要的代碼,提高構(gòu)建效率。
通過以上優(yōu)化措施,可以有效提升 webpack 的打包效率,減少開發(fā)和構(gòu)建時間,提升開發(fā)效率和用戶體驗(yàn)。根據(jù)具體項目需求和場景,選擇適合的優(yōu)化方法進(jìn)行配置和調(diào)整。
3 編寫Loader
編寫一個名為 reverse-txt-loader 的 Loader,實(shí)現(xiàn)對文本內(nèi)容進(jìn)行反轉(zhuǎn)處理的功能。
// reverse-txt-loader.js
module.exports = function (source) {
// 對源代碼進(jìn)行處理,這里是將字符串反轉(zhuǎn)
const reversedSource = source.split('').reverse().join('');
// 返回處理后的 JavaScript 代碼作為模塊輸出
return `module.exports = '${reversedSource}';`;
};
上述代碼定義了一個函數(shù),該函數(shù)接收一個參數(shù) source,即原始的文本內(nèi)容。在函數(shù)內(nèi)部,我們將源代碼進(jìn)行反轉(zhuǎn)處理,并將處理后的結(jié)果拼接成一個字符串,再通過 module.exports 輸出為一個 JavaScript 模塊。
要使用這個 Loader,需要在 webpack 配置中指定該 Loader 的路徑:
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /.txt$/,
use: [
{
loader: './path/reverse-txt-loader'
}
]
}
]
}
// ...
};
上述配置將該 Loader 應(yīng)用于所有以 .txt 結(jié)尾的文件。在構(gòu)建過程中,當(dāng)遇到需要加載的 .txt 文件時,會調(diào)用 reverse-txt-loader 對文件內(nèi)容進(jìn)行反轉(zhuǎn)處理,并將處理后的結(jié)果作為模塊的輸出。
請注意,在實(shí)際使用中,需要根據(jù)實(shí)際路徑修改 loader 配置的路徑,并將該 Loader 安裝在項目中。
4 編寫plugin
編寫一個自定義的 Webpack 插件需要創(chuàng)建一個 JavaScript 類,并在類中實(shí)現(xiàn)指定的生命周期方法。下面是一個簡單的示例,展示如何編寫一個自定義的 Webpack 插件:
class MyPlugin {
constructor(options) {
// 在構(gòu)造函數(shù)中可以接收插件的配置參數(shù)
this.options = options;
}
// Webpack 在安裝插件時會自動調(diào)用 apply 方法,并將 compiler 對象傳遞進(jìn)來
apply(compiler) {
// 在適當(dāng)?shù)纳芷阢^子中掛載插件的功能
// 示例:在 emit 生命周期鉤子中添加自定義的功能
compiler.hooks.emit.tap('MyPlugin', (compilation) => {
// compilation 對象包含了當(dāng)前構(gòu)建過程的各種信息
// 可以在這里執(zhí)行一些自定義的操作
// 示例:向輸出的文件中添加自定義的注釋
const comment = this.options.comment || 'Custom comment';
for (const asset in compilation.assets) {
if (compilation.assets.hasOwnProperty(asset)) {
compilation.assets[asset].source = () => {
return `/* ${comment} */\n` + compilation.assets[asset].source();
};
}
}
});
}
}
以上是一個簡單的插件示例,它在構(gòu)建過程中的 emit 生命周期鉤子中向輸出的文件添加了自定義的注釋。你可以根據(jù)實(shí)際需求在其他生命周期鉤子中實(shí)現(xiàn)不同的功能。
要使用該插件,在 webpack 的配置文件中進(jìn)行如下配置:
const MyPlugin = require('./path/to/MyPlugin');
module.exports = {
// ...
plugins: [
new MyPlugin({
comment: 'Custom comment',
}),
],
};
這樣,當(dāng)你運(yùn)行 webpack 構(gòu)建時,該插件就會被應(yīng)用,并執(zhí)行指定的功能。
需要注意的是,Webpack 的插件機(jī)制非常靈活,可以根據(jù)實(shí)際需求編寫各種各樣的插件。插件可以監(jiān)聽多個生命周期鉤子,并在每個生命周期鉤子中實(shí)現(xiàn)自定義的功能。詳細(xì)的插件開發(fā)文檔可以參考 Webpack 官方文檔。
5 說一下webpack的一些plugin,怎么使用webpack對項目進(jìn)行優(yōu)化
Webpack 提供了許多插件(Plugins)來幫助優(yōu)化項目構(gòu)建和性能。下面列舉一些常用的插件以及它們的作用:
構(gòu)建優(yōu)化插件:
ContextReplacementPlugin:用于限制某些模塊的上下文,可以減少編譯體積。IgnorePlugin:用于忽略特定的模塊,減少打包體積。babel-plugin-import:用于按需加載和使用模塊,減少打包體積。babel-plugin-transform-runtime:將代碼中的公共部分提取到一個單獨(dú)的模塊中,減少打包體積。happypack、thread-loader:實(shí)現(xiàn)并行編譯,加快構(gòu)建速度。uglifyjs-webpack-plugin:通過并行壓縮和緩存來加快代碼壓縮的速度。
性能優(yōu)化插件:
Tree-shaking:通過靜態(tài)分析代碼,去除未使用的代碼,減少打包體積。Scope Hoisting:將模塊之間的關(guān)系進(jìn)行靜態(tài)分析,減少打包后的模塊數(shù)量,提升代碼執(zhí)行速度。webpack-md5-plugin:根據(jù)文件內(nèi)容生成 hash,實(shí)現(xiàn)緩存的更新機(jī)制。splitChunksPlugin:根據(jù)配置將代碼拆分成多個塊,實(shí)現(xiàn)按需加載和并行加載的效果。import()、require.ensure:動態(tài)導(dǎo)入模塊,實(shí)現(xiàn)按需加載,提升頁面加載速度。
除了使用這些插件,還可以通過配置 webpack 的其他參數(shù)來進(jìn)一步優(yōu)化項目,例如:
配置 devtool:選擇合適的 Source Map 類型,既滿足調(diào)試需求又不影響構(gòu)建速度。配置 output:使用 chunkhash 或 contenthash 生成文件名,實(shí)現(xiàn)長期緩存。使用 cache-loader、hard-source-webpack-plugin、uglifyjs-webpack-plugin 等插件開啟緩存,加速再次構(gòu)建。使用 DllWebpackPlugin 和 DllReferencePlugin 預(yù)編譯公共模塊,減少重復(fù)構(gòu)建時間。
綜合使用這些插件和優(yōu)化策略,可以顯著提升 webpack 項目的構(gòu)建效率和性能。但是需要根據(jù)具體的項目需求和場景選擇合適的插件和優(yōu)化方法。
6 webpack Plugin 和 Loader 的區(qū)別
Loader 用于對模塊源碼進(jìn)行轉(zhuǎn)換,將非 JavaScript 模塊轉(zhuǎn)換為 JavaScript 模塊,或?qū)δK進(jìn)行預(yù)處理。它描述了 webpack 如何處理不同類型的文件,比如將 Sass 文件轉(zhuǎn)換為 CSS 文件,或?qū)?ES6 代碼轉(zhuǎn)換為 ES5 代碼。Loader 是針對單個文件的轉(zhuǎn)換操作,通過配置 rules 來匹配文件并指定相應(yīng)的 LoaderPlugin 用于擴(kuò)展 webpack 的功能,解決 Loader 無法解決的問題。Plugin 可以監(jiān)聽 webpack 構(gòu)建過程中的事件,并在特定的時機(jī)執(zhí)行相應(yīng)的操作。它可以在打包優(yōu)化、資源管理、環(huán)境變量注入等方面提供額外的功能。Plugin 的功能范圍更廣泛,可以修改 webpack 的內(nèi)部行為,從而實(shí)現(xiàn)更復(fù)雜的構(gòu)建需求。
總的來說,Loader 是用于處理模塊源碼的轉(zhuǎn)換工具,而 Plugin 則是用于擴(kuò)展 webpack 的功能,通過監(jiān)聽 webpack 構(gòu)建過程中的事件來執(zhí)行相應(yīng)的操作。它們各自的作用和功能不同,但都可以用于優(yōu)化和定制 webpack 的構(gòu)建過程。在配置 webpack 時,我們可以通過配置 Loader 和 Plugin 來滿足不同的需求,并實(shí)現(xiàn)對模塊的轉(zhuǎn)換和構(gòu)建過程的定制化
7 tree shaking 的原理是什么
Tree shaking 的原理主要是基于靜態(tài)分析的方式來實(shí)現(xiàn)無用代碼的消除,從而減小最終打包生成的文件體積。它的工作原理可以簡要概括如下:
采用 ES6 Module 語法:Tree shaking 只對 ES6 Module 語法進(jìn)行靜態(tài)分析和優(yōu)化。ES6 Module 的特點(diǎn)是可以進(jìn)行靜態(tài)分析,這意味著在編譯階段就能夠確定模塊之間的依賴關(guān)系。靜態(tài)分析模塊依賴:在編譯過程中,通過靜態(tài)分析可以確定每個模塊的依賴關(guān)系,以及模塊中導(dǎo)出的函數(shù)、變量等信息。標(biāo)記未被引用的代碼:在靜態(tài)分析的過程中,會標(biāo)記出那些未被其他模塊引用的函數(shù)、變量和代碼塊。消除未被引用的代碼:在構(gòu)建過程中,根據(jù)靜態(tài)分析得到的標(biāo)記信息,可以對未被引用的代碼進(jìn)行消除。這樣,在最終生成的打包文件中,未被引用的代碼將不會包含在內(nèi)。
總結(jié)來說,Tree shaking 的核心思想是通過靜態(tài)分析模塊依賴關(guān)系,并標(biāo)記和消除未被引用的代碼。這樣可以大大減小打包后的文件體積,提升應(yīng)用的性能和加載速度。需要注意的是,Tree shaking 只對 ES6 Module 語法起作用,而對于 CommonJS 等其他模塊系統(tǒng)則無法進(jìn)行靜態(tài)分析和優(yōu)化。
8 common.js 和 es6 中模塊引入的區(qū)別
CommonJS 是一種模塊規(guī)范,最初被應(yīng)用于 Nodejs,成為 Nodejs 的模塊規(guī)范。運(yùn)行在瀏覽器端的 JavaScript 由于也缺少類似的規(guī)范,在 ES6 出來之前,前端也實(shí)現(xiàn)了一套相同的模塊規(guī)范 (例如: AMD),用來對前端模塊進(jìn)行管理。自 ES6 起,引入了一套新的 ES6 Module規(guī)范,在語言標(biāo)準(zhǔn)的層面上實(shí)現(xiàn)了模塊功能,而且實(shí)現(xiàn)得相當(dāng)簡單,有望成為瀏覽器和服務(wù)器通用的模塊解決方案。但目前瀏覽器對 ES6 Module 兼容還不太好,我們平時在 Webpack 中使用的 export和 import,會經(jīng)過 Babel 轉(zhuǎn)換為 CommonJS 規(guī)范
CommonJS 和 ES6 Module 在模塊引入的方式和特性上有一些區(qū)別,主要包括以下幾個方面:
輸出方式:CommonJS 輸出的是一個值的拷貝,而 ES6 Module 輸出的是值的引用。在 CommonJS 中,模塊導(dǎo)出的值是被復(fù)制的,即使導(dǎo)出模塊后修改了模塊內(nèi)部的值,也不會影響導(dǎo)入模塊的值。而在 ES6 Module 中,模塊導(dǎo)出的值是引用關(guān)系,如果導(dǎo)出模塊后修改了模塊內(nèi)部的值,會影響到導(dǎo)入模塊的值加載時機(jī):CommonJS 模塊是運(yùn)行時加載,也就是在代碼執(zhí)行到導(dǎo)入模塊的位置時才會加載模塊并執(zhí)行。而 ES6 Module 是編譯時輸出接口,也就是在代碼編譯階段就會確定模塊的依賴關(guān)系,并在運(yùn)行前靜態(tài)地解析模塊的導(dǎo)入和導(dǎo)出導(dǎo)出方式:CommonJS 采用的是 module.exports 導(dǎo)出,可以導(dǎo)出任意類型的值。ES6 Module 采用的是 export 導(dǎo)出,只能導(dǎo)出具名的變量、函數(shù)、類等,而不能直接導(dǎo)出任意值導(dǎo)入方式:CommonJS 使用 require() 來導(dǎo)入模塊,可以使用動態(tài)語法,允許在條件語句中使用。ES6 Module 使用 import 來導(dǎo)入模塊,它是靜態(tài)語法,只能寫在模塊的頂層,不能寫在條件語句中this 指向:CommonJS 模塊中的 this 指向當(dāng)前模塊的 exports 對象,而不是全局對象。ES6 Module 中的 this 默認(rèn)是 undefined,在模塊中直接使用 this 會報錯
總的來說,CommonJS 主要用于服務(wù)器端的模塊化開發(fā),運(yùn)行時加載,更適合動態(tài)加載模塊,而 ES6 Module 是在語言層面上實(shí)現(xiàn)的模塊化方案,靜態(tài)編譯,更適合在構(gòu)建時進(jìn)行模塊依賴的靜態(tài)分析和優(yōu)化。在前端開發(fā)中,通常使用打包工具(如 webpack)將 ES6 Module 轉(zhuǎn)換為 CommonJS 或其他模塊規(guī)范,以實(shí)現(xiàn)在瀏覽器環(huán)境中的兼容性。
9 babel原理
Babel 是一個 JavaScript 編譯器。他把最新版的 javascript 編譯成當(dāng)下可以執(zhí)行的版本,簡言之,利用 babel 就可以讓我們在當(dāng)前的項目中隨意的使用這些新最新的 es6,甚至 es7 的語法
ES6、7代碼輸入 -> babylon進(jìn)行解析 -> 得到AST(抽象語法樹)-> plugin用babel-traverse對AST樹進(jìn)行遍歷轉(zhuǎn)譯 ->得到新的AST樹->用babel-generator通過AST樹生成ES5代碼
它的工作流程包括解析(parse)、轉(zhuǎn)換(transform)和生成(generate)三個主要步驟
解析(parse) :Babel 使用解析器(如 Babylon)將輸入的 JavaScript 代碼解析成抽象語法樹(AST)。解析器將代碼分析成語法結(jié)構(gòu),并生成對應(yīng)的 AST,表示代碼的抽象語法結(jié)構(gòu)。這個階段包括詞法分析和語法分析。詞法分析將源代碼轉(zhuǎn)換為一個個標(biāo)記(tokens)的流,而語法分析則將這個標(biāo)記流轉(zhuǎn)換為 AST 的形式。轉(zhuǎn)換(transform) :在轉(zhuǎn)換階段,Babel 使用插件(plugins)對 AST 進(jìn)行遍歷和轉(zhuǎn)換。插件可以對 AST 進(jìn)行增刪改查的操作,可以根據(jù)需求對語法進(jìn)行轉(zhuǎn)換、代碼優(yōu)化等。Babel 的插件系統(tǒng)非常靈活,可以根據(jù)需要自定義插件或使用現(xiàn)有插件來進(jìn)行代碼轉(zhuǎn)換。生成(generate) :在生成階段,Babel 使用生成器(如 babel-generator)將經(jīng)過轉(zhuǎn)換的 AST 轉(zhuǎn)換回字符串形式的 JavaScript 代碼。生成器會深度優(yōu)先遍歷 AST,并根據(jù) AST 的節(jié)點(diǎn)類型生成對應(yīng)的代碼字符串,最終將代碼字符串輸出。
通過以上三個步驟,Babel 實(shí)現(xiàn)了將最新版本的 JavaScript 代碼轉(zhuǎn)換為向后兼容的代碼,使得開發(fā)者可以在當(dāng)前環(huán)境中使用較新的 JavaScript 特性和語法。同時,Babel 還提供了一些常用的插件和預(yù)設(shè)(presets),以便開發(fā)者快速配置和使用常見的轉(zhuǎn)換規(guī)則,如轉(zhuǎn)換 ES6、ES7 語法、處理模塊化、轉(zhuǎn)換 JSX 等。
總的來說,Babel 的原理是通過解析、轉(zhuǎn)換和生成的過程,將新版本的 JavaScript 代碼轉(zhuǎn)換為兼容舊環(huán)境的代碼,使開發(fā)者能夠在當(dāng)前環(huán)境中使用較新的 JavaScript 特性和語法。
1 介紹一下 webpack 的構(gòu)建流程
核心概念
entry:入口。webpack是基于模塊的,使用webpack首先需要指定模塊解析入口(entry),webpack從入口開始根據(jù)模塊間依賴關(guān)系遞歸解析和處理所有資源文件。output:輸出。源代碼經(jīng)過webpack處理之后的最終產(chǎn)物。loader:模塊轉(zhuǎn)換器。本質(zhì)就是一個函數(shù),在該函數(shù)中對接收到的內(nèi)容進(jìn)行轉(zhuǎn)換,返回轉(zhuǎn)換后的結(jié)果。因?yàn)?Webpack 只認(rèn)識 JavaScript,所以 Loader 就成了翻譯官,對其他類型的資源進(jìn)行轉(zhuǎn)譯的預(yù)處理工作。plugin:擴(kuò)展插件?;谑录骺蚣?Tapable,插件可以擴(kuò)展 Webpack 的功能,在 Webpack 運(yùn)行的生命周期中會廣播出許多事件,Plugin 可以監(jiān)聽這些事件,在合適的時機(jī)通過 Webpack 提供的 API 改變輸出結(jié)果。module:模塊。除了js范疇內(nèi)的es module、commonJs、AMD等,css @import、url(...)、圖片、字體等在webpack中都被視為模塊。
解釋幾個 webpack 中的術(shù)語
module:指在模塊化編程中我們把應(yīng)用程序分割成的獨(dú)立功能的代碼模塊chunk:指模塊間按照引用關(guān)系組合成的代碼塊,一個 chunk 中可以包含多個 modulechunk group:指通過配置入口點(diǎn)(entry point)區(qū)分的塊組,一個 chunk group 中可包含一到多個 chunkbundling:webpack 打包的過程asset/bundle:打包產(chǎn)物
webpack 的打包思想可以簡化為 3 點(diǎn):
一切源代碼文件均可通過各種 Loader 轉(zhuǎn)換為 JS 模塊 (module),模塊之間可以互相引用。webpack 通過入口點(diǎn)(entry point)遞歸處理各模塊引用關(guān)系,最后輸出為一個或多個產(chǎn)物包 js(bundle) 文件。每一個入口點(diǎn)都是一個塊組(chunk group),在不考慮分包的情況下,一個 chunk group 中只有一個 chunk,該 chunk 包含遞歸分析后的所有模塊。每一個 chunk 都有對應(yīng)的一個打包后的輸出文件(asset/bundle)
打包流程
初始化參數(shù):從配置文件和 Shell 語句中讀取并合并參數(shù),得出最終的配置參數(shù)。開始編譯:從上一步得到的參數(shù)初始化 Compiler 對象,加載所有配置的插件,執(zhí)行對象的 run 方法開始執(zhí)行編譯。確定入口:根據(jù)配置中的 entry 找出所有的入口文件。編譯模塊:從入口文件出發(fā),調(diào)用所有配置的 loader 對模塊進(jìn)行翻譯,再找出該模塊依賴的模塊,這個步驟是遞歸執(zhí)行的,直至所有入口依賴的模塊文件都經(jīng)過本步驟的處理。完成模塊編譯:經(jīng)過第 4 步使用 loader 翻譯完所有模塊后,得到了每個模塊被翻譯后的最終內(nèi)容以及它們之間的依賴關(guān)系。輸出資源:根據(jù)入口和模塊之間的依賴關(guān)系,組裝成一個個包含多個模塊的 chunk,再把每個 chunk 轉(zhuǎn)換成一個單獨(dú)的文件加入到輸出列表,這一步是可以修改輸出內(nèi)容的最后機(jī)會。輸出完成:在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和文件名,把文件內(nèi)容寫入到文件系統(tǒng)。
簡版
Webpack CLI 啟動打包流程;載入 Webpack 核心模塊,創(chuàng)建 Compiler 對象;使用 Compiler 對象開始編譯整個項目;從入口文件開始,解析模塊依賴,形成依賴關(guān)系樹;遞歸依賴樹,將每個模塊交給對應(yīng)的 Loader 處理;合并 Loader 處理完的結(jié)果,將打包結(jié)果輸出到 dist 目錄。
在以上過程中,Webpack 會在特定的時間點(diǎn)廣播出特定的事件,插件在監(jiān)聽到相關(guān)事件后會執(zhí)行特定的邏輯,并且插件可以調(diào)用 Webpack 提供的 API 改變 Webpack 的運(yùn)行結(jié)果
構(gòu)建流程核心概念:
Tapable:一個基于發(fā)布訂閱的事件流工具類,Compiler 和 Compilation 對象都繼承于 TapableCompiler:compiler對象是一個全局單例,他負(fù)責(zé)把控整個webpack打包的構(gòu)建流程。在編譯初始化階段被創(chuàng)建的全局單例,包含完整配置信息、loaders、plugins以及各種工具方法Compilation:代表一次 webpack 構(gòu)建和生成編譯資源的的過程,在watch模式下每一次文件變更觸發(fā)的重新編譯都會生成新的 Compilation 對象,包含了當(dāng)前編譯的模塊 module, 編譯生成的資源,變化的文件, 依賴的狀態(tài)等而每個模塊間的依賴關(guān)系,則依賴于AST語法樹。每個模塊文件在通過Loader解析完成之后,會通過acorn庫生成模塊代碼的AST語法樹,通過語法樹就可以分析這個模塊是否還有依賴的模塊,進(jìn)而繼續(xù)循環(huán)執(zhí)行下一個模塊的編譯解析。
最終Webpack打包出來的bundle文件是一個IIFE的執(zhí)行函數(shù)。
// webpack 5 打包的bundle文件內(nèi)容
(() => { // webpackBootstrap
var __webpack_modules__ = ({
'file-A-path': ((modules) => { // ... })
'index-file-path': ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { // ... })
})
// The module cache
var __webpack_module_cache__ = {};
// The require function
function __webpack_require__(moduleId) {
// Check if module is in cache
var cachedModule = __webpack_module_cache__[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// Create a new module (and put it into the cache)
var module = __webpack_module_cache__[moduleId] = {
// no module.id needed
// no module.loaded needed
exports: {}
};
// Execute the module function
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
// Return the exports of the module
return module.exports;
}
// startup
// Load entry module and return exports
// This entry module can't be inlined because the eval devtool is used.
var __webpack_exports__ = __webpack_require__("./src/index.js");
})
webpack詳細(xì)工作流程
2 介紹 Loader
常用 Loader:
file-loader: 加載文件資源,如 字體 / 圖片 等,具有移動/復(fù)制/命名等功能;url-loader: 通常用于加載圖片,可以將小圖片直接轉(zhuǎn)換為 Date Url,減少請求;babel-loader: 加載 js / jsx 文件, 將 ES6 / ES7 代碼轉(zhuǎn)換成 ES5,抹平兼容性問題;ts-loader: 加載 ts / tsx 文件,編譯 TypeScript;style-loader: 將 css 代碼以