Grundlegendes zu (allen) „modularen“ JavaScript-Formaten und -Tools



Guten Tag, Freunde!

Ich präsentiere Ihnen die Übersetzung des Artikels Grundlegendes zu (allen) JavaScript-Modulformaten und -Tools von Dixin.

Beim Erstellen einer Anwendung besteht häufig der Wunsch, den Code in Teile, logische oder funktionale Blöcke (Module) zu unterteilen. JavaScript hatte jedoch zunächst keine Modulunterstützung. Dies hat zur Entstehung verschiedener modularer Technologien geführt. Dieser Artikel beschreibt alle grundlegenden Konzepte, Vorlagen, Bibliotheken, Syntax und Tools für die Arbeit mit Modulen in JavaScript.


IIFE-Modul: JS-Modulvorlage


Indem wir eine Variable in JS definieren, definieren wir sie als globale Variable. Dies bedeutet, dass eine solche Variable in allen auf der aktuellen Seite geladenen JS-Dateien verfügbar ist:

    //   
    let count = 0
    const increase = () => ++count
    const reset = () => {
        count = 0
        console.log(' .')
    }

    //   
    increase()
    reset()

Um eine Verschmutzung des globalen Namespace zu vermeiden, können Sie eine anonyme Funktion verwenden:

    (() => {
        let count = 0
        // ...
    })

Voila, es gibt keine globalen Variablen mehr. Der Code in der Funktion wird jedoch nicht ausgeführt.

IIFE: Sofortiger Funktionsausdruck


Um Code innerhalb einer Funktion auszuführen f, muss er mit ()how aufgerufen werden f(). Zum Ausführen von Code innerhalb einer anonymen Funktion (() => {})sollte ebenfalls verwendet werden (). Es sieht so aus (() => {})():

    (() => {
        let count = 0
        // ...
    })()

Dies wird als IIFE (sofort als Funktionsausdruck bezeichnet) bezeichnet. Ein Modul kann wie folgt definiert werden:

    //  IIFE 
    const iifeCounterModule = (() => {
        let count = 0
        return {
            increase: () => ++count,
            reset: () => {
                count = 0
                console.log(' .')
            }
        }
    })()

    //  IIFE 
    iifeCounterModule.increase()
    iifeCounterModule.reset()

Wir verpacken den Modulcode in IIFE. Eine anonyme Funktion gibt ein Objekt zurück. Dies ersetzt die Exportschnittstelle. Es gibt nur eine globale Variable - den Namen des Moduls (oder seinen Namespace). Anschließend kann der Name des Moduls zum Aufrufen verwendet werden (Export). Dies wird als JS-Modulvorlage bezeichnet.

Verunreinigungen des Imports


Bei der Definition eines Moduls können einige Abhängigkeiten erforderlich sein. Bei Verwendung einer modularen Vorlage ist jedes abhängige Modul eine globale Variable. Abhängige Module können innerhalb einer anonymen Funktion definiert oder als Argumente an sie übergeben werden:

    //  IIFE   
    const iifeCounterModule = ((dependencyModule1, dependencyModule2) => {
        let count = 0
        return {
            increase: () => ++count,
            reset: () => {
                count = 0
                console.log(' .')
            }
        }
    })(dependencyModule1, dependencyModule2)

Frühere Versionen gängiger Bibliotheken wie jQuery verwendeten diese Vorlage (die neueste Version von jQuery verwendet das UMD-Modul).

Modul öffnen: JS-Modulvorlage öffnen


Die offene Modulvorlage wurde von Christian Heilmann geprägt. Diese Vorlage ist ebenfalls IIFE, der Schwerpunkt liegt jedoch auf der Definition aller Schnittstellen als lokale Variablen innerhalb einer anonymen Funktion:

    //   
    const revealingCounterModule = (() => {
        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        return {
            increase,
            reset
        }
    })()

    //   
    revealingCounterModule.increase()
    revealingCounterModule.reset()

Diese Syntax erleichtert das Verständnis, wofür jede Schnittstelle verantwortlich ist (oder was sie tut).

CJS-Modul: CommonJS-Modul oder Node.js-Modul


