国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Webpack 是怎樣運(yùn)行的?

wangshijun / 2833人閱讀

摘要:它打包開(kāi)發(fā)代碼,輸出能在各種瀏覽器運(yùn)行的代碼,提升了開(kāi)發(fā)至發(fā)布過(guò)程的效率。下面我們來(lái)通過(guò)一個(gè)簡(jiǎn)單的項(xiàng)目來(lái)看一下是怎樣運(yùn)行的。至此,基本的模塊執(zhí)行過(guò)程就結(jié)束了。是的原生將加入全局?jǐn)?shù)組,緩存內(nèi)容執(zhí)行后,加載的狀態(tài)變?yōu)椋瑑?nèi)的函數(shù)開(kāi)始執(zhí)行。

在平時(shí)開(kāi)發(fā)中我們經(jīng)常會(huì)用到Webpack這個(gè)時(shí)下最流行的前端打包工具。它打包開(kāi)發(fā)代碼,輸出能在各種瀏覽器運(yùn)行的代碼,提升了開(kāi)發(fā)至發(fā)布過(guò)程的效率。

我們知道一份Webpack配置文件主要包含入口(entry)、輸出文件(output)、模式、加載器(Loader)、插件(Plugin)等幾個(gè)部分。但如果只需要組織 JS 文件的話,指定入口和輸出文件路徑即可完成一個(gè)迷你項(xiàng)目的打包。下面我們來(lái)通過(guò)一個(gè)簡(jiǎn)單的項(xiàng)目來(lái)看一下Webpack是怎樣運(yùn)行的。

同步加載
本文使用 webpack ^4.30.0 作示例.為了更好地觀察產(chǎn)出的文件,我們將模式設(shè)置為 development 關(guān)閉代碼壓縮,再開(kāi)啟 source-map 支持原始源代碼調(diào)試。除此之外。我們還簡(jiǎn)單的寫(xiě)了一個(gè)插件MyPlugin來(lái)去除源碼中的注釋。

新建src/index.js

console.log("Hello webpack!");

新建webpack配置文件webpack.config.js

const path = require("path");
const MyPlugin = require("./src/MyPlugin.js")

module.exports = {
  mode: "development",
  devtool: "source-map",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist")
  },
  plugins:[
    new MyPlugin()
  ]
};

新建src/MyPlugin.js。了解webpack插件更多信息

class MyPlugin {
  constructor(options) {
    this.options = options
    this.externalModules = {}
  }

