摘要:的編譯構建上一篇文章詳解中介紹了基于事件流編程,是個高度的插件集合,整體介紹了的編譯流程。本文將多帶帶聊一聊最核心的部分,編譯構建。的編譯重要的構建節點的構建中總會經歷如下幾個事件節點。
webpack的編譯&構建
上一篇文章webpack詳解中介紹了webpack基于事件流編程,是個高度的插件集合,整體介紹了webpack 的編譯流程。本文將多帶帶聊一聊最核心的部分,編譯&構建。
webpack的編譯 重要的構建節點webpack的構建中總會經歷如下幾個事件節點。
before-run 清除緩存
run 注冊緩存數據鉤子
compile 開始編譯
make 從入口分析依賴以及間接依賴模塊,創建模塊對象
build-module 模塊構建
seal 構建結果封裝, 不可再更改
after-compile 完成構建,緩存數據
emit 輸出到dist目錄
其中make是整個構建中最核心的部分編譯,通過模塊工廠函數創建模塊,然后對模塊進行編譯。
在make鉤子的編譯
上圖中提到的*ModuleFactory是指模塊工廠函數,之所以會有模塊工廠這樣的函數,還要從webpack中entry的配置說起,在webpack的配置項中entry支持如下類型:
字符類型string
字符數組類型[string]
多頁面對象key-value類型object {
也支持一個函數,返回構建的入口(function: () => string | [string] | object {
為了處理以后不同類型的入口模塊,所以就需要個模塊工廠來處理不同的入口模塊類型。
singleEntry: string|object {
multiEntry: [string]|object {
dynamicEntry: (function: () => string | [string] | object {
上圖中為了簡單說明構建的流程,就以最直接的singleEntry類型說起,對于此類入口模塊,webpack均使用NormalModuleFactory來創建模塊,這個創建的模塊的類型叫NormalModule,在NormalModule中實現了模塊的構建方法build,使用runLoaders對模塊進行加載,然后利用進行解析,分析模塊依賴,遞歸構建。
構建封裝seal到構建封裝階段時候,代碼構建已經完畢,但是如何將這些代碼按照依賴引用邏輯組織起來,當瀏覽器將你構建出來的代碼加載到瀏覽器的時候,仍然能夠正確執行。在webpack中通過Manifest記錄各個模塊的詳細要點,通過Runtime來引導,加載執行模塊代碼,特別是異步加載。
Runtime如上所述,我們這里只簡略地介紹一下。runtime,以及伴隨的 manifest 數據,主要是指:在瀏覽器運行時,webpack 用來連接模塊化的應用程序的所有代碼。runtime 包含:在模塊交互時,連接模塊所需的加載和解析邏輯。包括瀏覽器中的已加載模塊的連接,以及懶加載模塊的執行邏輯。
Manifest那么,一旦你的應用程序中,形如 index.html 文件、一些 bundle 和各種資源加載到瀏覽器中,會發生什么?你精心安排的 /src 目錄的文件結構現在已經不存在,所以 webpack 如何管理所有模塊之間的交互呢?這就是 manifest 數據用途的由來……
當編譯器(compiler)開始執行、解析和映射應用程序時,它會保留所有模塊的詳細要點。這個數據集合稱為 "Manifest",當完成打包并發送到瀏覽器時,會在運行時通過 Manifest 來解析和加載模塊。無論你選擇哪種模塊語法,那些 import 或 require 語句現在都已經轉換為 webpack_require 方法,此方法指向模塊標識符(module identifier)。通過使用 manifest 中的數據,runtime 將能夠查詢模塊標識符,檢索出背后對應的模塊。
定義了一個立即執行函數,聲明了__webpack_require__,對各種模塊進行加載。
(function(modules) { // webpackBootstrap var installedModules = {}; // cache module function __webpack_require__(moduleId) { // 模塊加載 // Check if module is in cache if (installedModules[moduleId]) { return installedModules[moduleId].exports; } // Create a new module (and put it into the cache) var module = installedModules[moduleId] = { i: moduleId, l: false, exports: {} }; // Execute the module function modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); // Flag the module as loaded module.l = true; // Return the exports of the module return module.exports; } // expose the modules object (__webpack_modules__) __webpack_require__.m = modules; // expose the module cache __webpack_require__.c = installedModules; // define getter function for harmony exports __webpack_require__.d = function(exports, name, getter) { if (!__webpack_require__.o(exports, name)) { Object.defineProperty(exports, name, { configurable: false, enumerable: true, get: getter }); } }; // getDefaultExport function for compatibility with non-harmony modules __webpack_require__.n = function(module) { var getter = module && module.__esModule ? function getDefault() { return module["default"]; } : function getModuleExports() { return module; }; __webpack_require__.d(getter, "a", getter); return getter; }; // Object.prototype.hasOwnProperty.call __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; // __webpack_public_path__ __webpack_require__.p = ""; // Load entry module and return exports return __webpack_require__(__webpack_require__.s = 0); })([/**modules*/])
上面提到的代碼片段便是webpack構建后在瀏覽器中執行的引導代碼。也就是上面提到的runtime。它是個立即執行函數,那么入參modules便是上面的Manifest,組織各個模塊的依賴邏輯。
(function(modules){ // ... // runtime function __webpack_require__(moduleId) { // 加載邏輯 } // ... })([function (module, exports, __webpack_require__) { var chunk1 = __webpack_require__(1); var chunk2 = __webpack_require__(2); }, function (module, exports, __webpack_require__) { __webpack_require__(2); var chunk1 = 1; exports.chunk1 = chunk1; }, function (module, exports) { var chunk2 = 1; exports.chunk2 = chunk2; }])
上面說到了runtime和manifest就是在seal階段注入的
class Compilation extends Tapable { seal(callback) { this.hooks.seal.call(); // ... if (this.hooks.shouldGenerateChunkAssets.call() !== false) { this.hooks.beforeChunkAssets.call(); this.createChunkAssets(); } // ... } createChunkAssets() { // ... for (let i = 0; i < this.chunks.length; i++) { const chunk = this.chunks[i]; // ... const template = chunk.hasRuntime() ? this.mainTemplate : this.chunkTemplate; // 根據是否有runTime選擇模塊,入口文件是true, 需要異步加載的文件則沒有 const manifest = template.getRenderManifest({ // 生成manifest chunk, hash: this.hash, fullHash: this.fullHash, outputOptions, moduleTemplates: this.moduleTemplates, dependencyTemplates: this.dependencyTemplates }); // [{ render(), filenameTemplate, pathOptions, identifier, hash }] // ... } }
通過template最后將代碼組織起來,上面看到的構建后的代碼就是mainTemplate生成的。
寫在最后通過template生成最后代碼,構建已經完成,接下來就是將代碼輸出到dist 目錄。
最后騰訊IVWEB團隊的工程化解決方案feflow已經開源:Github主頁:https://github.com/feflow/feflow
如果對您的團隊或者項目有幫助,請給個Star支持一下哈~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93927.html
摘要:那時候所配置的任務監聽匹配文件的變化自動刷新瀏覽器自動編譯自動補全前綴多雪碧圖合并拼圖等等基于編譯圖片的任務,已經是完全滿足我們的需求了。直至到后來在雪碧圖的合并,多倍圖的輸出上,在上苦苦找尋不了比較完美的解決方案等等。 折騰 從 2015 到現在,短短的三年內,幾乎每年折騰一下工作流的 更新換代 。從最早開始使用 Grunt 到 Gulp 再到 Webpack,再到 Rollup,...
摘要:原理踩坑起因最近在做框架的熱更新,記錄一下的原理和小坑。文件系統接收更改并通知。運行時通過請求這些更新。類似的問題還有很多,事件綁定手動插入并且沒有銷毀的定時器等,記得把這些副作用一起干掉。參考官方文檔原理分析與實現 webpack hot-module-replacement 原理&踩坑 起因 最近在做san框架的熱更新,記錄一下webpack HMR的原理和小坑。 什么是HMR? ...
摘要:在年成為最大贏家,贏得了實現的風暴之戰。和他的競爭者位列第二沒有前端開發者可以忽視和它的生態系統。他的殺手級特性是探測功能,通過檢查任何用戶的功能,以直觀的方式讓開發人員檢查所有端點。 2016 JavaScript 后起之秀 本文轉載自:眾成翻譯譯者:zxhycxq鏈接:http://www.zcfy.cc/article/2410原文:https://risingstars2016...
摘要:徹底分離源文件目錄和生成文件目錄使用生成出來的頁面可以很安心地跟打包好的其它資源放到一起,相對于另起一個目錄專門存放頁面文件來說,整個文件目錄結構更加合理如何利用生成頁面生成頁面主要是通過來實現的,下面來介紹如何實現。 本文首發于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。原文地址:https://segmentfault.com/a/119000000712...
摘要:本質上是一個可以模塊化使用的加載處理的函數。本文著重討論以作為樣本分析。下面一幅圖分別是單和雙編譯結果圖。總結通過簡單的例子復習了編譯后的文件執行流程探索了編譯流程研究意義還是有的。相關問題參考鏈接參考鏈接 引言 在回答一個問題時,引發一些疑問,分析總結下,作為備忘 webpack webpack對于我來說,應用場景主要是,編譯打包我通過模塊化組織書寫的文件,用其提供的各種loader...
閱讀 1040·2019-08-30 12:57
閱讀 2114·2019-08-30 11:11
閱讀 2177·2019-08-29 15:20
閱讀 1870·2019-08-29 14:12
閱讀 3274·2019-08-28 17:51
閱讀 2378·2019-08-26 13:23
閱讀 789·2019-08-26 10:34
閱讀 3844·2019-08-23 12:37