JavaScript模組化規範詳解

來源:互聯網
上載者:User

標籤:檔案路徑   ext   屬性   css   檔案系統   async   jquery   命名   .config   

JavaScript模組化規範詳解目錄
  1. 為什麼要模組化

  2. 模組化的好處

  3. 頁面引入載入script存在的問題

  4. 模組化規範

    • CommonJS

      • Node.js中實現

      • 瀏覽器端實現

    • AMD

    • CMD

    • ES6模組化

為什麼要模組化?
  1. Web sites are turning into Web Apps.

  2. Code complexity(複雜度) grows as the site gets bigger.

  3. Highly decoupled(解耦) JS files/modules is wanted.

  4. Deployment(部署) wants optimized(最佳化) code in few HTTP calls.

模組化的好處
  1. 避免命名衝突(減少命名空間汙染)

  2. 更好的分離,按需載入

  3. 更高複用性

  4. 高可維護性

頁面引入載入script存在的問題:
  • 請求過多

  • 依賴模糊

  • 難以維護

模組化規範

CommonJS

每個檔案都可當做一個模組

  • 在伺服器端: 模組的載入是運行時同步載入的。

  • 在瀏覽器端: 模組需要提前編譯打包處理。

基本文法:

  • 暴露模組:
    • module.exports = value
    • exports.xxx = value
  • 引入模組:
    • require(xxx)
    • 第三方模組: xxx為模組名
    • 自訂模組: xxx為模組檔案路徑

實現:

  • 伺服器端實現: Node.js
  • 瀏覽器端實現: Browserify,也稱為CommonJS的瀏覽器端的打包工具。

Node.js模組化過程
  1. 安裝Node.js

  2. 建立項目結構

    |-modules  |-module1.js  |-module2.js  |-module3.js|-app.js|-package.json  {    "name": "commonJS-node",    "version": "1.0.0"  }
  3. 下載第三方模組
    • npm install uniq --save
  4. 模組化編碼
    • module1.js

      module.exports = {    foo() {        console.log(‘module1 foo()‘);    }};
    • module2.js

      module.exports = function() {    console.log(‘module2()‘);};
    • module3.js

      exports.foo = function() {    console.log(‘module3 foo()‘);};exports.bar = function() {    console.log(‘module3 bar()‘);};
    • app.js

      /* * 1. 定義暴露模組: *  module.exports = value; *  exports.xxx = value; * 2. 引入模組: *  var module = require(模組名或模組路徑); */// 引用模組let fs = require(‘fs‘); // fs是nodejs中內建的檔案系統模組let uniq = require(‘uniq‘); // 下載的第三方模組,功能是數組排序去重let module1 = require(‘./modules/module1‘); // 自訂的modulelet module1 = require(‘./modules/module1‘);let module1 = require(‘./modules/module1‘);// 使用模組module1.foo();module2();console.log(uniq([1, 3, 2, 4, 2]));fs.readFile(‘app.js‘, function(error, data){    console.log(data.toString());})
  5. 通過node運行app.js: node app.js

Browserify模組化過程