  apply(compiler) {
    var reg = /("([^"]*(.)?)*")|("([^"]*(.)?)*")|(/{2,}.*?(
|
))|(/*(
|.)*?*/)|(/******/)/g
    compiler.hooks.emit.tap("CodeBeautify", (compilation)=> {
      Object.keys(compilation.assets).forEach((data)=> {
        let content = compilation.assets[data].source() // 欲處理的文本
        content = content.replace(reg, function (word) { // 去除注釋后的文本
          return /^/{2,}/.test(word) || /^/*!/.test(word) || /^/*{3,}//.test(word) ? "" : word;
        });
        compilation.assets[data] = {
          source(){
            return content
          },
          size(){
            return content.length
          }
        }
      })
    })
  }
}
module.exports = MyPlugin

現(xiàn)在我們運(yùn)行命令 webpack --config webpack.config.js ,打包完成后會(huì)多出一個(gè)輸出目錄 distdist/main.jsmainwebpack 默認(rèn)設(shè)置的輸出文件名,我們快速瞄一眼這個(gè)文件:

(function(modules){
  // ...
})({
  "./src/index.js": (function(){
    // ...
  })
});

整個(gè)文件只含一個(gè)立即執(zhí)行函數(shù)(IIFE),我們稱它為 webpackBootstrap,它僅接收一個(gè)對(duì)象 —— 未加載的 模塊集合(modules),這個(gè) modules 對(duì)象的 key 是一個(gè)路徑,value 是一個(gè)函數(shù)。你也許會(huì)問(wèn),這里的模塊是什么?它們又是如何加載的呢?
在細(xì)看產(chǎn)出代碼前,我們先豐富一下源代碼:
新文件 src/utils/math.js

export const plus = (a, b) => {
  return a + b;
};

修改src/index.js

import { plus } from "./utils/math.js";

console.log("Hello webpack!");
console.log("1 + 2: ", plus(1, 2));

我們按照 ES 規(guī)范的模塊化語(yǔ)法寫(xiě)了一個(gè)簡(jiǎn)單的模塊 src/utils/math.js,給 src/index.js 引用。Webpack 用自己的方式支持了 ES6 Module 規(guī)范,前面提到的 module 就是和 ES6 module 對(duì)應(yīng)的概念。

接下來(lái)我們看一下這些模塊是如何通 ES5 代碼實(shí)現(xiàn)的。再次運(yùn)行命令 webpack --config webpack.config.js 后查看輸出文件:

(function(modules){
  // ...
})({
  "./src/index.js": (function(){
    // ...
  }),
  "./src/utils/math.js": (function() {
    // ...
  })
});

IIFE 傳入的 modules 對(duì)象里多了一個(gè)鍵值對(duì),對(duì)應(yīng)著新模塊 src/utils/math.js,這和我們?cè)谠创a中拆分的模塊互相呼應(yīng)。然而,有了 modules 只是第一步,這份文件最終達(dá)到的效果應(yīng)該是讓各個(gè)模塊按開(kāi)發(fā)者編排的順序運(yùn)行。

探究 webpackBootstrap

接下來(lái)看看 webpackBootstrap 函數(shù)中有些什么:

// webpackBootstrap
(function(modules){

  // 緩存 __webpack_require__ 函數(shù)加載過(guò)的模塊
  var installedModules = {};

  /**
   * Webpack 加載函數(shù),用來(lái)加載 webpack 定義的模塊
   * @param {String} moduleId 模塊 ID,一般為模塊的源碼路徑,如 "./src/index.js"
   * @returns {Object} exports 導(dǎo)出對(duì)象
   */
  function __webpack_require__(moduleId) {
    // ...
  }

  // 在 __webpack_require__ 函數(shù)對(duì)象上掛載一些變量及函數(shù) ...

  // 傳入表達(dá)式的值為 "./src/index.js"
  return __webpack_require__(__webpack_require__.s = "./src/index.js");
})(/* modules */);

可以看到其實(shí)主要做了兩件事:

定義一個(gè)模塊加載函數(shù) __webpack_require__

使用加載函數(shù)加載入口模塊 "./src/index.js"

整個(gè) webpackBootstrap 中只出現(xiàn)了入口模塊的影子,那其他模塊又是如何加載的呢?我們順著 __webpack_require__("./src/index.js") 細(xì)看加載函數(shù)的內(nèi)部邏輯:

function __webpack_require__(moduleId) {
  // 重復(fù)加載則利用緩存
  if (installedModules[moduleId]) {
    return installedModules[moduleId].exports;
  }

  // 如果是第一次加載,則初始化模塊對(duì)象,并緩存
  var module = installedModules[moduleId] = {
    i: moduleId,  // 模塊 ID
    l: false,     // 模塊加載標(biāo)識(shí)
    exports: {}   // 模塊導(dǎo)出對(duì)象
  };

  /**
    * 執(zhí)行模塊
    * @param module.exports -- 模塊導(dǎo)出對(duì)象引用,改變模塊包裹函數(shù)內(nèi)部的 this 指向
    * @param module -- 當(dāng)前模塊對(duì)象引用
    * @param module.exports -- 模塊導(dǎo)出對(duì)象引用
    * @param __webpack_require__ -- 用于在模塊中加載其他模塊
    */
  modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

  // 模塊加載標(biāo)識(shí)置為已加載
  module.l = true;

  // 返回當(dāng)前模塊的導(dǎo)出對(duì)象引用
  return module.exports;
}

首先,加載函數(shù)使用了閉包變量 installedModules,用來(lái)將已加載過(guò)的模塊保存在內(nèi)存中。 接著是初始化模塊對(duì)象,并把它掛載到緩存里。然后是模塊的執(zhí)行過(guò)程,加載入口文件時(shí) modules[moduleId] 其實(shí)就是 ./src/index.js 對(duì)應(yīng)的模塊函數(shù)。執(zhí)行模塊函數(shù)前傳入了跟模塊相關(guān)的幾個(gè)實(shí)參,讓模塊可以導(dǎo)出內(nèi)容,以及加載其他模塊的導(dǎo)出。最后標(biāo)識(shí)該模塊加載完成,返回模塊的導(dǎo)出內(nèi)容。

根據(jù) __webpack_require__ 的緩存和導(dǎo)出邏輯,我們得知在整個(gè) IIFE 運(yùn)行過(guò)程中,加載已緩存的模塊時(shí),都會(huì)直接返回installedModules[moduleId].exports,換句話說(shuō),相同的模塊只有在第一次引用的時(shí)候才會(huì)執(zhí)行模塊本身。

模塊執(zhí)行函數(shù)

__webpack_require__ 中通過(guò) modules[moduleId].call() 運(yùn)行了模塊執(zhí)行函數(shù),下面我們就進(jìn)入到 webpackBootstrap 的參數(shù)部分,看看模塊的執(zhí)行函數(shù)。

/*** 入口模塊 ./src/index.js ***/
"./src/index.js": (function (module, __webpack_exports__, __webpack_require__) {
  "use strict";
// 用于區(qū)分 ES 模塊和其他模塊規(guī)范,不影響理解 demo,戰(zhàn)略跳過(guò)。
  __webpack_require__.r(__webpack_exports__);
  /* harmony import */
 // 源模塊代碼中,`import {plus} from "./utils/math.js";` 語(yǔ)句被 loader 解析轉(zhuǎn)化。
    // 加載 "./src/utils/math.js" 模塊,
  var _utils_math_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/utils/math.js");
  console.log("Hello webpack!");
  console.log("1 + 2: ", Object(_utils_math_js__WEBPACK_IMPORTED_MODULE_0__["plus"])(1, 2));
}),

"./src/utils/math.js": (function (module, __webpack_exports__, __webpack_require__) {
  "use strict";
  __webpack_require__.r(__webpack_exports__);
  /* harmony export (binding) */
// 源模塊代碼中,`export` 語(yǔ)句被 loader 解析轉(zhuǎn)化。
  __webpack_require__.d(__webpack_exports__, "plus", function () {
    return plus;
  });
  const plus = (a, b) => {
    return a + b;
  };
})

執(zhí)行順序是:入口模塊 -> 工具模塊 -> 入口模塊。入口模塊中首先就通過(guò) __webpack_require__("./src/utils/math.js") 拿到了工具模塊的 exports 對(duì)象。再看工具模塊,ES 導(dǎo)出語(yǔ)法轉(zhuǎn)化成了__webpack_require__.d(__webpack_exports__, [key], [getter]),而 __webpack_require__.d 函數(shù)的定義在 webpackBootstrap 內(nèi):

// 定義 exports 對(duì)象導(dǎo)出的屬性。
  __webpack_require__.d = function (exports, name, getter) {

    // 如果 exports (不含原型鏈上)沒(méi)有 [name] 屬性,定義該屬性的 getter。
    if (!__webpack_require__.o(exports, name)) {
      Object.defineProperty(exports, name, {
        enumerable: true,
        get: getter
      });
    }
  };

  // 包裝 Object.prototype.hasOwnProperty 函數(shù)。
  __webpack_require__.o = function (object, property) {
    return Object.prototype.hasOwnProperty.call(object, property);
  };

可見(jiàn) __webpack_require__.d 其實(shí)就是 Object.defineProperty 的簡(jiǎn)單包裝.
引用工具模塊導(dǎo)出的變量后,入口模塊再執(zhí)行它剩余的部分。至此,Webpack 基本的模塊執(zhí)行過(guò)程就結(jié)束了。

好了,我們用流程圖總結(jié)一下 Webpack 模塊的加載思路:

異步加載

有上面的打包我們發(fā)現(xiàn)將不同的打包進(jìn)一個(gè) main.js 文件。main.js 會(huì)集中消耗太多網(wǎng)絡(luò)資源,導(dǎo)致用戶需要等待很久才可以開(kāi)始與網(wǎng)頁(yè)交互。

一般的解決方式是:根據(jù)需求降低首次加載文件的體積,在需要時(shí)(如切換前端路由器,交互事件回調(diào))異步加載其他文件并使用其中的模塊。

Webpack 推薦用 ES import() 規(guī)范來(lái)異步加載模塊,我們根據(jù) ES 規(guī)范修改一下入口模塊的 import 方式,讓其能夠異步加載模塊:

src/index.js

console.log("Hello webpack!");

window.setTimeout(() => {
  import("./utils/math").then(mathUtil => {
  console.log("1 + 2: " + mathUtil.plus(1, 2));
  });
}, 2000);

工具模塊(src/utils/math.js)依然不變,在webpack 配置里,我們指定一下資源文件的公共資源路徑(publicPath),后面的探索過(guò)程中會(huì)遇到。

const path = require("path");
const MyPlugin = require("./src/MyPlugin.js")

module.exports = {
  mode: "development",
  devtool: "source-map",
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    publicPath: "/dist/"
  },
  plugins:[
    new MyPlugin()
  ]
};

接著執(zhí)行一下打包,可以看到除了 dist/main.js 外,又多了一個(gè) dist/0.js ./src/utils/math.js。模塊從main chunk 遷移到了 0 chunk 中。而與 demo1 不同的是,main chunk 中添加了一些用于異步加載的代碼,我們概覽一下:

// webpackBootstrap
(function (modules) {
  // 加載其他 chunk 后的回調(diào)函數(shù)
  function webpackJsonpCallback(data) {
    // ...
  }

  // ...

  // 用于緩存 chunk 的加載狀態(tài),0 為已加載
  var installedChunks = {
    "main": 0
  };

  // 拼接 chunk 的請(qǐng)求地址
  function jsonpScriptSrc(chunkId) {
    // ...
  }

  // 同步 require 函數(shù),內(nèi)容不變
  function __webpack_require__(moduleId) {
    // ...
  }

  // 異步加載 chunk,返回封裝加載過(guò)程的 promise
  __webpack_require__.e = function requireEnsure(chunkId) {
    // ...
  }

  // ...

  // defineProperty 的包裝,內(nèi)容不變
  __webpack_require__.d = function (exports, name, getter) {}

  // ...

  // 根據(jù)配置文件確定的 publicPath
  __webpack_require__.p = "/dist/";

  /**** JSONP 初始化 ****/
  var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
  var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
  jsonpArray.push = webpackJsonpCallback;
  jsonpArray = jsonpArray.slice();
  for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
  var parentJsonpFunction = oldJsonpFunction;
  /**** JSONP 初始化 ****/

  return __webpack_require__(__webpack_require__.s = "./src/index.js");
})({
  "./src/index.js": (function(module, exports, __webpack_require__) {

    document.write("Hello webpack!
");

    window.setTimeout(() => {
      __webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./utils/math */ "./src/utils/math.js")).then(mathUtil => {
        console.log("1 + 2: " + mathUtil.plus(1, 2));
      });
    }, 2000);

  })
})

可以看到 webpackBootstrap 的函數(shù)體部分增加了一些內(nèi)容,參數(shù)部分移除了 "./src/utils/math.js" 模塊。跟著包裹函數(shù)的執(zhí)行順序,我們先聚焦到「JSONP 初始化」部分:

// 存儲(chǔ) jsonp 的數(shù)組,首次運(yùn)行為 []
var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];

// 保存 jsonpArray 的 push 函數(shù),首次運(yùn)行為 Array.prototype.push
var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);

// 將 jsonpArray 的 push 重寫(xiě)為 webpackJsonpCallback (加載其他 chunk 后的回調(diào)函數(shù))
jsonpArray.push = webpackJsonpCallback;

// 將 jsonpArray 重置為正常數(shù)組,push 重置為 Array.prototype.push
jsonpArray = jsonpArray.slice();

// 由于 jsonpArray 為 [],不做任何事
for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);

// Array.prototype.push
var parentJsonpFunction = oldJsonpFunction;

初始化結(jié)束后,變化就是 window 上掛載了一個(gè) webpackJsonp 數(shù)組,它的值為 [];此外,這個(gè)數(shù)組的 push 被改寫(xiě)為 webpackJsonpCallback 函數(shù),我們?cè)诤竺鏁?huì)提到這些準(zhǔn)備工作的作用。