CommonJS, ursprünglich ServerJS genannt, ist eine Vorlage zum Definieren und Verwenden von Modulen. Es ist in Node.js eingebaut. Standardmäßig ist jede JS-Datei ein CJS. Variablen ermöglichen moduleauch exportsden Export des Moduls (der Datei). Die Funktion ermöglicht requiredas Laden und Verwenden des Moduls. Der folgende Code veranschaulicht die Definition eines Zählermoduls in der CommonJS-Syntax:

    //  CommonJS : commonJSCounterModule.js
    const dependencyModule1 = require('./dependencyModule1')
    const dependencyModule2 = require('./dependencyModule2')

    let count = 0
    const increase = () => ++count
    const reset = () => {
        count = 0
        console.log(' .')
    }

    exports.increase = increase
    exports.reset = reset
    //  ()
    module.exports = {
        increase,
        reset
    }

So wird dieses Modul verwendet:

    //  CommonJS 
    const {
        increase,
        reset
    } = require('./commonJSCounterModule')
    increase()
    reset()
    // 
    const commonJSCounterModule = require('./commonJSCounterModule')
    commonJSCounterModule.increase()
    commonJSCounterModule.reset()

In der Node.js-Laufzeit (Engine) wird diese Vorlage verwendet, indem der Code in die Datei in eine Funktion eingeschlossen wird, an die Variablen exports, moduleund eine Funktion als Parameter übergeben werden require:

    //  CommonJS 
    (function(exports, require, module, __filename, __dirname) {
        const dependencyModule1 = require('./dependencyModule1')
        const dependencyModule2 = require('./dependencyModule2')

        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        module.exports = {
            increase,
            reset
        }

        return module.exports
    }).call(thisValue, exports, require, module, filename, dirname)

    //  CommonJS 
    (function(exports, require, module, __filename, __dirname) {
        const commonJSCounterModule = require('./commonJSCounterModule')
        commonJSCounterModule.increase()
        commonJSCounterModule.reset()
    }).call(thisValue, exports, require, module, filename, dirname)

AMD-Modul oder RequireJS-Modul


AMD ( asynchrone Moduldefinition ) ist eine Vorlage zum Definieren und Verwenden von Modulen. Es wird in der RequireJS- Bibliothek verwendet . AMD enthält eine defineModuldefinitionsfunktion, die den Modulnamen, die Abhängigkeitsnamen und die Factory-Funktion akzeptiert:

    //  AMD 
    define('amdCounterModule', ['dependencyModule1', 'dependencyModule2'], (dependencyModule1, dependencyModule2) => {
        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        return {
            increase,
            reset
        }
    })

Es enthält auch eine Funktion requirezur Verwendung des Moduls:

    //  AMD 
    require(['amdCounterModule'], amdCounterModule => {
        amdCounterModule.increase()
        amdCounterModule.reset()
    })


requireAMD unterscheidet sich von requireCommonJS dadurch, dass die Namen der Module und der Module selbst als Argumente für die Funktion verwendet werden.

Dynamisches Laden


Die Funktion definehat auch einen anderen Zweck. Es nimmt eine Rückruffunktion an und übergibt requiredieser Funktion eine CommonJS-ähnliche Funktion. Innerhalb der Rückruffunktion wird require aufgerufen, um das Modul dynamisch zu laden:

    //   AMD 
    define(require => {
        const dynamicDependencyModule1 = require('dependencyModule1')
        const dynamicDependencyModule2 = require('dependencyModule2')

        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        return {
            increase,
            reset
        }
    })

AMD-Modul vom CommonJS-Modul


Die obige Funktion definekann zusätzlich requiredie Variablen exportsund als Argumente verwenden module. Daher kann defineCode von CommonJS wie folgt ausgeführt werden:

    //  AMD   CommonJS 
    define((require, exports, module) => {
        // CommonJS 
        const dependencyModule1 = require('dependencyModule1')
        const dependencyModule2 = require('dependencyModule2')

        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        exports.increase = increase
        exports.reset = reset
    })

    //  AMD   CommonJS 
    define(require => {
        // CommonJS 
        const counterModule = require('amdCounterModule')
        counterModule.increase()
        counterModule.reset()
    })

UMD-Modul: Universalmoduldefinition oder UmdJS-Modul


