日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

玩转webpack(一)下篇:webpack的基本架构和构建流程

發布時間:2025/3/18 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 玩转webpack(一)下篇:webpack的基本架构和构建流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

歡迎大家前往騰訊云社區,獲取更多騰訊海量技術實踐干貨哦~

作者:QQ會員技術團隊

接玩轉webpack(一)上篇:webpack的基本架構和構建流程

文件生成階段

這個階段的主要內容,是根據 chunks 生成最終文件。主要有三個步驟:模板 hash 更新,模板渲染 chunk,生成文件

Compilation 在實例化的時候,就會同時實例化三個對象:MainTemplate, ChunkTemplate,ModuleTemplate。這三個對象是用來渲染 chunk 對象,得到最終代碼的模板。第一個對應了在 entry 配置的入口 chunk 的渲染模板,第二個是動態引入的非入口 chunk 的渲染模板,最后是 chunk 中的 module 的渲染模板。

在開始渲染之前,Compilation 實例會調用 createHash 方法來生成這次構建的 hash。在 webpack 的配置中,我們可以在 output.filename 中配置 [hash] 占位符,最終就會替換成這個 hash。同樣,createHash 也會為每一個 chunk 也創建一個 hash,對應 output.filename 的 [chunkhash] 占位符。

每個 hash 的影響因素比較多,首先三個模板對象會調用 updateHash 方法來更新 hash,在內部還會觸發任務點 hash,傳遞 hash 到其他插件。 chunkhash 也是類似的原理:

// https://github.com/webpack/webpack/blob/master/lib/Compilation.jsclass Compilation extends Tapable {// 其他代碼..createHash() {// 其他代碼..const hash = crypto.createHash(hashFunction);if(outputOptions.hashSalt)hash.update(outputOptions.hashSalt);this.mainTemplate.updateHash(hash);this.chunkTemplate.updateHash(hash);this.moduleTemplate.updateHash(hash);// 其他代碼..for(let i = 0; i < chunks.length; i++) {const chunk = chunks[i];const chunkHash = crypto.createHash(hashFunction);if(outputOptions.hashSalt)chunkHash.update(outputOptions.hashSalt);chunk.updateHash(chunkHash);if(chunk.hasRuntime()) {this.mainTemplate.updateHashForChunk(chunkHash, chunk);} else {this.chunkTemplate.updateHashForChunk(chunkHash, chunk);}this.applyPlugins2("chunk-hash", chunk, chunkHash);chunk.hash = chunkHash.digest(hashDigest);hash.update(chunk.hash);chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);}this.fullHash = hash.digest(hashDigest);this.hash = this.fullHash.substr(0, hashDigestLength);} }

當 hash 都創建完成之后,下一步就會遍歷 compilation.chunks 來渲染每一個 chunk。如果一個 chunk 是入口 chunk,那么就會調用 MainTemplate 實例的 render 方法,否則調用 ChunkTemplate 的 render 方法:

// https://github.com/webpack/webpack/blob/master/lib/Compilation.jsclass Compilation extends Tapable {// 其他代碼..createChunkAssets() {// 其他代碼..for(let i = 0; i < this.chunks.length; i++) {const chunk = this.chunks[i];// 其他代碼..if(chunk.hasRuntime()) {source = this.mainTemplate.render(this.hash, chunk, this.moduleTemplate, this.dependencyTemplates);} else {source = this.chunkTemplate.render(chunk, this.moduleTemplate, this.dependencyTemplates);}file = this.getPath(filenameTemplate, {noChunkHash: !useChunkHash,chunk});this.assets[file] = source;// 其他代碼..}} }

這里注意到 ModuleTemplate 實例會被傳遞下去,在實際渲染時將會用 ModuleTemplate 來渲染每一個 module,其實更多是往 module 前后添加一些"包裝"代碼,因為 module 的源碼實際上是已經渲染完畢的(還記得前面的 loaders 應用嗎?)。

MainTemplate 的渲染跟 ChunkTemplate 的不同點在于,入口 chunk 的源碼中會帶有啟動 webpack 的代碼,而非入口 chunk 的源碼是不需要的。這個只要查看 webpack 構建后的文件就可以比較清楚地看到區別:

// 入口 chunk /******/ (function(modules) { // webpackBootstrap /******/ // install a JSONP callback for chunk loading /******/ var parentJsonpFunction = window["webpackJsonp"]; /******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) { /******/ // add "moreModules" to the modules object, /******/ // then flag all "chunkIds" as loaded and fire callback /******/ var moduleId, chunkId, i = 0, resolves = [], result; /******/ for(;i < chunkIds.length; i++) { /******/ chunkId = chunkIds[i]; /******/ if(installedChunks[chunkId]) { /******/ resolves.push(installedChunks[chunkId][0]); /******/ } /******/ installedChunks[chunkId] = 0; /******/ } /******/ for(moduleId in moreModules) { /******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { /******/ modules[moduleId] = moreModules[moduleId]; /******/ } /******/ } /******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules); /******/ while(resolves.length) { /******/ resolves.shift()(); /******/ } /******/ /******/ }; /******/ // 其他代碼.. /******/ })(/* modules代碼 */);// 動態引入的 chunk webpackJsonp([0],[/* modules代碼.. */ ]);

當每個 chunk 的源碼生成之后,就會添加在 Compilation 實例的 assets 屬性中。

assets 對象的 key 是最終要生成的文件名稱,因此這里要用到前面創建的 hash。調用 Compilation 實例內部的 getPath 方法會根據配置中的 output.filename 來生成文件名稱。

assets 對象的 value 是一個對象,對象需要包含兩個方法,source 和 size 分別返回文件內容和文件大小。

當所有的 chunk 都渲染完成之后,assets 就是最終更要生成的文件列表。此時 Compilation 實例還會觸發幾個任務點,例如 addtional-chunk-assets,addintial-assets等,在這些任務點可以修改 assets 屬性來改變最終要生成的文件。

完成上面的操作之后,Compilation 實例的 seal 方法結束,進入到 Compiler 實例的 emitAssets 方法。Compilation 實例的所有工作到此也全部結束,意味著一次構建過程已經結束,接下來只有文件生成的步驟。

在 Compiler 實例開始生成文件前,最后一個修改最終文件生成的任務點 emit 會被觸發:

// 監聽 emit 任務點,修改最終文件的最后機會 compiler.plugin("emit", (compilation, callback) => {let data = "abcd"compilation.assets["newFile.js"] = {source() {return data}size() {return data.length}} })

當任務點 emit 被觸發之后,接下來 webpack 會直接遍歷 compilation.assets 生成所有文件,然后觸發任務點 done,結束構建流程。

總結

經過全文的討論,我們將 webpack 的基本架構以及核心的構建流程都過了一遍,希望在閱讀完全文之后,對大家了解 webpack 原理有所幫助。
最后再次說明,本文內容是由個人理解和整理,如果有不正確的地方歡迎大家指正。如果需要轉載,請注明出處。

下一篇文章將會講解 webpack 核心的對象,敬請期待。

本文來源于 小時光茶社 微信公眾號

相關閱讀

玩轉webpack(一)上篇:webpack的基本架構和構建流程
Webpack + vue 之抽離 CSS 的正確姿勢
使用Yeoman generator來規范工程的初始化

此文已由作者授權騰訊云技術社區發布,轉載請注明原文出處
原文鏈接:https://cloud.tencent.com/com...

總結

以上是生活随笔為你收集整理的玩转webpack(一)下篇:webpack的基本架构和构建流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。