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

資訊專欄INFORMATION COLUMN

深入理解webpack的require.context

lncwwn / 1653人閱讀

摘要:可以做做不到的事情。看完這段代碼就不難理解文檔中所說的會返回一個帶有個的函數(shù)了。進階深入探究源碼我們知道在版本后,在加載模塊時,可以指定模塊加載模式,我們能使用幾種方式來控制我們要加載的模塊。

前言

require.context 其實是一個非常實用的 api。但是 3-4 年過去了,卻依舊還有很多人不知道如何使用。

而這個 api 主要為我們做什么樣的事情?它可以幫助我們動態(tài)加載我們想要的文件,非常靈活和強大(可遞歸目錄)。可以做 import 做不到的事情。今天就帶大家一起來分析一下,webpack 的 require.context是如何實現(xiàn)的。

準備工作

在分析這個 api 之前呢,我們需要先了解一下一個最簡單的文件,webpack 會編譯成啥樣。

-- src
    -- index.ts
// index.ts
console.log(123)

編譯之后,我們可以看見 webpack 會編譯成如下代碼

// 源碼 https://github.com/MeCKodo/require-context-sourece/blob/master/simple-dist/bundle-only-index.js
 (function(modules) { // webpackBootstrap
     // The module cache
     var installedModules = {};
     // The require function
     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
             });
         }
     };
     // define __esModule on exports
     __webpack_require__.r = function(exports) {
         Object.defineProperty(exports, "__esModule", { value: true });
     };
     // 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 = "./src/index.ts");
 })
 ({
 "./src/index.ts": (function(module, exports) {
      console.log("123");
    })
 });

初次一看是很亂的,所以為了梳理結構,我?guī)痛蠹胰コ恍└疚臒o關緊要的。其實主要結構就是這樣而已,代碼不多為了之后的理解,一定要仔細看下每一行

// 源碼地址 https://github.com/MeCKodo/require-context-sourece/blob/master/simple-dist/webpack-main.js

(function(modules) {
  // 緩存所有被加載過的模塊(文件)
  var installedModules = {};
  // 模塊(文件)加載器 moduleId 一般就是文件路徑
  function __webpack_require__(moduleId) {
    // 走 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: {}
    });
    // 執(zhí)行我們的模塊(文件) 目前就是 ./src/index.ts 并且傳入 3 個參數(shù)
    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;
  }
  // 開始加載入口文件
  return __webpack_require__((__webpack_require__.s = "./src/index.ts"));
})({
  "./src/index.ts": function(module, exports, __webpack_require__) {
    console.log("123");
  }
});

__webpack_require__ 就是一個模塊加載器,而我們所有的模塊都會以對象的形式被讀取加載

modules = {
    "./src/index.ts": function(module, exports, __webpack_require__) {
       console.log("123");
    }
}

我們把這樣的結構先暫時稱之為 模塊結構對象

正片

了解了主體結構之后我們就可以寫一段require.context來看看效果。我們先新增 2 個 ts 文件并且修改一下我們的 index.ts,以便于測試我們的動態(tài)加載。

--- src
    --- demos
        --- demo1.ts
        --- demo2.ts
    index.ts
// index.ts
// 稍后我們通過源碼分析為什么這樣寫
function importAll(contextLoader: __WebpackModuleApi.RequireContext) {
  contextLoader.keys().forEach(id => console.log(contextLoader(id)));
}

const contextLoader = require.context("./demos", true, /.ts/);
importAll(contextLoader);

查看我們編譯后的源碼,發(fā)現(xiàn)多了這樣一塊的 模塊結構對象