UMD ( Universal Module Definition ) - eine Reihe von Vorlagen, mit denen der Betrieb des Moduls in verschiedenen Laufzeitumgebungen sichergestellt werden kann.

UMD für AMD (RequireJS) und Browser


Der folgende Code stellt das Modul sowohl in AMD (RequireJS) als auch im Browser bereit:

    //  UMD   AMD (RequireJS)  
    ((root, factory) => {
        //   define AMD/RequireJS
        if (typeof define === 'function' && define.amd) {
            //  ,      
            define('umdCounterModule', ['dependencyModule1', 'dependencyModule2'], factory)
        } else {
            //  ,    
            //      (  Window)
            //    
            root.umdCounterModule = factory(root.dependencyModule1, root.dependencyModule2)
        }
    })(typeof self !== undefined ? self : this, (dependencyModule1, dependencyModule2) => {
        //  
        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' ')
        }

        return {
            increase,
            reset
        }
    })

Es sieht kompliziert aus, aber es ist nur IIFE. Eine anonyme Funktion bestimmt, ob es eine Funktion definevon AMD / RequireJS gibt.

  • Wenn defineerkannt, wird die Werksfunktion über sie aufgerufen.
  • Wird es definenicht gefunden, wird die Factory-Funktion direkt aufgerufen. Zu diesem Zeitpunkt ist das Argument rootdas Browser-Fensterobjekt. Es empfängt abhängige Module von globalen Variablen (Eigenschaften des Window-Objekts). Wenn ein factoryModul zurückkehrt, wird es auch zu einer globalen Variablen (eine Eigenschaft des Window-Objekts).

UMD für AMD (RequireJS) und CommonJS (Node.js)


Der folgende Code stellt das Modul sowohl in AMD (RequireJS) als auch in CommonJS (Node.js) bereit:

    (define => define((require, exports, module) => {
        //  
        const dependencyModule1 = require("dependencyModule1")
        const dependencyModule2 = require("dependencyModule2")

        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log("Count is reset.")
        }

        module.export = {
            increase,
            reset
        }
    }))( //   module  exports  CommonJS/Node.js
        //    define  AMD/RequireJS
        typeof module === 'object' && module.exports && typeof define !== 'function'
            ? // CommonJS/Node.js.    define
                factory => module.exports = factory(require, exports, module)
            : // AMD/RequireJS.   define
                define)

Hab keine Angst, es ist wieder nur IIFE. Wenn eine anonyme Funktion aufgerufen wird, wird ihr Argument "ausgewertet". Bewertung des Arguments zur Bestimmung der Ausführungsumgebung (definiert durch das Vorhandensein von Variablen moduleund exportsCommonJS / Node.js sowie die Funktionen definevon AMD / RequireJS).

  • Wenn die Laufzeit CommonJS / Node.js ist, erstellt das anonyme Funktionsargument die Funktion manuell define.
  • Wenn die Laufzeit AMD / RequireJS ist, ist das Argument für die anonyme Funktion eine Funktion defineaus dieser Umgebung. Durch Ausführen einer anonymen Funktion wird sichergestellt, dass die Funktion funktioniert define. Innerhalb einer anonymen Funktion wird eine Funktion aufgerufen, um das Modul zu erstellen define.

ES-Modul: ECMAScript2015- oder ES6-Modul


In Version 6 der JS-Spezifikation wurde 2015 eine neue modulare Syntax eingeführt. Dies wird als ECMAScript 2015 (ES2015) oder ECMAScript 6 (ES6) bezeichnet. Grundlage der neuen Syntax sind die Schlüsselwörter importund export. Der folgende Code veranschaulicht die Verwendung des ES-Moduls für den benannten und standardmäßigen (Standard-) Import / Export:

    //  ES : esCounterModule.js  esCounterModule.mjs
    import dependencyModule1 from './dependencyModule1.mjs'
    import dependencyModule2 from './dependencyModule2.mjs'

    let count = 0
    //  
    export const increase = () => ++count
    export const reset = () => {
        count = 0
        console.log(' .')
    }
    //    
    export default {
        increase,
        reset
    }