接著是 __webpack_require__ 入口模塊,由于 __webpack_require__ 函數(shù)沒(méi)有改變,我們繼續(xù)觀察入口模塊執(zhí)行函數(shù)有了什么變化。

顯然,import("../utils/math.js") 被轉(zhuǎn)化為__webpack_require__.e(0).then(__webpack_require__.bind(null, "./src/utils/math.js"))。0 是 ./src/utils/math.js 所在 chunk id,「同步加載模塊」的邏輯拆分成了「先加載 chunk,完成后再加載模塊」。

我們翻到 __webpack_require__.e 的定義位置:

__webpack_require__.e = function requireEnsure(chunkId) {
  var promises = [];

  // installedChunks 是在 webpackBootstrap 中維護(hù)的 chunk 緩存
  var installedChunkData = installedChunks[chunkId];

  // chunk 未加載
  if(installedChunkData !== 0) {

    // installedChunkData 為 promise 表示 chunk 加載中
    if(installedChunkData) {
      promises.push(installedChunkData[2]);
    } else {
      /*** 首次加載 chunk: ***/
      // 初始化 promise 對(duì)象
      var promise = new Promise(function(resolve, reject) {
        installedChunkData = installedChunks[chunkId] = [resolve, reject];
      });
      promises.push(installedChunkData[2] = promise);

      // 創(chuàng)建 script 標(biāo)簽加載 chunk
      var head = document.getElementsByTagName("head")[0];
      var script = document.createElement("script");
      var onScriptComplete;

      // ... 省略一些 script 屬性設(shè)置

      // src 根據(jù) publicPath 和 chunkId 拼接
      script.src = jsonpScriptSrc(chunkId);

      // 加載結(jié)束回調(diào)函數(shù),處理 script 加載完成、加載超時(shí)、加載失敗的情況
      onScriptComplete = function (event) {
        script.onerror = script.onload = null; // 避免 IE 內(nèi)存泄漏問(wèn)題
        clearTimeout(timeout);
        var chunk = installedChunks[chunkId];

        // 處理 script 加載完成,但 chunk 沒(méi)有加載完成的情況
        if(chunk !== 0) {
          // chunk 加載中
          if(chunk) {
            var errorType = event && (event.type === "load" ? "missing" : event.type);
            var realSrc = event && event.target && event.target.src;
            var error = new Error("Loading chunk " + chunkId + " failed.
(" + errorType + ": " + realSrc + ")");
            error.type = errorType;
            error.request = realSrc;

            // reject(error)
            chunk[1](error);
          }

          // 統(tǒng)一將沒(méi)有加載的 chunk 標(biāo)記為未加載
          installedChunks[chunkId] = undefined;
        }
      };

      // 設(shè)置 12 秒超時(shí)時(shí)間
      var timeout = setTimeout(function(){
        onScriptComplete({ type: "timeout", target: script });
      }, 120000);

      script.onerror = script.onload = onScriptComplete;
      head.appendChild(script);

      /*** 首次加載 chunk ***/
    }
  }
  return Promise.all(promises);
};

看起來(lái)有點(diǎn)長(zhǎng),我們一步步剖析,先從第一行和最后一行來(lái)看,整個(gè)函數(shù)將異步加載的過(guò)程封裝到了 promise 中,最終導(dǎo)出。

接著從第二行開(kāi)始,installedChunkData 從緩存中取值,顯然首次加載 chunk 時(shí)此處是 undefined。接下來(lái),installedChunkDataundefined 值觸發(fā)了第一層 if 語(yǔ)句的判斷條件。緊接著進(jìn)行到第二層 if 語(yǔ)句,此時(shí)根據(jù)判斷條件走入 else 塊,這里 if 塊里的內(nèi)容我們先戰(zhàn)略跳過(guò),else 里主要有兩塊內(nèi)容,一是 chunk 腳本加載過(guò)程,這個(gè)過(guò)程創(chuàng)建了一個(gè) script 標(biāo)簽,使其請(qǐng)求 chunk所在地址并執(zhí)行 chunk 內(nèi)容;二是初始化 promise ,并用 promise 控制 chunk 文件加載過(guò)程。

不過(guò),我們只在這段 else 代碼塊中找到了 reject 的使用處,也就是在 chunk 加載異常時(shí) chunk[1](error) 的地方,但并沒(méi)發(fā)現(xiàn)更重要的 resolve 的使用地點(diǎn),僅僅是把 resolve 掛在了緩存上(installedChunks[chunkId] = [resolve, reject])

這里的 chunk 文件加載下來(lái)會(huì)發(fā)生什么呢?讓我們打開(kāi)dist/0.js 一探究竟:

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0], {
  "./src/utils/math.js":
    (function (module, __webpack_exports__, __webpack_require__) {

      "use strict";
      __webpack_require__.r(__webpack_exports__);
      /* harmony export (binding) */
      __webpack_require__.d(__webpack_exports__, "plus", function () {
        return plus;
      });
      const plus = (a, b) => {
        return a + b;
      };
    })

}]);

