可能是最詳細的UMD模塊入門指南


學習UMD

介紹

這個倉庫記錄了一些關於javascript UMD模塊規范的demo,對我學習UMD規范有了很大幫助,希望也能幫助到你。

回顧

之前也寫了幾篇關於javascript模塊的博客,鏈接如下:

近幾天准備總結一下javascript模塊的知識點,所以建了這個Git倉庫,如果能幫助到您,麻煩點個star哦,非常感謝!

這篇博客主要說下自己關於UMD的一點認知和思考,從實現一個簡單的UMD模塊,再到實現一個有依賴關系的UMD模塊,整個過程加深了我對UMD模塊的理解。

什么是UMD

所謂UMD (Universal Module Definition),就是一種javascript通用模塊定義規范,讓你的模塊能在javascript所有運行環境中發揮作用。

簡單UMD模塊的實現

實現一個UMD模塊,就要考慮現有的主流javascript模塊規范了,如CommonJS, AMD, CMD等。那么如何才能同時滿足這幾種規范呢?

首先要想到,模塊最終是要導出一個對象,函數,或者變量。

而不同的模塊規范,關於模塊導出這部分的定義是完全不一樣的。

因此,我們需要一種過渡機制。

首先,我們需要一個factory,也就是工廠函數,它只負責返回你需要導出的內容(對象,函數,變量等)。

我們從導出一個簡單的對象開始。

function factory() {
    return {
        name: '我是一個umd模塊'
    }
}

全局對象掛載屬性

假設不考慮CommonJS, AMD, CMD,僅僅將這個模塊作為全局對象的一個屬性應該怎么寫呢?

(function(root, factory) {
    console.log('沒有模塊環境,直接掛載在全局對象上')
    root.umdModule = factory();
}(this, function() {
    return {
        name: '我是一個umd模塊'
    }
}))

我們把factory寫成一個匿名函數,利用IIFE(立即執行函數)去執行工廠函數,返回的對象賦值給root.umdModule,這里的root就是指向全局對象this,其值可能是window或者global,視運行環境而定。

打開效果頁面鏈接(要看源碼的話,點開Git倉庫),觀察Network的文件加載順序,可以看到,原則就是依賴先行。

global調用UMD模塊

再進一步,兼容AMD規范

要兼容AMD也簡單,判斷一下環境,是否滿足AMD規范。如果滿足,則使用require.js提供的define函數定義模塊。

(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // 如果環境中有define函數,並且define函數具備amd屬性,則可以判斷當前環境滿足AMD規范
        console.log('是AMD模塊規范,如require.js')
        define(factory)
    } else {
        console.log('沒有模塊環境,直接掛載在全局對象上')
        root.umdModule = factory();
    }
}(this, function() {
    return {
        name: '我是一個umd模塊'
    }
}))

打開效果頁面鏈接,可以看到,原則是調用者先加載,所依賴的模塊后加載。

requirejs調用UMD模塊

起飛,直接UMD

同理,接着判斷當前環境是否滿足CommonJSCMD規范,分別使用相應的模塊定義方法進行模塊定義。

(function(root, factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        console.log('是commonjs模塊規范,nodejs環境')
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        console.log('是AMD模塊規范,如require.js')
        define(factory)
    } else if (typeof define === 'function' && define.cmd) {
        console.log('是CMD模塊規范,如sea.js')
        define(function(require, exports, module) {
            module.exports = factory()
        })
    } else {
        console.log('沒有模塊環境,直接掛載在全局對象上')
        root.umdModule = factory();
    }
}(this, function() {
    return {
        name: '我是一個umd模塊'
    }
}))

最終,使用require.js, sea.js, nodejs或全局對象掛載屬性等方式都能完美地使用umd-module.js這個模塊,實現了大一統。

給個sea.js調用UMD的效果頁面鏈接,sea.js調用UMD模塊

nodejs調用UMD模塊需要執行node命令,

node umd-simple-used-by-nodejs

效果如下:

nodejs調用umd模塊

有依賴關系的UMD模塊

當然,我們不能止步於此,模塊會被調用,當然也會調用其他模塊。因此我們還需要實現一個有依賴關系的UMD模塊,來驗證UMD規范的可行性。

全局對象掛載屬性

這個簡單,在html中你的模塊前引入所依賴的模塊即可。umd-module-dependedumd-module都是UMD模塊,后者依賴前者。

<!DOCTYPE html>
<html>
    <head>
        <title>Test UMD</title>
        <!-- 依賴放前面 -->
        <script src="assets/js/umd-dep/umd-module-depended.js"></script>
        <script src="assets/js/umd-dep/umd-module.js"></script>
        <script src="assets/js/umd-dep/umd-global.js"></script>
    </head>
    <body>
        <h1>測試UMD模塊</h1>
        <h2></h2>
        <p id="content"></p>
        <p id="content2"></p>
    </body>
</html>

點開效果頁面鏈接,看得更清楚明白!

兼容AMD規范

我們先在入口文件umd-main-requirejs.js中,定義好模塊路徑,方便調用。

require.config({
    baseUrl: "./assets/js/umd-dep/",
    paths: {
        umd: "umd-module",
        depModule: "umd-module-depended"
    }
});

被依賴的模塊umd-module-depended,只需要簡單實現UMD規范即可。

而調用者umd-module,則需要做一些處理。按照require.js的規范來即可, define時,指定依賴的模塊depModule,而匿名工廠函數需要在參數上接收依賴的模塊depModule

(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        console.log('是AMD模塊規范,如require.js')
        define(['depModule'], factory)
    } else {
        console.log('沒有模塊環境,直接掛載在全局對象上')
        root.umdModule = factory(root.depModule);
    }
}(this, function(depModule) {
    console.log('我調用了依賴模塊', depModule)
    // ...省略了一些代碼,去代碼倉庫看吧
    return {
        name: '我自己是一個umd模塊'
    }
}))

打開效果頁面鏈接,看得更清楚明白!

UMD依賴寫法

同理,各種規范要求你怎么寫模塊依賴,你就怎么寫就行。

(function(root, factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        console.log('是commonjs模塊規范,nodejs環境')
        var depModule = require('./umd-module-depended')
        module.exports = factory(depModule);
    } else if (typeof define === 'function' && define.amd) {
        console.log('是AMD模塊規范,如require.js')
        define(['depModule'], factory)
    } else if (typeof define === 'function' && define.cmd) {
        console.log('是CMD模塊規范,如sea.js')
        define(function(require, exports, module) {
            var depModule = require('depModule')
            module.exports = factory(depModule)
        })
    } else {
        console.log('沒有模塊環境,直接掛載在全局對象上')
        root.umdModule = factory(root.depModule);
    }
}(this, function(depModule) {
    console.log('我調用了依賴模塊', depModule)
	// ...省略了一些代碼,去代碼倉庫看吧
    return {
        name: '我自己是一個umd模塊'
    }
}))

給個sea.js調用的示例鏈接

nodejs調用也是通過命令行測試,

node umd-dep-used-by-nodejs

效果如下:

nodejs調用有依賴的UMD模塊

總結

以上實現了簡單的UMD模塊,也驗證了UMD模塊間存在依賴關系時的可行性。雖然本文是以簡單對象導出為例,但足以作為我們深入UMD規范的起點,加油!

最后厚着臉皮求個star點亮我吧

首發鏈接


掃一掃下方小程序二維碼或搜索Tusi博客,即刻閱讀最新文章!

Tusi博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM