前端模塊化開發

來源於:阿賢博客javascript

javascript模塊化

今天給你們寫一篇關於前端模塊化開發知識點。

前端模塊化開發那點歷史
php

  • 模塊化:html

    • 是指在解決某個複雜、混雜問題時,依照一種分類的思惟把問題進行系統性的分解以之處理。模塊化是一種處理複雜系統分解爲代碼結構更合理,可維護性更高的可管理的模塊的方式。
    • 模塊化是軟件系統的屬性,這個系統被分解爲一組高內聚,低耦合的模塊。那麼在理想狀態下咱們只須要完成本身部分的核心業務邏輯代碼,其餘方面的依賴能夠經過直接加載被人已經寫好模塊進行使用便可。
  • 模塊化系統所必須的能力:前端

    1. 定義封裝的模塊。
    2. 定義新模塊對其餘模塊的依賴。
    3. 可對其餘模塊的引入支持。

好了,思想有了,那麼總要有點什麼來創建一個模塊化的規範制度吧,否則各式各樣的模塊加載方式只會將局攪得更爲混亂。那麼在JavaScript中出現了一些非傳統模塊開發方式的規範 CommonJS的模塊規範,AMD(Asynchronous Module Definition),CMD(Common Module Definition)等。java

爲了創建一個模塊化的規範制度、模塊加載方式。在JavaScript中出現了一些非傳統模塊開發方式的規範 CommonJS的模塊規範,AMD(Asynchronous Module Definition)、CMD(Common Module Definition)、ES6模塊誕生了。

AMD規範(與Requirejs)

AMD(Asynchronous Module Definition)異步模塊定義,全部的模塊將被異步加載,模塊加載不影響後面語句運行。全部依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成以後,這個回調函數纔會運行。

AMD規範定義了一個自由變量或者說是全局變量 define 的函數。node

define( id?, dependencies?, factory );

AMD規範jquery

  • 第一個參數 id 爲字符串類型,表示了模塊標識,爲可選參數。若不存在則模塊標識應該默認定義爲在加載器中被請求腳本的標識。若是存在,那麼模塊標識必須爲頂層的或者一個絕對的標識。
  • 第二個參數,dependencies ,是一個當前模塊依賴的,已被模塊定義的模塊標識的數組字面量。
  • 第三個參數,factory,是一個須要進行實例化的函數或者一個對象。
建立模塊標識爲 alpha 的模塊,依賴於 require, export,和標識爲 beta 的模塊

define("alpha", [ "require", "exports", "beta" ], function( require, exports, beta ){
        export.verb = function(){
            return beta.verb();
            // or:
            return require("beta").verb();
        }
    });
一個返回對象字面量的異步模塊

define(["alpha"], function( alpha ){
        return {
            verb : function(){
                return alpha.verb() + 1 ;
            }
        }
    });
無依賴模塊能夠直接使用對象字面量來定義

define( {
        add : function( x, y ){
            return x + y ;
        }
    } );

require();

require API
在 AMD 規範中的 require 函數與通常的 CommonJS中的 require 不一樣。因爲動態檢測依賴關係使加載異步,對於基於回調的 require 需求強烈。git

局部 與 全局 的require

局部的 require 須要在AMD模式中的 define 工廠函數中傳入 require。es6

define( ['require'], function( require ){
      // ...
    } );
    or:
    define( function( require, exports, module ){
      // ...
    } );

局部的 require 須要其餘特定的 API 來實現。
github

全局的 require 函數是惟一全局做用域下的變量,像 define同樣。全局的 require 並非規範要求的,可是若是實現全局的 require函數,那麼其須要具備與局部 require 函數 同樣的如下的限定:<br />
1. 模塊標識視爲絕對的,而不是相對的對應另外一個模塊標識。<br />
2. 只有在異步狀況下,require的回調方式才被用來做爲交互操做使用。由於他不可能在同步的狀況下經過 require(String) 從頂層加載模塊。<br />
依賴相關的API會開始模塊加載。若是須要有互操做的多個加載器,那麼全局的 reqiure 應該被加載頂層模塊來代替。
require(String)
   define( function( require ){
       var a = require('a'); // 加載模塊a
   } );
   
   require(Array, Function)
   define( function( require ){
       require( ['a', 'b'], function( a,b ){ // 加載模塊a b 使用
           // 依賴 a b 模塊的運行代碼
       } ); 
   } );
   
   require.toUrl( Url )
   define( function( require ){
       var temp = require.toUrl('./temp/a.html'); // 加載頁面
   } );

RequireJS

官網
API

API 中文

RequireJS 是一個前端的模塊化管理的工具庫,遵循AMD規範,它的做者就是AMD規範的創始人 James Burke。

