自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Webpack原理與實(shí)踐之Webpack運(yùn)行機(jī)制與核心工作原理

開發(fā) 前端
對(duì)于依賴模塊中無(wú)法通過(guò)js代碼表示的資源模塊,例如圖片或字體文件,一般的Loader會(huì)將它們單獨(dú)作為資源文件拷貝到輸出目錄中,然后將這個(gè)資源文件所對(duì)應(yīng)的訪問(wèn)路徑作為這個(gè)模塊的導(dǎo)出成員暴露給外部。

[[441145]]

寫在前面

Webpack在整個(gè)打包過(guò)程中:

通過(guò)loader處理特殊類型資源的加載,例如加載樣式、圖片

通過(guò)plugin實(shí)現(xiàn)各種自動(dòng)化的構(gòu)建任務(wù),例如自動(dòng)壓縮、自動(dòng)發(fā)布

那么webpack的工作過(guò)程和原理又是如何實(shí)現(xiàn)的呢?

Webpack的工作過(guò)程

首先webpack會(huì)加載入口文件js,通過(guò)分析代碼中import、require等去解析依賴,然后通過(guò)依賴形成依賴關(guān)系樹,webpack會(huì)去遍歷依賴關(guān)系樹,去加載所依賴的資源模塊。webpack會(huì)通過(guò)Loader配置去加載模塊,通過(guò)plugins實(shí)現(xiàn)自動(dòng)化構(gòu)建。

對(duì)于依賴模塊中無(wú)法通過(guò)js代碼表示的資源模塊,例如圖片或字體文件,一般的Loader會(huì)將它們單獨(dú)作為資源文件拷貝到輸出目錄中,然后將這個(gè)資源文件所對(duì)應(yīng)的訪問(wèn)路徑作為這個(gè)模塊的導(dǎo)出成員暴露給外部。

webpack在每個(gè)打包環(huán)節(jié)都預(yù)留了鉤子,我們可以通過(guò)plugins去配置其所依賴的插件。

具體的:

  • Webpack cli啟動(dòng)打包流程
  • 載入Webpack核心模塊,創(chuàng)建Compiler對(duì)象
  • 使用創(chuàng)建Compiler對(duì)象開始編譯整個(gè)項(xiàng)目
  • 從入口文件開始,解析模塊依賴,形成依賴關(guān)系樹
  • 遞歸遍歷依賴樹,將每個(gè)模塊交給對(duì)應(yīng)的loader處理
  • 合并loader處理完的結(jié)果,將打包結(jié)果輸出到dist目錄

