最全的前端模組化方案

_zhongmeizhi_發表於2019-04-25

模組化主要是用來抽離公共程式碼,隔離作用域,避免變數衝突等。將一個複雜的系統分解為多個模組以方便編碼。

會講述以下內容

  1. CommonJS
  2. AMD 及 核心原理實現
  3. CMD 及 核心原理實現
  4. UMD 及 原始碼解析
  5. ES6 Module
  6. webpack打包策略

CommonJS

同步載入

CommonJS API是以在瀏覽器環境之外構建 JS 生態系統為目標而產生的專案

如果沒有寫字尾名Node會嘗試為檔名新增.js、.json、.node後再搜尋。

.js件會以文字格式的JavaScript指令碼檔案解析,.json檔案會以JSON格式的文字檔案解析,.node檔案會以編譯後的二進位制檔案解析。

AMD

非同步載入(物件)

"Asynchronous Module Definition"(非同步模組定義),是由RequireJS提出的

AMD核心實現

  function require (url, callback) {
    // url可以換成List,然後遍歷;
    var $script = document.createElement('script');
    $script.src = url;

    // 利用onload回撥,實現依賴載入
    $script.onload = function (e) {
      // 省略callback 檢測
      callback();
    }
    document.body.appendChild($script);
  }

複製程式碼

CMD

按需載入

由玉伯提出的(seajs),按需解析載入模組(代價挺大的),需要使用把模組變為字串解析一遍才知道依賴了那些模組

CMD核心實現

  // ajax,怕忘了原生ajax怎麼寫。順手寫一個

  function myAjax (url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open('get', url);
    xhr.send();

    xhr.onreadystatechange = function () {
      if (request.readyState === 4) {
          if (request.status === 200) {
              return callback(request.responseText);
          } else {
              // 省略...
          }
      } else {
        // 省略...
      }
    }
  }

  // 實現
  function require(url) {
    myAjax(url, function(res) {
      // 此時 res 的對應JS的 String形式
      // 解析 省略
      // 執行
      eval(res);
    });
  }
複製程式碼

UMD

相容AMD,CommonJS 模組化語法。

UMD原始碼解析

  (function (root, factory) {

    // 判斷是否支援AMD(define是否存在)
    if (typeof define === 'function' && define.amd) {
        define(['b'], factory);

    // 判斷是否支援NodeJS模組格式(exports是否存在)
    } else if (typeof module === 'object' && module.exports) {
        module.exports = factory(require('b'));

    // 前兩個都不存在,則將模組公開到全域性(window或global)
    } else {
        root.returnExports = factory(root.b);
    }
  } (this, function (b) {
      // ...
  }));
複製程式碼

import

載入引用

  • 編譯時載入(靜態執行)。
  • 載入的是引用
  • 不能處於程式碼塊中
    • 為了實現編譯時載入
      • 提案表示可以用 import()使用時載入
  • 不能使用表示式和變數 等執行時載入的語法
    • 同上

webpack打包策略

import會被編譯成 require/exports (CommonJS規範)

1. 直接引入

import xxx.js或者import xxx.css會像新增<script><link>標籤一樣注入到全域性中去

2. commonjs同步語法

webpack會將require('abc.js')打包進引用它的檔案中。以物件的形式獲取。

3. commonjs非同步載入

webpack(require.ensure):webpack 2.x 版本中的程式碼分割。

在commonjs中有一個Modules/Async/A規範,裡面定義了require.ensure語法。webpack實現了它,作用是可以在打包的時候進行程式碼分片,並非同步載入分片後的程式碼。

此時list.js會被打包成一個單獨的chunk檔案。像這樣:1.d6f343b727f5923508bf.js

例如:vue路由懶載入const Foo = () => import('./Foo.vue')

manifest

manifest檔案是最先載入的,manifest是在vendor的基礎上,再抽取出要經常變動的部分,通過manifest.js檔案來管理bundle檔案的執行和載入。(比如關於非同步載入js模組部分的內容)

webpack v4.6.0+ 新增了預取和預載入的支援

  import(/* webpackPrefetch: true */ 'LoginModal');
  
  會生成 <link rel="prefetch" href="login-modal-chunk.js"> 並追加到頁面頭部
複製程式碼

整理不易,喜歡請 star,github.com/zhongmeizhi

相關文章