頁面頂層<script>標籤含有一個特殊的屬性data-main,require.js使用它來啓動腳本加載過程,而baseUrl通常設置到與該屬性相一致的目錄。下列示例中展現了baseUrl的設置:
<script data-main="scripts/main.js" src="scripts/require.js"></script>
defined用於定義模塊,RequireJS要求每一個模塊均放在獨立的文件之中。按照是否有依賴其餘模塊的狀況分爲獨立模塊和非獨立模塊。
1. 獨立模塊,不依賴其餘模塊。直接定義:

define({
        method1: function(){},
        method2: function(){}
    });
    //等價於
    define(function(){
        return{
            method1: function(){},
            method2: function(){}
        }
    });
2. 非獨立模塊,對其餘模塊有依賴。

define([ 'module1', 'module2' ], function(m1, m2){
        //代碼...
    });
    //等價於
    define( function( require ){
        var m1 = require( 'module1' ),
          m2 = require( 'module2' );
        //代碼...
    });

define 和 require 這兩個定義模塊,調用模塊的方法合稱爲AMD模式,定義模塊清晰,不會污染全局變量,清楚的顯示依賴關係。AMD模式能夠用於瀏覽器環境而且容許非同步加載模塊,也能夠按需動態加載模塊。

/***
    **** require方法調用模塊
    ****  在加載 foo 與 bar 兩個模塊以後執行回調函數實現具體過程。
    ***/
    require( ['foo', 'bar'], function( foo, bar ){
        foo.func();
        bar.func();
    } );
    
    /***
    **** 在define定義模塊內部進行require調用模塊
    ***/
    define( function( require ){
        var m1 = require( 'module1' ),
            m2 = require( 'module2' );
        //代碼...
    });

CMD規範(與Seajs)