Um die Moduldatei im Browser zu verwenden, fügen Sie das Tag hinzu <script>und identifizieren Sie es als Modul : <script type="module" src="esCounterModule.js"></script>. Um dieses Modul in Node.js zu verwenden, ändern Sie seine Erweiterung in .mjs:

    //  ES 
    //    
    import {
        increase,
        reset
    } from './esCounterModule.mjs'
    increase()
    reset()
    //      
    import esCounterModule from './esCounterModule.mjs'
    esCounterModule.increase()
    esCounterModule.reset()


Aus Gründen der Abwärtskompatibilität im Browser können Sie ein Tag <script>mit dem folgenden Attribut hinzufügen nomodule:

    <Skriptnomodul>
        alert ('Nicht unterstützt.')
    </ script>

Dynamisches ES-Modul: Dynamisches Modul ECMAScript2020 oder ES11


Die neueste Version 11 der JS 2020-Spezifikation enthält eine integrierte Funktion importfür die dynamische Verwendung von ES-Modulen. Diese Funktion gibt ein Versprechen zurück, sodass Sie das Modul verwenden können mit then:

    //   ES    ,    
    import('./esCounterModule.js').then(({
        increase,
        reset
    }) => {
        increase()
        reset()
    })
    //      
    import('./esCounterModule.js').then(dynamicESCounterModule => {
        dynamicESCounterModule.increase()
        dynamicESCounterModule.reset()
    })

Aufgrund der Tatsache, dass die Funktion importein Versprechen zurückgibt, kann sie das Schlüsselwort verwenden await:

    //   ES   async/await
    (async () => {
        //    
        const {
            increase,
            reset
        } = await import('./esCounterModule.js')
        increase()
        reset()

        //      
        const dynamicESCounterModule = await import('./esCounterModule.js')
        dynamicESCounterModule.increase()
        dynamicESCounterModule.reset()
    })

Systemmodul: SystemJS-Modul


SystemJS ist eine Bibliothek zur Unterstützung von ES-Modulen in älteren Browsern. Das folgende Modul wird beispielsweise mit der ES6-Syntax geschrieben:

    //  ES 
    import dependencyModule1 from "./dependencyModule1.js"
    import dependencyModule2 from "./dependencyModule2.js"
    dependencyModule1.api1()
    dependencyModule2.api2()

    let count = 0
    //  
    export const increase = function() {
        return ++count
    }
    export const reset = function() {
        count = 0
        console.log("Count is reset.")
    }
    //    
    export default {
        increase,
        reset
    }

Dieser Code funktioniert nicht in Browsern, die die ES6-Syntax nicht unterstützen. Eine Lösung für dieses Problem besteht darin, den Code über die System.registerSystemJS-Bibliotheksschnittstelle zu übersetzen :

    //  SystemJS 
    System.register(['./dependencyModule1', './dependencyModule2'], function(exports_1, context_1) {
        'use strict'
        var dependencyModule1_js_1, dependencyModule2_js_1, count, increase, reset
        var __moduleName = context_1 && context_1.id
        return {
            setters: [
                function(dependencyModule1_js_1_1) {
                    dependencyModule1_js_1 = dependencyModule1_js_1_1
                },
                function(dependencyModule2_js_1_1) {
                    dependencyModule2_js_1 = dependencyModule2_js_1_1
                }
            ],
            execute: function() {
                dependencyModule1_js_1.default.api1()
                dependencyModule2_js_1.default.api2()
                count = 0
                //  
                exports_1('increase', increase = function() {
                    return ++count
                })
                exports_1('reset', reset = function() {
                    count = 0
                    console.log(' .')
                })
                //    
                exports_1('default', {
                    increase,
                    reset
                })
            }
        }
    })

Die neue modulare ES6-Syntax ist weg. In älteren Browsern funktioniert der Code jedoch einwandfrei. Diese Transpilation kann automatisch mit Webpack, TypeScript usw. durchgeführt werden.

Dynamisches Laden von Modulen


SystemJS enthält auch eine Funktion importfür den dynamischen Import:

    //  SystemJS   
    System.import('./esCounterModule.js').then(dynamicESCounterModule => {
        dynamicESCounterModule.increase()
        dynamicESCounterModule.reset()
    })

Webpack-Modul: Kompilierung und Zusammenstellung von CJS-, AMD- und ES-Modulen