我們發(fā)現(xiàn)了:

久違的 ./src/utils/math.js 模塊

window["webpackJsonp"] 數(shù)組的使用地點(diǎn)

這段代碼開(kāi)始執(zhí)行,把異步加載相關(guān)的 chunk id 與模塊傳給 push 函數(shù)。而前面已經(jīng)提到過(guò),window["webpackJsonp"] 數(shù)組的 push 函數(shù)已被重寫(xiě)為 webpackJsonpCallback 函數(shù),它的定義位置在 webpackBootstrap 中:

function webpackJsonpCallback(data) {
  var chunkIds = data[0];
  var moreModules = data[1];

  // then flag all "chunkIds" as loaded and fire callback
  var moduleId, chunkId, i = 0, resolves = [];

  // 將 chunk 標(biāo)記為已加載
  for(;i < chunkIds.length; i++) {
    chunkId = chunkIds[i];
    if(installedChunks[chunkId]) {
      resolves.push(installedChunks[chunkId][0]);
    }
    installedChunks[chunkId] = 0;
  }

  // 把 "moreModules" 加到 webpackBootstrap 中的 modules 閉包變量中。
  for(moduleId in moreModules) {
    if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
      modules[moduleId] = moreModules[moduleId];
    }
  }

  // parentJsonpFunction 是 window["webpackJsonp"] 的原生 push
  // 將 data 加入全局?jǐn)?shù)組,緩存 chunk 內(nèi)容
  if(parentJsonpFunction) parentJsonpFunction(data);

  // 執(zhí)行 resolve 后,加載 chunk 的 promise 狀態(tài)變?yōu)?resolved,then 內(nèi)的函數(shù)開(kāi)始執(zhí)行。
  while(resolves.length) {
    resolves.shift()();
  }

};