在CMD中,一個模塊就是一個文件,格式爲:
[CMD模塊定義規範]( https://github.com/seajs/seaj...

define( factory );

全局函數define,用來定義模塊。

參數 factory 能夠是一個函數,也能夠爲對象或者字符串。

當 factory 爲對象、字符串時,表示模塊的接口就是該對象、字符串。

定義JSON數據模塊:

define({ "foo": "bar" });
經過字符串定義模板模塊:

define('this is {{data}}.');
factory 函數

//表示模塊的構造方法,執行構造方法即可以獲得模塊向外提供的接口。
    define( function(require, exports, module) { 
        // 模塊代碼
    });

define( id?, deps?, factory );

define也能夠接受兩個以上的參數,字符串id爲模塊標識,數組deps爲模塊依賴:

define( 'module', ['module1', 'module2'], function( require, exports, module ){
        // 模塊代碼
    } );

其與 AMD 規範用法不一樣。

require 是 factory 的第一個參數。

require( id );

接受模塊標識做爲惟一的參數,用來獲取其餘模塊提供的接口:

define(function( require, exports ){
        var a = require('./a');
        a.doSomething();
    });

require.async( id, callback? );

require是同步往下執行的,須要的異步加載模塊可使用 require.async 來進行加載:

define( function(require, exports, module) { 
        require.async('.a', function(a){
            a.doSomething();
        });
    });

require.resolve( id )

可使用模塊內部的路徑機制來返回模塊路徑,不會加載模塊。

exports 是 factory 的第二個參數,用來向外提供模塊接口。

define(function( require, exports ){
        exports.foo = 'bar'; // 向外提供的屬性
        exports.do = function(){}; // 向外提供的方法
    });
    
    //使用 return 直接向外提供接口。
    define(function( require, exports ){
        return{
            foo : 'bar', // 向外提供的屬性
            do : function(){} // 向外提供的方法
        }
    });
    
    //簡化爲直接對象字面量的形式:
    define({
        foo : 'bar', // 向外提供的屬性
        do : function(){} // 向外提供的方法
    });

module 是factory的第三個參數,爲一個對象,上面存儲了一些與當前模塊相關聯的屬性與方法。

module.id 爲模塊的惟一標識。

module.uri 根據模塊系統的路徑解析規則獲得模塊的絕對路徑。

module.dependencies 表示模塊的依賴。

module.exports 當前模塊對外提供的接口。

Seajs

官網文檔

倉庫代碼

SeaJS API快速參考

官網( http://seajs.org/)已經關閉。
其define 與 require 使用方式基本就是CMD規範中的示例。

sea.js 核心特徵:

  1. 遵循CMD規範,與NodeJS般的書寫模塊代碼。
  2. 依賴自動加載,配置清晰簡潔。

兼容 Chrome 3+,Firefox 2+,Safari 3.2+,Opera 10+,IE 5.5+。

seajs.use

用來在頁面中加載一個或者多個模塊

// 加載一個模塊 
    seajs.use('./a');
    // 加載模塊,加載完成時執行回調
    
    seajs.use('./a',function(a){
        a.doSomething();
    });
    
    // 加載多個模塊執行回調
    seajs.use(['./a','./b'],function(a , b){
        a.doSomething();
        b.doSomething();
    });

AMD 與 CMD 區別

玉伯對於 AMD 與 CMD 區別的解釋:
AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。
CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。
相似的還有 CommonJS Modules/2.0 規範,是 BravoJS 在推廣過程當中對模塊定義的規範化產出
  1. 對於依賴的模塊,AMD 是提早執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣)。
  2. CMD 推崇依賴就近,AMD 推崇依賴前置。看代碼:
// CMD
    define(function(require, exports, module) {
        var a = require('./a');
        a.doSomething();
        // 此處略去 100 行
        var b = require('./b'); // 依賴能夠就近書寫
        b.doSomething();
        // 代碼...
    })
    
    // AMD 默認推薦的是
    define(['./a', './b'], function(a, b) { // 依賴必須一開始就寫好
        a.doSomething();
        // 此處略去 100 行
        b.doSomething();
        
        // 代碼...
    })
雖然 AMD 也支持 CMD 的寫法,同時還支持將 require 做爲依賴項傳遞,但 RequireJS 的做者默認是最喜歡上面的寫法,也是官方文檔裏默認的模塊定義寫法。
  1. AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。
  2. 還有一些細節差別,具體看這個規範的定義就好,就很少說了。

另外,SeaJS 和 RequireJS 的差別

UMD

UMD

AMD、CMD、UMD 模塊

既然CommonJs和AMD風格同樣流行,彷佛缺乏一個統一的規範。因此人們產生了這樣的需求,但願有支持兩種風格的「通用」模式,因而通用模塊規範(UMD)誕生了。

(function (root, factory) {
        if (typeof define === 'function' && define.amd) {
            // AMD
            define(['jquery'], factory);
        } else if (typeof exports === 'object') {
            // Node, CommonJS之類的
            module.exports = factory(require('jquery'));
        } else {
            // 瀏覽器全局變量(root 即 window)
            root.returnExports = factory(root.jQuery);
        }
    }(this, function ($) {
        //    方法
        function myFunc(){};
     
        //    暴露公共方法
        return myFunc;
    }));
    
    //複雜、依賴了多個組件而且暴露多個方法
    (function (root, factory) {
        if (typeof define === 'function' && define.amd) {
            // AMD
            define(['jquery', 'underscore'], factory);
        } else if (typeof exports === 'object') {
            // Node, CommonJS之類的
            module.exports = factory(require('jquery'), require('underscore'));
        } else {
            // 瀏覽器全局變量(root 即 window)
            root.returnExports = factory(root.jQuery, root._);
        }
    }(this, function ($, _) {
        //    方法
        function a(){};    //    私有方法,由於它沒被返回 (見下面)
        function b(){};    //    公共方法,由於被返回了
        function c(){};    //    公共方法,由於被返回了
     
        //    暴露公共方法
        return {
            b: b,
            c: c
        }
    }));

ES6模塊

ES6

Module 的語法

ES6 模塊的設計思想,是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時肯定這些東西。好比,CommonJS 模塊就是對象,輸入時必須查找對象屬性。

// ES6模塊
    import { stat, exists, readFile } from 'fs';

上面代碼的實質是從fs模塊加載3個方法,其餘方法不加載。這種加載稱爲「編譯時加載」或者靜態加載,即 ES6 能夠在編譯時就完成模塊加載。

ES6模塊好處

  1. 再也不須要UMD模塊格式了,未來服務器和瀏覽器都會支持 ES6 模塊格式。目前,經過各類工具庫,其實已經作到了這一點。
  2. 未來瀏覽器的新 API 就能用模塊格式提供,再也不必須作成全局變量或者navigator對象的屬性。
  3. 再也不須要對象做爲命名空間(好比Math對象),將來這些功能能夠經過模塊提供。

擴展閱讀:

AMD規範文檔
amdjs 的 require 接口文檔
amdjs 的接口文檔
RequireJS官網接口文檔
模塊系統
前端模塊化開發的價值
前端模塊化開發那點歷史
CMD 模塊定義規範
SeaJS API快速參考
從 CommonJS 到 Sea.js
RequireJS和AMD規範
CommonJS規範
JavaScript模塊化開發 - CommonJS規範
JavaScript模塊化開發 - AMD規範
Javascript模塊化編程1
Javascript模塊化編程2
知乎 AMD 和 CMD 的區別有哪些?
與 RequireJS 的異同
模塊化設計
模塊化
ES6
Module 的語法

來源於:阿賢博客

相關文章
相關標籤/搜索