Webpack ist ein Modul-Builder. Sein Transpiler kombiniert CommonJS-, AMD- und ES-Module in einer einzigen ausgeglichenen modularen Vorlage und sammelt den gesamten Code in einer einzigen Datei. In den folgenden 3 Dateien werden beispielsweise 3 Module mit unterschiedlicher Syntax definiert:

    //  AMD : amdDependencyModule1.js
    define('amdDependencyModule1', () => {
        const api1 = () => {}
        return {
            api1
        }
    })

    //  CommonJS : commonJSDependencyModule2.js
    const dependencyModule2 = require('./commonJSDependencyModule2')
    const api2 = () => dependencyModule1.api1()
    exports.api2 = api2

    //  ES : esCounterModule.js
    import dependencyModule1 from './amdDependencyModule1'
    import dependencyModule2 from './commonJSDependencyModule2'

    let count = 0
    const increase = () => ++count
    const reset = () => {
        count = 0
        console.log(' .')
    }

    export default {
        increase,
        reset
    }

Der folgende Code demonstriert die Verwendung dieses Moduls:

    //  ES : index.js
    import counterModule from './esCounterModule'
    counterModule.increase()
    counterModule.reset()

Webpack kann diese Dateien trotz der Tatsache, dass es sich um verschiedene modulare Systeme handelt, zu einer Datei zusammenfassen main.js:

    Wurzel
        dist
            main.js (Zusammenstellung von Dateien im Ordner src)
        src
            amdDependencyModule1.js
            commonJSDependencyModule2.js
            esCounterModule.js
            index.js
        webpack.config.js

Da Webpack auf Node.js basiert, verwendet es die modulare Syntax von CommonJS. In webpack.config.js:

    const path = require('path')

    module.exports = {
        entry: './src/index.js',
        mode: 'none', //          
        output: {
            filename: 'main.js',
            path: path.resolve(__dirname, 'dist'),
        },
    }

Zum Kompilieren und Erstellen müssen Sie die folgenden Befehle ausführen:

    npm install webpack webpack-cli --save-dev
    npx webpack --config webpack.config.js

Infolgedessen erstellt Webpack die Datei main.js. Der folgende Code wurde main.jsformatiert, um die Lesbarkeit zu verbessern:

    (function(modules) { //  Webpack
        //    
        var installedModules = {}
        //  require
        function require(moduleId) {
            // ,     
            if (installedModules[moduleId]) {
                return installedModules[moduleId].exports
            }
            //        
            var module = installedModules[moduleId] = {
                i: moduleId,
                l: false,
                exports: {}
            }
            //   module
            modules[moduleId].call(module.exports, module, module.exports, require)
            //    
            module.l = true
            //   exports 
            return module.exports
        }

        //   modules (__webpack_modules__)
        require.m = modules
        //    
        require.c = installedModules
        //     
        require.d = function(exports, name, getter) {
            if (!require.o(exports, name)) {
                Object.defineProperty(exports, name, {
                    enumerable: true,
                    get: getter
                })
            }
        }
        //  __esModule  exports
        require.r = function(exports) {
            if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
                Object.defineProperty(exports, Symbol.toStringTag, {
                    value: 'Module'
                })
            }
            Object.defineProperty(exports, '__esModule', {
                value: true
            })
        }
        //       
        // mode & 1:  -  ,  
        // mode & 2:       ns (namespace)
        // mode & 4:  ,   ns  
        // mode & 8|1:   require
        require.t = function(value, mode) {
            if (mode & 1) value = require(value)
            if (mode & 8) return value
            if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value
            var ns = Object.create(null)
            require.r(ns)
            Object.defineProperty(ns, 'default', {
                enumerable: true,
                value: value
            })
            if (mode & 2 && typeof value !== 'string')
                for (var key in value) require.d(ns, key, function(key) {
                    return value[key]
                }.bind(null, key))
            return ns
        }
        //  getDefaultExport      
        require.n = function(module) {
            var getter = module && module.__esModule ?
                function getDefault() {
                    return module['default']
                } :
                function getModuleExports() {
                    return module
                }
            require.d(getter, 'a', getter)
            return getter
        }
        // Object.prototype.hasOwnProperty.call
        require.o = function(object, property) {
            return Object.prototype.hasOwnProperty.call(object, property)
        }
        // __webpack_public_path__
        require.p = ''
        //      exports
        return require(require.s = 0)
    })([
        function(module, exports, require) {
            'use strict'
            require.r(exports)
            //  ES : index.js
            var esCounterModule = require(1)
            esCounterModule['default'].increase()
            esCounterModule['default'].reset()
        },
        function(module, exports, require) {
            'use strict'
            require.r(exports)
            //  ES : esCounterModule.js
            var amdDependencyModule1 = require.n(require(2))
            var commonJSDependencyModule2 = require.n(require(3))
            amdDependencyModule1.a.api1()
            commonJSDependencyModule2.a.api2()

            let count = 0
            const increase = () => ++count
            const reset = () => {
                count = 0
                console.log(' .')
            }

            exports['default'] = {
                increase,
                reset
            }
        },
        function(module, exports, require) {
            var result!(result = (() => {
                    //  AMD : amdDependencyModule1.js
                    const api1 = () => {}
                    return {
                        api1
                    }
                }).call(exports, require, exports, module),
                result !== undefined && (module.exports = result))
        },
        function(module, exports, require) {
            //  CommonJS : commonJSDependencyModule2.js
            const dependencyModule1 = require(2)
            const api2 = () => dependencyModule1.api1()
            exports.api2 = api2
        }
    ])

