每天讀一點webpack-001

彭博發表於2021-10-16

每天讀一點webpack

day-01-webpack入口

  • npm包我們可以通過package.json中的包資訊檔案快速的定位到這個包的入口檔案,通過webpack的包資訊main欄位可以得到整個webpack專案的入口位置為 lib/index.js

入口檔案

  • 入口檔案中通過動態匯入的方式將專案的各個模組進行整合,如各種內部外掛,內部依賴,內部配置資訊等。

包的快取

  • 在入口檔案中通過一個快取方法lazyFunctionwebpack 這個模組進行了快取操作,其中原始碼如下

    // 通過 lazyFunction 對指定包進行快取操作
    const fn = lazyFunction(() => require("./webpack"));
  • 如何實現包的快取?lazyFunction 其實是使用了閉包的方式對包進行了快取。先看關鍵原始碼,memoize 方法通過閉包的方式將入參中函式fn的執行結果快取起來,這樣在下次想要獲取fn函式的返回結果時就無需在執行fn方法了。

    const memoize = fn => {
    let cache = false
    let result = undefined
    // 返回一個函式 構造一個 閉包,用於快取 fn 函式的返回值
    return () => {
      if(cache) {
        return result
      }else {
        result = fn()
        cache = true
        return result
      }
    }
    }
  • lazyFunction只是對以上memoize方法的簡單封裝,使得其返回的方法支援引數傳遞,實際上相當於一次柯里化處理。但是 memoize 中並沒有接受其傳入的引數,因此此次封裝並無效果。其實可以直接將memoize方法進行一步改造,讓其作為返回值的函式接受入參,並傳遞給fn函式即可達到預期效果,

    const lazyFunction = factory => {
      const fac = memoize(factory);
      const f = (...args) => {
          return fac()(...args);
      }
      return f;
    };

包的合併

  • 入口檔案中並沒有簡單對依賴進行組合,而是通過mergeExports方法對各個模組進行了組裝。該方法主要通過Object.defineProperty來達到物件組裝的目的,這樣做的目的是,可以更好的對物件的屬性進行控制,如屬性的讀、寫、刪除、列舉。相關原始碼如下

    • getOwnPropertyDescriptors 用於獲取物件上 所有屬性的描述符
    • 該方法中使用了遞迴的方式將 物件型別的屬性平鋪開來,這樣使得 原始碼模組特間關係可以保持的同時,降低了模組功能應用的複雜性

      const mergeExports = (obj, exports) => {
      const descriptors = Object.getOwnPropertyDescriptors(exports);
      for (const name of Object.keys(descriptors)) {
          const descriptor = descriptors[name];
          if (descriptor.get) {
              const fn = descriptor.get;
              Object.defineProperty(obj, name, {
                  configurable: false,
                  enumerable: true,
                  get: memoize(fn)
              });
          } else if (typeof descriptor.value === "object") {
              Object.defineProperty(obj, name, {
                  configurable: false,
                  enumerable: true,
                  writable: false,
          // 通過遞迴的方式將 物件型別的 屬性 平鋪開來
                  value: mergeExports({}, descriptor.value)
              });
          } else {
              throw new Error(
                  "Exposed values must be either a getter or an nested object"
              );
          }
      }
      return /** @type {A & B} */ (Object.freeze(obj));
      };

相關文章