Webpack cli的作用是將cli參數(shù)和webpack配置文件中的配置進(jìn)行整合得到一個(gè)完整的配置對(duì)象。Webpack cli會(huì)通過(guò)yargs模塊解析cli參數(shù),運(yùn)行webpack命令時(shí)通過(guò)命令行傳入的參數(shù)。

  1. const config = { options: {}, path: new WeakMap() }; 
  2.     // 判斷是否指定了配置文件 
  3.     if (options.config && options.config.length > 0) { 
  4.       const loadedConfigs = await Promise.all
  5.         options.config.map((configPath) => 
  6.           loadConfigByPath(path.resolve(configPath), options.argv), 
  7.         ), 
  8.       ); 
  9.  
  10.       config.options = []; 
  11.  
  12.       loadedConfigs.forEach((loadedConfig) => { 
  13.         const isArray = Array.isArray(loadedConfig.options); 
  14.  
  15.         // TODO we should run webpack multiple times when the `--config` options have multiple values with `--merge`, need to solve for the next major release 
  16.         if (config.options.length === 0) { 
  17.           config.options = loadedConfig.options; 
  18.         } else { 
  19.           if (!Array.isArray(config.options)) { 
  20.             config.options = [config.options]; 
  21.           } 
  22.  
  23.           if (isArray) { 
  24.             loadedConfig.options.forEach((item) => { 
  25.               config.options.push(item); 
  26.             }); 
  27.           } else { 
  28.             config.options.push(loadedConfig.options); 
  29.           } 
  30.         } 
  31.  
  32.         if (isArray) { 
  33.           loadedConfig.options.forEach((options) => { 
  34.             config.path.set(options, loadedConfig.path); 
  35.           }); 
  36.         } else { 
  37.           config.path.set(loadedConfig.options, loadedConfig.path); 
  38.         } 
  39.       }); 
  40.  
  41.       config.options = config.options.length === 1 ? config.options[0] : config.options; 
  42.     } else { 
  43.       // 按照配置文件規(guī)則找到加載配置文件 
  44.       // Order defines the priority, in decreasing order 
  45.       const defaultConfigFiles = [ 
  46.         "webpack.config"
  47.         ".webpack/webpack.config"
  48.         ".webpack/webpackfile"
  49.       ] 
  50.         .map((filename) => 
  51.           // Since .cjs is not available on interpret side add it manually to default config extension list 
  52.           [...Object.keys(interpret.extensions), ".cjs"].map((ext) => ({ 
  53.             path: path.resolve(filename + ext), 
  54.             ext: ext, 
  55.             module: interpret.extensions[ext], 
  56.           })), 
  57.         ) 
  58.         .reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); 
  59.  
  60.       let foundDefaultConfigFile; 
  61.  
  62.       for (const defaultConfigFile of defaultConfigFiles) { 
  63.         if (!fs.existsSync(defaultConfigFile.path)) { 
  64.           continue
  65.         } 
  66.  
  67.         foundDefaultConfigFile = defaultConfigFile; 
  68.         break; 
  69.       } 
  70.  
  71.       if (foundDefaultConfigFile) { 
  72.         const loadedConfig = await loadConfigByPath(foundDefaultConfigFile.path, options.argv); 
  73.  
  74.         config.options = loadedConfig.options; 
  75.  
  76.         if (Array.isArray(config.options)) { 
  77.           config.options.forEach((item) => { 
  78.             config.path.set(item, loadedConfig.path); 
  79.           }); 
  80.         } else { 
  81.           config.path.set(loadedConfig.options, loadedConfig.path); 
  82.         } 
  83.       } 
  84.     } 