Und wieder ist dies nur IIFE. Der Code aus 4 Dateien wird in ein Array von 4 Funktionen konvertiert. Und dieses Array wird als Parameter an die anonyme Funktion übergeben.

Babel-Modul: Transpilation des ES-Moduls


Babel ist ein weiterer Transporter zur Unterstützung von ES6 + -Code in älteren Browsern. Das obige ES6 + -Modul kann wie folgt in ein Babel-Modul konvertiert werden:

    // Babel
    Object.defineProperty(exports, '__esModule', {
        value: true
    })
    exports['default'] = void 0

    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            'default': obj
        }
    }

    //  ES : esCounterModule.js
    var dependencyModule1 = _interopRequireDefault(require('./amdDependencyModule1'))
    var dependencyModule2 = _interopRequireDefault(require('./commonJSDependencyModule2'))
    dependencyModule1['default'].api1()
    dependencyModule2['default'].api2()

    var count = 0
    var increase = function() {
        return ++count
    }
    var reset = function() {
        count = 0
        console.log(' .')
    }

    exports['default'] = {
        increase: increase,
        reset: reset
    }

Und hier ist der Code index.js, der die Verwendung dieses Moduls demonstriert:

    // Babel
    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            'default': obj
        }
    }

    //  ES : index.js
    var esCounterModule = _interopRequireDefault(require('./esCounterModule.js'))
    esCounterModule['default'].increase()
    esCounterModule['default'].reset()

Dies ist die Standardtranspilation. Babel weiß auch, wie man mit anderen Werkzeugen arbeitet.

Babel und SystemJS


SystemJS kann als Plugin für Babel verwendet werden:

    npm install --save-dev @ babel / plugin-transform-modules-systemjs


Dieses Plugin sollte hinzugefügt werden zu babel.config.json:

    {
        'plugins': ['@ babel / plugin-transform-modules-systemjs'],
        'Presets': [
            [
            '@ babel / env',
                {
                    'Ziele': {
                        'dh': '11'
                    }}
                }}
            ]]
        ]]
    }}

Jetzt kann Babel mit SystemJS zusammenarbeiten, um CommonJS / Node.js-, AMD / RequireJS- und ES-Module zu transpilieren:

    npx babel src --out-dir lib

Ergebnis:

    Wurzel
        lib
            amdDependencyModule1.js (transpiliert mit SystemJS)
            commonJSDependencyModule2.js (transpiliert mit SystemJS)
            esCounterModule.js (transpiliert mit SystemJS)
            index.js (transpiliert mit SystemJS)
        src
            amdDependencyModule1.js
            commonJSDependencyModule2.js
            esCounterModule.js
            index.js
        babel.config.json