// 編譯后代碼地址 https://github.com/MeCKodo/require-context-sourece/blob/master/simple-dist/contex-sync.js#L82-L113
{
"./src/demos sync recursive .ts": function(module, exports, __webpack_require__) {
  var map = {
    "./demo1.ts": "./src/demos/demo1.ts",
    "./demo2.ts": "./src/demos/demo2.ts"
  };

  // context 加載器,通過之前的模塊加載器 加載模塊(文件) 
  function webpackContext(req) {
    var id = webpackContextResolve(req);
    var module = __webpack_require__(id);
    return module;
  }
  
  // 通過 moduleId 查找模塊(文件)真實路徑
  // 個人在這不喜歡 webpack 內部的一些變量命名,moduleId 它都會編譯為 request
  function webpackContextResolve(req) {
    // id 就是真實文件路徑
    var id = map[req];
    // 說實話這波操作沒看懂,目前猜測是 webpack 會編譯成 0.js 1.js 這樣的文件 如果找不到誤加載就出個 error
    if (!(id + 1)) {
      // check for number or string
      var e = new Error("Cannot find module "" + req + "".");
      e.code = "MODULE_NOT_FOUND";
      throw e;
    }
    return id;
  }
  
  // 遍歷得到所有 moduleId
  webpackContext.keys = function webpackContextKeys() {
    return Object.keys(map);
  };
  // 獲取文件真實路徑方法
  webpackContext.resolve = webpackContextResolve;
  // 該模塊就是返回一個 context 加載器
  module.exports = webpackContext;
  // 該模塊的 moduleId 用于 __webpack_require__ 模塊加載器
  webpackContext.id = "./src/demos sync recursive .ts";
}

我在源碼中寫了很詳細的注釋。看完這段代碼就不難理解文檔中所說的require.context 會返回一個帶有 3 個API的函數(shù)(webpackContext)了。

接著我們看看編譯后 index.ts 的源碼

"./src/index.ts": function(module, exports, __webpack_require__) {
  function importAll(contextLoader) {
    contextLoader.keys().forEach(function(id) {
      // 拿到所有 moduleId,在通過 context 加載器去加載每一個模塊
      return console.log(contextLoader(id));
    });
  }
  var contextLoader = __webpack_require__(
    "./src/demos sync recursive .ts"
  );
  importAll(contextLoader);
}

很簡單,可以發(fā)現(xiàn) require.context 編譯為了 __webpack_require__加載器并且加載了 id 為./src/demos sync recursive .ts 的模塊,sync表明我們是同步加載這些模塊(之后我們在介紹這個參數(shù)),recursive 表示需要遞歸目錄查找。自此,我們就完全能明白 webpack 是如何構建所有模塊并且動態(tài)加載的了。

進階深入探究 webpack 源碼

我們知道 webpack 在 2.6 版本后,在加載模塊時,可以指定 webpackMode 模塊加載模式,我們能使用幾種方式來控制我們要加載的模塊。常用的 mode一般為sync lazy lazy-once eager

所以在 require.context 是一樣適用的,我們如果查看一下@types/webpack-env就不難發(fā)現(xiàn)它還有第四個參數(shù)。

簡要來說

sync 直接打包到當前文件,同步加載并執(zhí)行

lazy 延遲加載會分離出多帶帶的 chunk 文件

lazy-once 延遲加載會分離出多帶帶的 chunk 文件,加載過下次再加載直接讀取內存里的代碼。

eager 不會分離出多帶帶的 chunk 文件,但是會返回 promise,只有調用了 promise 才會執(zhí)行代碼,可以理解為先加載了代碼,但是我們可以控制延遲執(zhí)行這部分代碼。

文檔在這里 https://webpack.docschina.org...。

這部分文檔很隱晦,也可能是文檔組沒有跟上,所以如果我們去看 webpack 的源碼的話,可以發(fā)現(xiàn)真正其實是有 6 種 mode。

mode類型定義
https://github.com/webpack/we...

那 webpack 到底是如何做到可遞歸獲取我們的文件呢?在剛剛上面的源碼地址里我們能發(fā)現(xiàn)這樣一行代碼。

這一看就是去尋找我們所需要的模塊。所以我們跟著這行查找具體的源碼。

這就是 require.context 是如何加載到我們文件的具體邏輯了。其實就是fs.readdir而已。最后獲取到文件之后在通過 context 加載器來生成我們的模塊結構對象。比如這樣的代碼就是負責生成我們sync類型的context加載器。大家可以具體在看別的5種類型。

6種類型加載邏輯并且生成 context 加載器的模塊結構對象 
https://github.com/webpack/we...
總結

1.學習了解 webpack 是如何組織加載一個模塊的,webpack 的加載器如何運作,最后如何生成編譯后的代碼。

2.本來僅僅只是想了解 require.context 如何實現(xiàn)的,卻發(fā)現(xiàn)了它第三個參數(shù)有 6 種mode,這部分卻也是 webpack 文檔上沒有的。

3.從一個實用的 API 出發(fā),探索了該 api 的實現(xiàn)原理,并且一起閱讀了部分 webpack 源碼。

4.探索本質遠比你成為 API 的搬運工更重要。只有你不斷地探尋本質,才可以發(fā)現(xiàn)世界的奧秘。

最后拋磚引玉,可以按照這樣的思路再去學習另外 6 種 mode 編譯后的代碼。

文章里編譯后的代碼,都在這里 >>> https://github.com/MeCKodo/re...

個人網(wǎng)站 >>> http://www.meckodo.com

最后常年招人

廈門 RingCentral 外企,福利待遇廈門頂尖

5點半下班 5點半下班 5點半下班

有想法的加我微信 abcdefghijklmnoKodo

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

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106037.html

相關文章

  • webpackrequire.context使用

    摘要:我們按照提供的思路,對路由按業(yè)務模塊進行拆分。這時就可以使用到了打包入口文件自動引入子目錄下所有文件參考分享使用的實現(xiàn)路由去中心化管理之用法的基礎組件的自動化全局注冊官方文檔 概述 You can create your own context with the require.context() function. It allows you to pass in a directo...

    cyrils 評論0 收藏0
  • 【翻譯向】webpack2 指南(上)

    摘要:原文發(fā)布與抹橋的博客翻譯向指南上前置定義代碼包代碼塊安裝代碼分割代碼分割是中最引人注目的功能之一。回調函數(shù)一個回調函數(shù)會被執(zhí)行一次當所有依賴都被加載以后。對象的實現(xiàn)作為一個參數(shù)傳遞給這個回調函數(shù)。 原文發(fā)布與 抹橋的博客 -【翻譯向】webpack2 指南(上) 前置定義 Bundle 代碼包Chunk 代碼塊 安裝 npm install webpack --save-dev 代碼分...

    史占廣 評論0 收藏0
  • 基于webpack構建angular 1.x工程(angular篇)

    摘要:基于構建的工程篇上一篇基于構建的工程一篇里我們已經(jīng)成功構建了整個項目的打包配置。不同的模塊之間都會有標識來標志,所以不會說存在干擾和污染的問題。但是對于我這個重構的項目,就會有麻煩要改寫的文件有太多了。然而還有一種情況。 基于webpack構建的angular 1.x工程(angular篇) ??上一篇基于webpack構建的angular 1.x 工程(一)webpack篇里我們已經(jīng)...

    jerry 評論0 收藏0
  • webpack2.x 中文文檔 翻譯 之 依賴管理 Dependency Management

    摘要:依賴管理該條已在中文網(wǎng)存在,點擊這里表達式來調用當你的請求包含表達式,那個一個上下文環(huán)境將被創(chuàng)建。一個包含所有父文件夾和子及后代文件夾中以結尾的文件的上下文。一個函數(shù),返回一個數(shù)組,包含上下文模塊能夠處理的所有的請求。 依賴管理 Dependency Management 該條已在webpack2.x中文網(wǎng)存在,點擊這里 es6 modules commonjs amd 表達式...

    raledong 評論0 收藏0
  • Node.js 熱更新(一)

    摘要:直到最近在使用微信機器人時,遇到了強烈的需求。增刪文件后熱更新上面的代碼已經(jīng)不小心實現(xiàn)了增加文件后熱更新,因為表示檢測的更新,如果增加一個,那么就變成,于是新模塊不等于老模塊不存在,從而使用注冊事件監(jiān)聽器。 背景 剛思考這個話題的時候,首先想到的是 Vue 或 React 的組件熱更新(基于 Webpack HMR),后來又想到了 Lua、Erlang 等語言的熱更新,不過在實際開發(fā) ...

    LancerComet 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<