開始載入webpack核心模塊,傳入配置選項(xiàng),創(chuàng)建Compiler對(duì)象。

  1. // 創(chuàng)建Compiler對(duì)象的函數(shù) 
  2. async createCompiler(options, callback) { 
  3.   if (typeof options.nodeEnv === "string") { 
  4.     process.env.NODE_ENV = options.nodeEnv; 
  5.   } 
  6.  
  7.   let config = await this.loadConfig(options); 
  8.   config = await this.buildConfig(config, options); 
  9.  
  10.   let compiler; 
  11.  
  12.   try { 
  13.     // 開始調(diào)用webpack核心模塊 
  14.     compiler = this.webpack( 
  15.       config.options, 
  16.       callback 
  17.         ? (error, stats) => { 
  18.             if (error && this.isValidationError(error)) { 
  19.               this.logger.error(error.message); 
  20.               process.exit(2); 
  21.             } 
  22.  
  23.             callback(error, stats); 
  24.           } 
  25.         : callback, 
  26.     ); 
  27.   } catch (error) { 
  28.     if (this.isValidationError(error)) { 
  29.       this.logger.error(error.message); 
  30.     } else { 
  31.       this.logger.error(error); 
  32.     } 
  33.  
  34.     process.exit(2); 
  35.   } 
  36.  
  37.   // TODO webpack@4 return Watching and MultiWatching instead Compiler and MultiCompiler, remove this after drop webpack@4 
  38.   if (compiler && compiler.compiler) { 
  39.     compiler = compiler.compiler; 
  40.   } 
  41.  
  42.   return compiler; 

make階段

make階段主體的目標(biāo)是:根據(jù)entry配置找到入口模塊,開始依次遞歸出所有依賴,形成依賴關(guān)系樹,然后遞歸到的每個(gè)模塊交給不同的loader處理。

  1. // 多路打包 
  2. if (Array.isArray(options)) { 
  3.   await Promise.all
  4.     options.map(async (_, i) => { 
  5.       if (typeof options[i].then === "function") { 
  6.         options[i] = await options[i]; 
  7.       } 
  8.  
  9.       // `Promise` may return `Function
  10.       if (typeof options[i] === "function") { 
  11.         // when config is a function, pass the env from args to the config function 
  12.         options[i] = await options[i](argv.env, argv); 
  13.       } 
  14.     }), 
  15.   ); 
  16. else { 
  17.   // 單線打包 
  18.   if (typeof options.then === "function") { 
  19.     options = await options; 
  20.   } 
  21.  
  22.   // `Promise` may return `Function
  23.   if (typeof options === "function") { 
  24.     // when config is a function, pass the env from args to the config function 
  25.     options = await options(argv.env, argv); 
  26.   } 

默認(rèn)使用的就是單一入口打包的方式,所以這里最終會(huì)執(zhí)行其中的SingleEntryPlugin。

  • SingleEntryPlugin中調(diào)用了Compilation對(duì)象的addEntry方法,開始解析入口。
  • addEntry方法中又調(diào)用了_addModuleChain方法,將入口模塊添加到模塊依賴列表。
  • 然后通過(guò)Compilation對(duì)象的buildModule方法進(jìn)行模塊構(gòu)建
  • buildModule方法中執(zhí)行具體的Loader,處理特殊資源加載
  • build完成后,通過(guò)acorn庫(kù)生成模塊代碼的AST語(yǔ)法樹
  • 根據(jù)語(yǔ)法樹分析這個(gè)模塊是否還有依賴的模塊,如果有則繼續(xù)循環(huán)build每個(gè)依賴
  • 所有依賴解析完成,build階段結(jié)束
  • 最后合并生成需要輸出的bundle.js寫入目錄

參考文章

《webpack原理與實(shí)踐》

《webpack中文文檔》

寫在最后

 

本文主要說(shuō)明了webpack的工作過(guò)程和原理是如何實(shí)現(xiàn)的,并且對(duì)部分源碼進(jìn)行了分析,源碼相當(dāng)于牛津詞典,你不可能專門單獨(dú)設(shè)定時(shí)間去閱讀,而應(yīng)該是需要什么查閱什么,帶著目的性去學(xué)習(xí)。

 

責(zé)任編輯:武曉燕 來(lái)源: 前端萬(wàn)有引力
相關(guān)推薦

2021-12-15 23:42:56

Webpack原理實(shí)踐

2021-12-19 07:21:48

Webpack 前端插件機(jī)制

2021-12-16 22:02:28

webpack原理模塊化

2021-12-24 08:01:44

Webpack優(yōu)化打包

2019-08-15 10:17:16

Webpack運(yùn)行瀏覽器

2015-11-16 11:17:30

PHP底層運(yùn)行機(jī)制原理

2021-12-25 22:29:04

WebpackRollup 前端

2021-12-22 22:44:49

Webpack熱替換模塊

2021-12-17 00:02:28

Webpack資源加載

2017-05-31 13:16:35

PHP運(yùn)行機(jī)制原理解析

2020-08-05 08:21:41

Webpack

2017-05-02 16:29:11

Webpack技巧建議

2017-03-24 10:56:21

Webpack技巧建議

2021-12-21 14:00:25

WebpackDevServer的開發(fā)

2021-09-13 09:40:35

Webpack 前端HMR 原理

2010-05-06 17:54:54

Oracle鎖

2021-05-31 05:36:43

WebpackJavaScript 前端

2021-04-19 10:45:52

Webpack熱更新前端

2021-08-26 10:30:29

WebpackTree-Shakin前端

2025-03-07 10:23:46

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)