走進(jìn)這個(gè)函數(shù)中,意味著異步加載的 chunk 內(nèi)容已經(jīng)拿到,這個(gè)時(shí)候我們要完成兩件事,一是讓依賴這次異步加載結(jié)果的模塊繼續(xù)執(zhí)行,二是緩存加載結(jié)果。

關(guān)于第一點(diǎn),我們回憶一下之前 __webpack_require__.e 的內(nèi)容,此時(shí) chunk 還處于「加載中」的狀態(tài),也就是說(shuō)對(duì)應(yīng)的 installedChunks[chunkId] 的值此時(shí)為 [resolve, reject, promise]。 而這里,chunk 已經(jīng)加載,但 promise 還未決議,于是 webpackJsonpCallback 內(nèi)部定義了一個(gè) resolves 變量用來(lái)收集 installedChunks 上的 resolve 并執(zhí)行它。

接下來(lái)說(shuō)到第二點(diǎn),就要涉及幾個(gè)層面的緩存了。

首先是 chunk 層面,這里有兩個(gè)相關(guān)操作,操作一將 installedChunks[chunkId] 置為 0 可以讓 __webpack_require__.e 在第二次加載同一 chunk 時(shí)返回一個(gè)立即決議的 promise(Promise.all([]));操作二將 chunk data 添加進(jìn) window["webpackJsonp"] 數(shù)組,可以在多入口模式時(shí),方便地拿到已加載過(guò)的 chunk 緩存。通過(guò)以下代碼實(shí)現(xiàn):