Die gesamte Syntax von AMD-, CommonJS- und ES-Modulen wird in die SystemJS-Syntax übertragen:

    //  AMD/RequireJS   SystemJS : lib/amdDependencyModule1.js
    System.register([], function(_export, _context) {
        'use strict'
        return {
            setters: [],
            execute: function() {
                //  AMD : src/amdDependencyModule1.js
                define('amdDependencyModule1', () => {
                    const api1 = () => {}

                    return {
                        api1
                    }
                })
            }
        }
    })

    //  CommonJS/Node.js   SystemJS : lib/commonJSDependencyModule2.js.
    System.register([], function(_export, _context) {
        'use strict'
        var dependencyModule1, api2
        return {
            setters: [],
            execute: function() {
                //  CommonJS : src/commonJSDependencyModule2.js
                dependencyModule1 = require('./amdDependencyModule1')

                api2 = () => dependencyModule1.api1()

                exports.api2 = api2
            }
        }
    })

    //  ES   SystemJS 
    System.register(['./amdDependencyModule1', './commonJSDependencyModule2'], function(_export, _context) {
        var dependencyModule1, dependencyModule2, count, increase, reset
        return {
            setters: [function(_amdDependencyModule) {
                dependencyModule1 = _amdDependencyModule.default
            }, function(_commonJSDependencyModule) {
                dependencyModule2 = _commonJSDependencyModule.default
            }],
            execute: function() {
                //  ES : src/esCounterModule.js
                dependencyModule1.api1()
                dependencyModule1.api2()
                count = 0

                increase = () => ++count

                reset = () => {
                    count = 0
                    console.log(' .')
                }

                _export('default', {
                    increase,
                    reset
                })
            }
        }
    })

    //  ES   SystemJS : lib/index.js
    System.register(['./esCounterModule'], function(_export, _context) {
        var esCounterModule
        return {
            setters: [function(_esCounterModule) {
                esCounterModule = _esCounterModule.default
            }],
            execute: function() {
                //  ES : src/index.js
                esCounterModule.increase()
                esCounterModule.reset()
            }
        }
    })

TypeScript-Modul: Transpilation von CJS-, AMD-, ES- und SystemJS-Modulen


TypeScript unterstützt alle Varianten der JS-Syntax, einschließlich ES6. Während der Transpilation kann die Syntax des ES6-Moduls gespeichert oder in ein anderes Format konvertiert werden, einschließlich CommonJS / Node.js, AMD / RequireJS, UMD / UmdJS oder SystemJS, gemäß den Einstellungen der Transpilation in tsconfig.json:

    {
        'compilerOptions': {
            'Modul': 'ES2020' // Keine, CommonJS, AMD, System,
            UMD, ES6, ES2015, ESNext
        }}
    }}

Zum Beispiel:

    // TypeScript  ES 
    //  compilerOptions: { module: 'ES6' }.    
    import dependencyModule from './dependencyModule'
    dependencyModule.api()
    let count = 0
    export const increase = function() {
        return ++count
    }

    //  compilerOptions: { module: 'CommonJS' }.   CommonJS/Node.js 
    var __importDefault = (this && this.__importDefault) || function(mod) {
        return (mod && mod.__esModule) ? mod : {
            'default': mod
        }
    }
    exports.__esModule = true

    var dependencyModule_1 = __importDefault(require('./dependencyModule'))
    dependencyModule_1['default'].api()
    var count = 0
    exports.increase = function() {
        return ++count
    }

    //  compilerOptions: { module: 'AMD' }.   AMD/RequireJS 
    var __importDefault = (this && this.__importDefault) || function(mod) {
        return (mod && mod.__esModule) ? mod : {
            'default': mod
        }
    }
    define(['require', 'exports', './dependencyModule'], function(require, exports, dependencyModule_1) {
        'use strict'
        exports.__esModule = true

        dependencyModule_1 = __importDefault(dependencyModule_1)
        dependencyModule_1['default'].api()
        var count = 0
        exports.increase = function() {
            return ++count
        }
    })

    //  compilerOptions: { module: 'UMD' }.   UMD/UmdJS 
    var __importDefault = (this & this.__importDefault) || function(mod) {
            return (mod && mod.__esModule) ? mod : {
                'default': mod
            }
        }
        (function(factory) {
            if (typeof module === 'object' && typeof module.exports === 'object') {
                var v = factory(require, exports)
                if (v !== undefined) module.exports = v
            } else if (typeof define === 'function' && define.amd) {
                define(['require', 'exports', './dependencyModule'], factory)
            }
        })(function(require, exports) {
            'use strict'
            exports.__esModule = true

            var dependencyModule_1 = __importDefault(require('./dependencyModule'))
            dependencyModule_1['default'].api()
            var count = 0
            exports.increase = function() {
                return ++count
            }
        })

    //  compilerOptions: { module: 'System' }.   System/SystemJS 
    System.register(['./dependencyModule'], function(exports_1, context_1) {
        'use strict'
        var dependencyModule_1, count, increase
        car __moduleName = context_1 && context_1.id
        return {
            setters: [
                function(dependencyModule_1_1) {
                    dependencyModule_1 = dependencyModule_1_1
                }
            ],
            execute: function() {
                dependencyModule_1['default'].api()
                count = 0
                exports_1('increase', increase = function() {
                    return ++count
                })
            }
        }
    })

