前端模塊化

模塊化

模塊化用來分割,組織和打包軟件。每一個模塊完成一個特定的子功能,全部的模塊按某種方法組裝起來,成爲一個總體,完成整個系統所要求的功能。html

之前開發沒用模塊化可能致使的問題

  1. 命名空間衝突,多個庫可能會使用同一名稱
  2. 沒法合理的管理項目的依賴和版本
  3. 沒法方便的控制依賴的加載順序

## 現在前端模塊化的主流方式
利用自動化構建工具Gulp/Webpack 把源代碼轉換成發佈線上的可執行JavaScrip、CSS、HTML 代碼
一般自動化構建工具作的內容有:前端

  • 代碼轉換:ECMASCRIPT6 編譯成 ECMASCRIPT五、LESS 編譯成 CSS 等。
  • 文件優化:壓縮 JavaScript、CSS、HTML 代碼,壓縮合並圖片等
  • 代碼分割:提取多個頁面的公共代碼、提取首屏不須要執行部分的代碼讓其異步加載。
  • 模塊合併:在採用模塊化的項目裏會有不少個模塊和文件,須要構建功能把模塊分類合併成一個文件。
  • 自動刷新:監聽本地源代碼的變化,自動從新構建、刷新瀏覽器。
  • 代碼校驗:在代碼被提交到倉庫前須要校驗代碼是否符合規範,以及單元測試是否經過。
  • 自動發佈:更新完代碼後,自動構建出線上發佈代碼並傳輸給發佈系統。

## 模塊化的幾種規範node

  1. CommonJS
  2. AMD
  3. ES6模塊化

## CommonJS
CommonJS定義的模塊分爲:{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}
  require()用來引入外部模塊;exports對象用於導出當前模塊的方法或變量,惟一的導出口;module對象就表明模塊自己。瀏覽器

  • 使用方式
// foo.js 
module.exports = function(x) { // 導出
  console.log(x);
};

// main.js
var foo = require("./foo"); // 導入
foo("Hi");
  • 原理

瀏覽器不兼容CommonJS的根本緣由,在於缺乏四個Node.js環境的變量。安全

  • module
  • exports
  • require
  • global

換言之, 只要咱們提供了這幾個, 瀏覽器就能加載 CommonJS 模塊。下面是一個簡單的示例服務器

var module = {
  exports: {}
};

(function(module, exports) {
  exports.multiply = function (n) { return n * 1000 };
}(module, module.exports))

var f = module.exports.multiply;
f(5) // 5000
  • 模擬實現require
function require(p){
  var path = require.resolve(p);   // 返回路徑
  var mod = require.modules[path];  // 是否已註冊
  if (!mod) throw new Error('failed to require "' + p + '"');  // 未註冊拋出
  if (!mod.exports) {   // 若是註冊了  就執行模塊 
    mod.exports = {};
    mod.call(mod.exports, mod, mod.exports, require.relative(path));    // 執行模塊
  }
  return mod.exports;
}

require.modules = {};
require.resolve = function (path){
  var orig = path;
  var reg = path + '.js';   
  var index = path + '/index.js';
  return require.modules[reg] && reg || require.modules[index] && index || orig;
};

require.register = function (path, fn){  // 註冊模塊
  require.modules[path] = fn;  
};

require.relative = function (parent) {
  return function(p){
    if ('.' != p.charAt(0)) return require(p);
    var path = parent.split('/');
    var segs = p.split('/');
    path.pop();

    for (var i = 0; i < segs.length; i++) {
      var seg = segs[i];
      if ('..' == seg) path.pop();
      else if ('.' != seg) path.push(seg);
    }

    return require(path.join('/'));
  };
};

require.register("moduleId", function(module, exports, require){
  // 代碼寫在這裏
});
var result = require("moduleId");

AMD

優勢babel

  1. 可在不轉換代碼的狀況下直接在瀏覽器中運行
  2. 可加載多個依賴
  3. 代碼可運行在瀏覽器環境和 Node.js 環境下

缺點app

  1. JavaScript 運行環境沒有原生支持 AMD,須要先導入實現了 AMD 的庫後才能正常使用
  • 語法
define([module-name?],  // 模塊名
[array-of-dependencies?],  // 依賴模塊
[module-factory-or-object]); // 模塊的實現,或者一個JavaScript對象
  • 使用方法
define('a', [], function () {
    return 'a';
});
define('b', ['a'], function (a) {
    return a + 'b';
});
// 導入和使用
require(['b'], function (b) {
    console.log(b);
});

define函數具備異步性。當define函數執行時,首先會異步的去調用第二個參數中列出的依賴模塊,當全部的模塊被載入完成以後,
若是第三個參數是一個回調函數則執行;而後告訴系統模塊可用,也就通知了依賴於本身的模塊本身已經可用異步

  • 模擬實現
let factories = {};
function define(modName, dependencies, factory) {
    factory.dependencies = dependencies;  // 依賴
    factories[modName] = factory; // 儲存模塊 
}
function require(modNames, callback) {
    let loadedModNames = modNames.map(function (modName) {
        let factory = factories[modName];
        let dependencies = factory.dependencies;
        let exports;
        require(dependencies, function (...dependencyMods) {
            exports = factory.apply(null, dependencyMods);
        });
        return exports;
    })
    callback.apply(null, loadedModNames);
}

目前AMD使用比較少了ide

ES6模塊化

ES6 模塊化是ECMA提出的JavaScript模塊化規範,它在語言的層面上實現了模塊化。瀏覽器廠商和Node.js
都宣佈要原生支持該規範。它將逐漸取代CommonJS和AMD`規範,成爲瀏覽器和服務器通用的模塊解決方案。

  • 優勢

    1. 主流方案, 各類瀏覽器廠商和node都逐漸支持
  • 缺點

    1. 目前沒法直接運行在大部分 JavaScript 運行環境下,必須經過工具轉換成標準的 ES5 後才能正常運行
  • 特色

    1. 若是你經過本地加載Html 文件 (好比一個 file:// 路徑的文件), 你將會遇到 CORS 錯誤,由於Javascript 模塊安全性須要。你須要經過一個服務器來測試。
    2. 自動使用嚴格模式。
    3. 加載一個模塊腳本時不須要使用 defer 屬性, 模塊會自動延遲加載。
    4. 沒法在全局得到. 所以,你只能在導入這些功能的腳本文件中使用他們,你也沒法經過Javascript console 中獲取到他們
  • 使用方法
  1. 基本使用
// 導出
export const name = 'xiaoming';
// 導入
import { name } from './person.js';
  1. 默認導出
// 導出
const name = 'xiaoming';
export default name
// 導入
import name from './person.js';
//  或者
import {default as name} from './person.js';
  1. 重命名導出與導入
export {
  function1 as newFunctionName,
  function2 as anotherNewFunctionName
};

// inside main.mjs
import { newFunctionName, anotherNewFunctionName } from '/modules';
  1. 所有導入
import * as Module from '/modules/module';
Module.function1()
Module.function2()
  1. 動態導入
import('/modules/myModule.mjs')
  .then((module) => {
    // Do something with the module.
  });
//    須要babel解析才能使用

參考資料

珠峯培訓
深刻理解commonjs
AMD與requireJS
JavaScript modules 模塊

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息