/*** 緩存執(zhí)行部分 ***/
var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
// ...
for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
var parentJsonpFunction = oldJsonpFunction;
/*** 緩存執(zhí)行部分 ***/

/*** 緩存添加部分 ***/
function webpackJsonpCallback(data) {
  //...
    // 此處的 parentJsonpFunction 是 window["webpackJsonp"] 數(shù)組的原生 push
    if (parentJsonpFunction) parentJsonpFunction(data);
  //...
}
/*** 緩存添加部分 ***/

而在 modules 層面,chunk 中的 moreModules 被合入入口文件的 modules 中,可供下一個(gè)微任務(wù)中的 __webpack_require__ 同步加載模塊。

({

  "./src/index.js":
    (function (module, exports, __webpack_require__) {
      console.log("Hello webpack!");
      window.setTimeout(() => {
        __webpack_require__.e(0).then(__webpack_require__.bind(null, "./src/utils/math.js")).then(mathUtil => {
          console.log("1 + 2: " + mathUtil.plus(1, 2));
        });
      }, 2000);
    })
});

__webpack_require__.e(0) 返回的 promise 決議后,__webpack_require__.bind(null, "./src/utils/math.js") 可以加載到 chunk 攜帶的模塊,并返回模塊作為下一個(gè)微任務(wù)函數(shù)的入?yún)ⅲ酉聛?lái)就是 Webpack Loader 翻譯過(guò)的其他業(yè)務(wù)代碼了。

