首頁 > web前端 > js教程 > 主體

我寫了一個模組捆綁器。筆記等

王林
發布: 2024-07-25 03:10:43
原創
220 人瀏覽過

I wrote a module bundler. notes, etc

我建立了一個簡單的 JavaScript 捆綁器,結果比我預期的要容易得多。我將分享我在這篇文章中學到的所有知識。

編寫大型應用程式時,最好將 JavaScript 原始碼劃分為單獨的 js 文件,但是使用多個腳本標籤將這些文件添加到 html 文件中會帶來新問題,例如

  • 全域命名空間的污染。

  • 比賽條件。

模組捆綁器將不同檔案中的原始程式碼合併到一個大檔案中,幫助我們享受抽象的好處,同時避免缺點。

模組捆綁器通常分兩步驟完成。

  1. 從入口檔案開始,找到所有的JavaScript來源檔案。這稱為依賴解析,產生的映射稱為依賴圖。
  2. 使用依賴圖產生一個bundle:一大串可以在瀏覽器中執行的JavaScript原始碼。這可以寫入文件並使用腳本標籤新增到 html 文件。

依賴解析

如前所述,我們在這裡

  • 取得入口文件,
  • 閱讀並解析其內容,
  • 將其添加到模組數組中
  • 找到它的所有依賴項(它導入的其他檔案),
  • 讀取並解析依賴內容
  • 向數組添加依賴項
  • 查找依賴項的依賴項等等,直到我們到達最後一個模組

我們將這樣做(前面是 JavaScript 程式碼)

在文字編輯器中建立一個bundler.js 檔案並加入以下程式碼:

雷雷

bundler 函數是我們bundler 的主要入口。它獲取檔案(入口檔案)的路徑並傳回一個字串(捆綁包)。在其中,它使用 createDependencyGraph 函數來產生依賴圖。

雷雷

createDependencyGraph 函數取得入口檔案的路徑。它使用 createModule 函數產生此文件的模組表示。

雷雷

createAsset 函數會取得檔案的路徑並將其內容讀取到字串中。然後該字串被解析為抽象語法樹。抽象語法樹是原始碼內容的樹表示。它可以比喻為 html 文件的 DOM 樹。這使得在程式碼上運行一些功能變得更容易,例如搜尋等。
我們使用babylon解析器從模組建立一個ast。

接下來,在 babel 核心轉譯器的幫助下,我們將程式碼內容轉換為 es2015 之前的語法,以實現跨瀏覽器相容性。
然後使用 babel 中的特殊函數遍歷 ast 來尋找原始檔案的每個導入聲明(依賴項)。

然後我們將這些依賴項(相對檔案路徑的字串文字)推送到依賴項數組。

我們也創建一個 id 來唯一標識該模組並且
最後我們回傳一個代表該模組的物件。此模組包含一個 id、字串格式的檔案內容、依賴項陣列和絕對檔案路徑。

雷雷

回到 createDependencyGraph 函數,我們現在可以開始產生圖的過程。我們的圖表是一個物件數組,每個物件代表我們應用程式中使用的每個原始檔案。
我們使用入口模組初始化圖表,然後循環它。儘管它只包含一項,但我們透過存取入口模組(以及我們將添加的其他模組)的依賴項數組來將項目新增到數組的末尾。

dependency 陣列包含模組所有相依性的相對檔案路徑。此數組被循環,對於每個相對檔案路徑,首先解析絕對路徑並用於建立新模組。該子模組被推到圖的末尾,並且該過程重新開始,直到所有依賴項都已轉換為模組。
此外,每個模組都給出一個映射對象,該對象簡單地將每個依賴項相對路徑映射到子模組的 id。
對每個依賴項執行檢查模組是否已存在,以防止模組重複和無限循環依賴。
最後我們返回我們的圖表,它現在包含我們應用程式的所有模組。

捆綁

依賴圖完成後,產生套件將涉及兩個步驟

  1. Wrapping each module in a function. This creates the idea of each module having its own scope
  2. Wrapping the module in a runtime.

Wrapping each module

We have to convert our module objects to strings so we can be able to write them into the bundle.js file. We do this by initializing moduleString as an empty string. Next we loop through our graph appending each module into the module string as key value pairs, with the id of a module being the key and an array containing two items: first, the module content wrapped in function (to give it scope as stated earlier) and second an object containing the mapping of its dependencies.

const wrapModules = (graph)=>{
         let modules = ‘’
           graph.forEach(mod => {
    modules += `${http://mod.id}: [
      function (require, module, exports) {
        ${mod.code}
      },
      ${JSON.stringify(mod.mapping)},
    ],`;
  });
return modules
}
登入後複製

Also to note, the function wrapping each module takes a require, export and module objects as arguments. This is because these don’t exist in the browser but since they appear in our code we will create them and pass them into these modules.

Creating the runtime

This is code that will run immediately the bundle is loaded, it will provide our modules with the require, module and module.exports objects.

const bundle = (graph)=>{
        let modules = wrapModules(graph)
        const result = `
    (function(modules) {
      function require(id) {
        const [fn, mapping] = modules[id];

        function localRequire(name) {
          return require(mapping[name]);
        }

        const module = { exports : {} };

        fn(localRequire, module, module.exports);

        return module.exports;
      }

      require(0);
    })({${modules}})`;
  return result;
}
登入後複製

We use an immediately invoked function expression that takes our module object as an argument. Inside it we define our require function that gets a module from our module object using its id.
It constructs a localRequire function specific to a particular module to map file path string to id. And a module object with an empty exports property
It runs our module code, passing the localrequire, module and exports object as arguments and then returns module.exports just like a node js module would.
Finally we call require on our entry module (index 0).

To test our bundler, in the working directory of our bundler.js file create an index.js file and two directories: a src and a public directory.

In the public directory create an index.html file, and add the following code in the body tag:



    
        Module bundler
        
    
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!