Die von TypeScript unterstützte modulare ES-Syntax wird als externe Module bezeichnet.

Interne Module und Namespace


TypeScript hat auch Schlüsselwörter moduleund namespace. Sie werden interne Module genannt:

    module Counter {
        let count = 0
        export const increase = () => ++count
        export const reset = () => {
            count = 0
            console.log(' .')
        }
    }

    namespace Counter {
        let count = 0
        export const increase = () => ++count
        export const reset = () => {
            count = 0
            console.log(' .')
        }
    }

Beide werden in JS-Objekte transponiert:

    var Counter;
    (function(Counter) {
        var count = 0
        Counter.increase = function() {
            return ++count
        }
        Counter.reset = function() => {
            count = 0
            console.log(' .')
        }
    })(Counter || (Counter = {}))

Das TypeScript-Modul und der Namespace können mehrere Verschachtelungsebenen durch das Trennzeichen aufweisen .:

    module Counter.Sub {
        let count = 0
        export const increase = () => ++count
    }

    namespace Counter.Sub {
        let count = 0
        export const increase = () => ++count
    }

Submodul und Subnamespace werden in Objekteigenschaften umgesetzt:

    var Counter;
    (function(Counter) {
        var Sub;
        (function(Sub) {
            var count = 0
            Sub.increase = function() {
                return ++count
            }
        })(Sub = Counter.Sub || (Counter.Sub = {}))
    })(Counter || (Counter = {}))

Das TypeScript-Modul und der Namespace können auch in einer Anweisung verwendet werden export:

    module Counter {
        let count = 0
        export module Sub {
            export const increase = () => ++count
        }
    }

    module Counter {
        let count = 0
        export namespace Sub {
            export const increase = () => ++count
        }
    }

Der obige Code wird auch in Submodul und Subnamespace übersetzt:

    var Counter;
    (function(Counter) {
        var count = 0
        var Sub;
        (function(Sub) {
            Sub.increase = function() {
                return ++count
            }
        })(Sub = Counter.Sub || (Counter.Sub = {}))
    })(Counter || (Counter = {}))

Fazit


Willkommen bei JS mit mehr als 10 Systemen / Modulationsformaten / Namespaces:

  • IIFE-Modul: JS-Modulvorlage
  • Modul öffnen: JS-Modulvorlage öffnen
  • CJS-Modul: CommonJS-Modul oder Node.js-Modul
  • AMD-Modul: asynchrone Moduldefinition oder RequireJS-Modul
  • UMD-Modul: Universalmoduldefinition oder UmdJS-Modul
  • ES-Modul: ECMAScript2015- oder ES6-Modul
  • Dynamisches ES-Modul: Dynamisches Modul ECMAScript2020 oder ES11
  • Systemmodul: SystemJS-Modul
  • Webpack-Modul: Kompilierung und Zusammenstellung von CJS-, AMD- und ES-Modulen
  • Babel-Modul: Transpilation des ES-Moduls
  • TypeScript-Modul und Namespace

Glücklicherweise verfügt JS derzeit über integrierte Standardtools für die Arbeit mit Modulen, die von Node.js und allen modernen Browsern unterstützt werden. Für ältere Browser können Sie die neue modulare ES-Syntax verwenden und sie mit Webpack / Babel / SystemJS / TypeScript in eine kompatible Syntax übersetzen.

Vielen Dank für Ihre Zeit. Ich hoffe es wurde gut angelegt.

All Articles