現(xiàn)在讓我們把異步流程梳理一下:

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/109373.html

相關(guān)文章

  • 我他喵到底要怎樣才能在生產(chǎn)環(huán)境中用上 ES6 模塊化?

    摘要:因此,你還是需要各種各樣雜七雜八的工具來(lái)轉(zhuǎn)換你的代碼噢,我可去你媽的吧,這些東西都是干嘛的我就是想用個(gè)模塊化,我到底該用啥子本文正旨在列出幾種可用的在生產(chǎn)環(huán)境中放心使用模塊化的方法,希望能幫到諸位后來(lái)者這方面的中文資源實(shí)在是忒少了。 原文發(fā)表在我的博客上。最近搗鼓了一下 ES6 的模塊化,分享一些經(jīng)驗(yàn) :) Python3 已經(jīng)發(fā)布了九年了,Python 社區(qū)卻還在用 Python 2...

    KaltZK 評(píng)論0 收藏0
  • 單文件組件下vue,可以擦出怎樣火花

    摘要:線上另加入了排行榜功能,如需查看源碼的,請(qǐng)切換到分支整個(gè)項(xiàng)目結(jié)構(gòu)清晰,尤其單文件組件的表現(xiàn)力尤為突出,使得每個(gè)組件的邏輯都沒(méi)有過(guò)于復(fù)雜,而且在的統(tǒng)籌下,的單向數(shù)據(jù)流模式使得所有的變化都在可控制可預(yù)期的范圍內(nèi)。 2016注定不是個(gè)平凡年,無(wú)論是中秋節(jié)問(wèn)世的angular2,還是全面走向穩(wěn)定的React,都免不了面對(duì)另一個(gè)競(jìng)爭(zhēng)對(duì)手vue2。喜歡vue在設(shè)計(jì)思路上的先進(jìn)性(原諒我用了這么一個(gè)...

    Keven 評(píng)論0 收藏0
  • 舒適前端開(kāi)發(fā)環(huán)境怎樣一種體驗(yàn)?

    摘要:那我們有沒(méi)有辦法不刷新頁(yè)面又能看到代碼的更新呢其實(shí)很簡(jiǎn)單,因?yàn)橐呀?jīng)內(nèi)置了這樣的功能,我們只要配置下的注意到上面的代碼,我們?cè)黾恿耍岄_(kāi)發(fā)環(huán)境有了熱更新的能力。 作者:Nicolas (滬江Web前端)本文為原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明作者及出處 本文的 webpack 代碼示例根據(jù) webpack 2.7.0 編寫(xiě),并在 Mac 上正常運(yùn)行。 去年一篇《在 2016 年學(xué) JavaScript...

    weapon 評(píng)論0 收藏0
  • 前端周報(bào)第 19 期

    摘要:本文作者揭開(kāi)的神秘面紗,用簡(jiǎn)單易懂的代碼示例,介紹它的用法優(yōu)劣點(diǎn)和適用場(chǎng)景。深入生成盒子作者主要介紹了和,兩者的區(qū)別和特點(diǎn)。應(yīng)用可使用文件控制環(huán)境變量,這個(gè)工具可以幫你自動(dòng)同步到文件。原文鏈接前端周報(bào)第期 精選 JavaScript Proxy 實(shí)戰(zhàn)指南 ES6 新引入了 Proxy 對(duì)象,它不僅能用在元編程上,還支持了 Vue3.0 新的響應(yīng)式原理,但除此之外我們對(duì) Proxy 的了...

    Benedict Evans 評(píng)論0 收藏0
  • 【譯】一個(gè)小時(shí)搭建一個(gè)全棧Web應(yīng)用框架(上)

    摘要:初始項(xiàng)目設(shè)置我們將使用包管理器來(lái)處理依賴項(xiàng)。使用包管理器可以使您的項(xiàng)目依賴項(xiàng)保持最新?tīng)顟B(tài),并能夠獲取和安裝最新的包。是小型應(yīng)用的最佳選擇之一。 翻譯:瘋狂的技術(shù)宅英文標(biāo)題:Creating a full-stack web application with Python, NPM, Webpack and React英文原文:https://codeburst.io/creating....

    wizChen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<