由於瀏覽器端不具備node那樣的環境,不能識別require等方法,所以瀏覽器端的模組化需要藉助Browserify工具來完成打包,以便瀏覽器識別。

  1. 建立項目結構

    |-js  |-dist // 打包組建檔案的目錄  |-src // 源碼所在的目錄    |-module1.js    |-module2.js    |-module3.js    |-app.js // 應用主源檔案|-index.html|-package.json  {    "name": "browserify-test",    "version": "1.0.0"  }
  2. 下載browserify

    • 全域: npm install browserify -g // 全域環境安裝
    • 局部: npm install browserify --save-dev // 只是協助我們編譯打包檔案,在開發環境(-dev)下安裝即可,將來生產環境並不需要

    安裝完後,package.json中會變成:

      {    "name": "browserify-test",    "version": "1.0.0"    "devDependencies": {"browserify": 版本號碼}, // 開發環境下的依賴包    "dependencies": {"uniq": 版本號碼} // 全域依賴包  }
  3. 定義模組代碼

    • 和Node.js中一樣的定義。
  4. 打包處理js源檔案:

    • browserify js/src/app.js -o js/dist/build.js

    • 上面的命令執行完畢後,產生了打包後的檔案,就可以在html頁面中引入了:

      <script type="text/javascript" src="js/dist/build.js"></script>

AMD

Asynchronous Module Definition(非同步模組定義)

專門用於瀏覽器端,模組的載入是非同步。

文法:

  1. 定義暴露模組

    • 定義沒有依賴的模組

      define(function(){    return 模組})
    • 定義有依賴的模組

      define([‘module1‘,‘module2‘], function(m1, m2){    return 模組})
  2. 引入使用模組

    require([‘module1‘,‘module2‘], function(m1, m2){ //顯式聲明依賴注入    使用m1/m2})

實現: Require.js

在沒有使用AMD規範(require.js)的時候,我們通過多個script標籤來按照依賴順序依次引入js檔案,
這樣不但增加了HTTP請求數,更增加了維護的難度,容易出錯。

通過模組載入器require.js來載入js模組:

  1. 下載Require.JS,官網: http://www.requirejs.cn/

  2. 建立項目結構

    |-js  |-libs    |-require.js  |-modules    |-module1.js    |-module2.js  |-main.js|-index.html
  3. 定義模組代碼

    • module1.js

      define(function(){    let msg = ‘hello‘;    function getMsg(){        return msg.toUpperCase();    }    return {getMsg};});
    • module2.js

      define([‘module1‘, ‘jquery‘], function(m1, $){    let name = "module2";    function showMsg(){        $(‘body‘).css(‘background‘, "red");        alert(m1.getMsg() + ‘,‘ + name);    }    return {showMsg};});
  4. 編寫應用主入口: main.js

    (function () {    // 配置    require.config({        //基本路徑        baseUrl: "js/",        //模組標識名與模組路徑映射        paths: {            "module1": "./modules/module1", // 內部會給路徑自動加上.js副檔名            "module2": "./modules/module2",        }    });    // 引入使用模組    require([‘module2‘], function(module2){        module2.showMsg();    })})()
  5. 頁面使用模組

    <script data-main="js/main.js" src="js/libs/require.js"></script>

    require.js 在載入的時候會檢查 data-main 屬性:
    可以在data-main指向的指令碼中設定模板載入 選項,然後載入第一個應用模組。

    注意:你在main.js中所設定的指令碼是非同步載入的。所以如果你在頁面中配置了其它JS載入,則不能保證它們所依賴的JS已經載入成功

    例如:

    <script data-main="scripts/main" src="scripts/require.js"></script><script src="scripts/other.js"></script>
    // contents of main.js:require.config({    paths: {        foo: ‘libs/foo-1.1.3‘    }});
    // contents of other.js:// This code might be called before the require.config() in main.js// has executed. When that happens, require.js will attempt to// load ‘scripts/foo.js‘ instead of ‘scripts/libs/foo-1.1.3.js‘require( [‘foo‘], function( foo ) {});
  6. 使用第三方基於require.js的架構(jquery)

    jQuery支援AMD規範,在源碼的最後幾行,define("jquery", [], function(){return jQuery;}); 這說明jQuery暴露了一個模組介面,並且標識名為jquery。

    注意在引入的時候,寫jquery而不是jQuery

    將jQuery庫檔案匯入到項目的libs目錄中,然後在main.js中配置jquery路徑:

    path: {    ‘jquery‘: ‘./libs/jquery-1.10.1‘}

    接下來就可以使用在module中了。

    define([‘module1‘, ‘jquery‘], function (module1, $) {    var name = ‘Tom‘;    function showMsg() {        $(‘body‘).css({background : ‘red‘})        alert(name + ‘ ‘ + module1.getMsg())    }    return {showMsg}})
  7. 使用第三方不基於require.js的架構(angular)

    將angular.js/angular-messages.js匯入項目目錄,然後在paths中添加angular路徑。

    為了配置不相容AMD的模組,需要在require.config中多添加:

    shim: {    ‘angular‘: {        exports: ‘angular‘    },    `angular-messages`: {        exports: ‘angular-message‘,        deps: [‘angular‘]    }}

CMD

專門應用於瀏覽器端,模組的載入是非同步。

實現: sea.js,github: https://github.com/seajs/seajs

模組使用時才會載入執行。

文法:

  1. 定義暴露模組

    • 定義沒有依賴的模組

      define(function(require, exports, module){    exports.xxx = value;    module.exports = value;})
    • 定義有依賴的模組

      define(function(require, exports, module){    //引入相依模組(同步)    var module2 = require(‘./module2‘);    //引入相依模組(非同步),注意非同步function會在主線程執行完畢再執行,因此輸出順序可能變化    require.async(‘./module3‘, function(m3){    })    //暴露模組    exports.xxx = value;})
  2. 引入使用模組

    define(function(require){    var m1 = require(‘./module1‘);    var m4 = require(‘./module4‘);    m1.show();    m4.show();})

CMD規範,定義模組類似AMD,暴露模組類似Commonjs。

使用方法:

  1. 下載sea.js並引入到libs。

  2. 建立項目結構

    |-js  |-libs    |-sea.js  |-modules    |-module1.js    |-module2.js    |-module3.js    |-module4.js    |-main.js|-index.html
  3. 定義sea.js的模組代碼

    • module1.js

      define(function(require, exports, module) {    var data = "hello";    function show(){        console.log(‘module1 show()‘ + data);    }    // 向外暴露    exports.show = show;})
    • 主入口模組: main.js

      define(function(require){    var m1 = require(‘./module1‘);    m1.show();})
  4. 在index頁面引入

    <script type="text/javascript" src="js/libs/sea.js"></script><script type="text/javascript">    seajs.use(‘./js/modules/main.js‘)</script>

ES6模組化規範

ES6中內建了js模組化的實現。

文法:

  1. 定義暴露模組: export

    • 暴露一個對象(預設暴露):

      export default 對象

      可以暴露任意資料類型,暴露什麼就接收到什麼。

    • 暴露多個對象(常規暴露):

      // 分別暴露export var xxx = value1;export let yyy = value2;// 統一暴露var xxx = value1;let yyy = value2;export {xxx, yyy}

      統一暴露或者分別暴露,在引入的時候必須用對象解構賦值的形式。

  2. 引入使用模組: import

    • 預設暴露的模組:

      import xxx from ‘模組路徑/模組名‘
    • 其他模組

      import {xxx, yyy} from ‘模組路徑/模組名‘import * as module1 from ‘模組路徑/模組名‘

問題:

一些瀏覽器還不能直接識別ES6模組化的的文法。

需要使用Babel來將ES6轉換為ES5,但由於內部還使用了CommonJS,所以瀏覽器仍然不能直接執行。

接著再次使用Browserify來將檔案打包處理,最終引入頁面,瀏覽器可以直接運行。

js轉換及打包方法:

  1. 定義package.json檔案

    {    "name": "es6_babel_browserify-test",    "version": "1.0.0"}
  2. 安裝babel-cli, babel-preset-es2015和browserify

    • npm install babel-cli browserify -g
    • npm install babel-preset-es2015 --save-dev
  3. 定義.babelrc設定檔(babel在執行之前會先讀取該檔案)

    {    "presets": ["es2015"] // 該命令決定了babel要去執行的任務,"es2015"表示ES6文法轉換}
  4. 編寫模組

    • js/src/module1.js

      something...

    • js/src/app.js

      import {fun1, fun2} from ‘./module1‘;import $ from ‘jquery‘;$(‘body‘).css(‘background‘, ‘red‘);fun1();fun2();
  5. 編譯打包

    • 使用Babel編譯為ES5文法(包含CommonJS):

      babel js/src -d js/build (可以自動產生新目錄build)

    • 使用Browserify打包js:

      browserify js/build/app.js -o js/dist/bundle.js(不能自動產生dist目錄)

  6. 頁面中引入

    <script type="text/javascript" src="js/build/bundle.js"></script>

  7. 引入第三方模組(jQuery)

    1. 下載jQuery模組:

      npm install [email protected] --save (模組後加@代表下載相應版本號碼下的最新版本)

    2. 在app.js中引入使用:

      import $ from ‘jquery‘

注意:

當改變了模組中的代碼後,需要重新轉換(Babel)、編譯打包(Browserify),再引入頁面。

JavaScript模組化規範詳解

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.