成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Webpack原理與實踐之Webpack運行機制與核心工作原理

開發 前端
對于依賴模塊中無法通過js代碼表示的資源模塊,例如圖片或字體文件,一般的Loader會將它們單獨作為資源文件拷貝到輸出目錄中,然后將這個資源文件所對應的訪問路徑作為這個模塊的導出成員暴露給外部。

[[441145]]

寫在前面

Webpack在整個打包過程中:

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

通過plugin實現各種自動化的構建任務,例如自動壓縮、自動發布

那么webpack的工作過程和原理又是如何實現的呢?

Webpack的工作過程

首先webpack會加載入口文件js,通過分析代碼中import、require等去解析依賴,然后通過依賴形成依賴關系樹,webpack會去遍歷依賴關系樹,去加載所依賴的資源模塊。webpack會通過Loader配置去加載模塊,通過plugins實現自動化構建。

對于依賴模塊中無法通過js代碼表示的資源模塊,例如圖片或字體文件,一般的Loader會將它們單獨作為資源文件拷貝到輸出目錄中,然后將這個資源文件所對應的訪問路徑作為這個模塊的導出成員暴露給外部。

webpack在每個打包環節都預留了鉤子,我們可以通過plugins去配置其所依賴的插件。

具體的:

  • Webpack cli啟動打包流程
  • 載入Webpack核心模塊,創建Compiler對象
  • 使用創建Compiler對象開始編譯整個項目
  • 從入口文件開始,解析模塊依賴,形成依賴關系樹
  • 遞歸遍歷依賴樹,將每個模塊交給對應的loader處理
  • 合并loader處理完的結果,將打包結果輸出到dist目錄

Webpack cli的作用是將cli參數和webpack配置文件中的配置進行整合得到一個完整的配置對象。Webpack cli會通過yargs模塊解析cli參數,運行webpack命令時通過命令行傳入的參數。

  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.       // 按照配置文件規則找到加載配置文件 
  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核心模塊,傳入配置選項,創建Compiler對象。

  1. // 創建Compiler對象的函數 
  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.     // 開始調用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階段主體的目標是:根據entry配置找到入口模塊,開始依次遞歸出所有依賴,形成依賴關系樹,然后遞歸到的每個模塊交給不同的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.   } 

默認使用的就是單一入口打包的方式,所以這里最終會執行其中的SingleEntryPlugin。

  • SingleEntryPlugin中調用了Compilation對象的addEntry方法,開始解析入口。
  • addEntry方法中又調用了_addModuleChain方法,將入口模塊添加到模塊依賴列表。
  • 然后通過Compilation對象的buildModule方法進行模塊構建
  • buildModule方法中執行具體的Loader,處理特殊資源加載
  • build完成后,通過acorn庫生成模塊代碼的AST語法樹
  • 根據語法樹分析這個模塊是否還有依賴的模塊,如果有則繼續循環build每個依賴
  • 所有依賴解析完成,build階段結束
  • 最后合并生成需要輸出的bundle.js寫入目錄

參考文章

《webpack原理與實踐》

《webpack中文文檔》

寫在最后

 

本文主要說明了webpack的工作過程和原理是如何實現的,并且對部分源碼進行了分析,源碼相當于牛津詞典,你不可能專門單獨設定時間去閱讀,而應該是需要什么查閱什么,帶著目的性去學習。

 

責任編輯:武曉燕 來源: 前端萬有引力
相關推薦

2021-12-15 23:42:56

Webpack原理實踐

2021-12-16 22:02:28

webpack原理模塊化

2021-12-19 07:21:48

Webpack 前端插件機制

2021-12-24 08:01:44

Webpack優化打包

2019-08-15 10:17:16

Webpack運行瀏覽器

2015-11-16 11:17:30

PHP底層運行機制原理

2021-12-17 00:02:28

Webpack資源加載

2021-12-25 22:29:04

WebpackRollup 前端

2021-12-22 22:44:49

Webpack熱替換模塊

2020-08-05 08:21:41

Webpack

2017-05-31 13:16:35

PHP運行機制原理解析

2017-03-24 10:56:21

Webpack技巧建議

2017-05-02 16:29:11

Webpack技巧建議

2021-12-21 14:00:25

WebpackDevServer的開發

2021-09-13 09:40:35

Webpack 前端HMR 原理

2021-04-19 10:45:52

Webpack熱更新前端

2021-05-31 05:36:43

WebpackJavaScript 前端

2010-05-06 17:54:54

Oracle鎖

2021-08-26 10:30:29

WebpackTree-Shakin前端

2022-08-26 13:24:03

version源碼sources
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 天天操天天怕 | 国产欧美视频一区二区 | 精品国产一区一区二区三亚瑟 | 97综合在线 | 中文在线一区 | 国产黄色大片 | 久久国产精品视频 | 青娱乐av | 国产精品免费一区二区三区四区 | 午夜国产 | 久久免费高清视频 | 久久久这里都是精品 | 国产高清一区二区 | 日韩在线精品视频 | av片免费 | 欧美成人精品在线观看 | 久久久久久99 | 亚洲人成人一区二区在线观看 | 日韩精品一区二区三区中文在线 | 亚洲视频一 | 91久久久久久久久久久 | 欧美日韩黄色一级片 | 免费性视频| 日韩亚洲视频 | 国产一区二区三区视频在线观看 | 久草福利 | 嫩草视频网站 | 国产欧美一区二区三区久久 | 欧美极品在线视频 | 亚洲网站在线观看 | 欧美精品免费观看二区 | 日韩羞羞 | 欧美成人精品在线观看 | 中文字幕不卡在线观看 | 午夜视频网站 | 99tv | 国产精品久久久久久久久久免费看 | 久久久久国产精品一区二区 | 亚洲成人福利视频 | 国产精品成人品 | 欧美日韩高清一区 |