Memahami (semua) format dan alat JavaScript "modular"



Selamat siang teman!

Saya mempersembahkan kepada Anda terjemahan artikel “Memahami (semua) format dan alat modul JavaScript” oleh Dixin.

Saat membuat aplikasi, sering kali ada keinginan untuk membagi kode menjadi beberapa bagian, blok logis atau fungsional (modul). Namun, JavaScript pada awalnya tidak memiliki dukungan modul. Ini telah menyebabkan munculnya berbagai teknologi modular. Artikel ini membahas semua konsep dasar, templat, pustaka, sintaksis dan alat untuk bekerja dengan modul dalam JavaScript.


Modul IIFE: Templat modul JS


Dengan mendefinisikan variabel dalam JS, kami mendefinisikannya sebagai variabel global. Ini berarti bahwa variabel tersebut akan tersedia di semua file JS yang dimuat di halaman saat ini:

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

    //   
    increase()
    reset()

Untuk menghindari polusi namespace global, Anda dapat menggunakan fungsi anonim:

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

Voila, tidak ada lagi variabel global. Namun, kode di dalam fungsi tidak dieksekusi.

IIFE: ekspresi fungsi langsung


Untuk menjalankan kode di dalam suatu fungsi f, ia harus dipanggil menggunakan ()cara f(). Untuk menjalankan kode di dalam fungsi anonim (() => {})juga harus digunakan (). Ini terlihat seperti ini (() => {})():

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

Ini disebut IIFE (langsung disebut ekspresi fungsi). Modul dapat didefinisikan sebagai berikut:

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

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

Kami membungkus kode modul dalam IIFE. Fungsi anonim mengembalikan objek. Ini menggantikan antarmuka ekspor. Hanya ada satu variabel global - nama modul (atau ruang namanya). Selanjutnya, nama modul dapat digunakan untuk menyebutnya (ekspor). Ini disebut templat modul JS.

Kotoran impor


Saat mendefinisikan modul, beberapa dependensi mungkin diperlukan. Saat menggunakan template modular, setiap modul dependen adalah variabel global. Modul dependen dapat didefinisikan di dalam fungsi anonim atau diteruskan sebagai argumen:

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

Versi sebelumnya dari pustaka populer seperti jQuery menggunakan templat ini (versi jQuery terbaru menggunakan modul UMD).

Buka modul: buka templat modul JS


Template modul terbuka diciptakan oleh Christian Heilmann. Template ini juga IIFE, tetapi penekanannya adalah pada mendefinisikan semua antarmuka sebagai variabel lokal di dalam fungsi anonim:

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

        return {
            increase,
            reset
        }
    })()

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

Sintaks ini membuatnya lebih mudah untuk memahami apa yang bertanggung jawab untuk masing-masing antarmuka (atau apa fungsinya).

Modul CJS: Modul CommonJS atau modul Node.js


CommonJS, awalnya bernama ServerJS, adalah templat untuk mendefinisikan dan menggunakan modul. Itu dibangun ke Node.js. Secara default, setiap file JS adalah CJS. Variabel modulejuga exportsmenyediakan ekspor modul (file). Fungsi ini requiremenyediakan memuat dan menggunakan modul. Kode berikut menunjukkan definisi modul penghitung dalam sintaks CommonJS:

    //  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
    }

Begini cara modul ini digunakan:

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

Dalam runtime Node.js (engine), templat ini digunakan dengan membungkus kode di dalam file ke dalam suatu fungsi, ke mana variabel exports, moduledan fungsi dilewatkan sebagai parameter 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)

Modul AMD atau modul RequireJS


AMD ( definisi modul asinkron ) adalah templat untuk mendefinisikan dan menggunakan modul. Ini digunakan di perpustakaan RequireJS . AMD berisi fungsi definedefinisi modul yang menerima nama modul, nama dependensi, dan fungsi pabrik:

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

        return {
            increase,
            reset
        }
    })

Ini juga berisi fungsi requireuntuk menggunakan modul:

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


requireAMD berbeda dari requireCommonJS karena AMD mengambil nama modul dan modul itu sendiri sebagai argumen untuk fungsi tersebut.

Pemuatan dinamis


Fungsi tersebut definejuga memiliki tujuan yang berbeda. Dibutuhkan fungsi callback dan meneruskan requirefungsi seperti CommonJS ke fungsi ini. Di dalam fungsi panggilan balik, mengharuskan dipanggil untuk memuat modul secara dinamis:

    //   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
        }
    })

Modul AMD dari modul CommonJS


Fungsi di atas define, di samping itu require, dapat mengambil variabel exportsdan sebagai argumen module. Karenanya, definekode dari CommonJS dapat dieksekusi di dalam :

    //  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()
    })

Modul UMD: definisi modul universal atau modul UmdJS


UMD ( universal module definition ) - satu set templat untuk memastikan operasi modul dalam lingkungan runtime yang berbeda.

UMD untuk AMD (RequireJS) dan browser


Kode berikut menyediakan modul dalam AMD (RequireJS) dan browser:

    //  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
        }
    })

Terlihat rumit, tapi itu hanya IIFE. Fungsi anonim menentukan apakah ada fungsi definedari AMD / RequireJS.

  • Jika defineterdeteksi, fungsi pabrik dipanggil melaluinya.
  • Jika definetidak ditemukan, fungsi pabrik dipanggil langsung. Pada titik ini, argumennya rootadalah objek Window browser. Ini menerima modul tergantung dari variabel global (properti dari objek Window). Ketika factorymodul kembali, itu juga menjadi variabel global (properti dari objek Window).

UMD untuk AMD (RequireJS) dan CommonJS (Node.js)


Kode berikut menyediakan modul dalam AMD (RequireJS) dan CommonJS (Node.js):

    (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)

Jangan takut, itu hanya IIFE lagi. Ketika fungsi anonim dipanggil, argumennya "dievaluasi". Menilai argumen untuk menentukan lingkungan eksekusi (ditentukan oleh keberadaan variabel moduledan exportsCommonJS / Node.js, dan fungsi defineAMD / RequireJS).

  • Jika runtime adalah CommonJS / Node.js, argumen fungsi anonim secara manual membuat fungsi define.
  • Jika runtime adalah AMD / RequireJS, argumen ke fungsi anonim adalah fungsi definedari lingkungan itu. Melakukan fungsi anonim memastikan bahwa fungsi tersebut berfungsi define. Di dalam fungsi anonim, fungsi dipanggil untuk membuat modul define.

Modul ES: modul ECMAScript2015 atau ES6


Pada 2015, versi 6 dari spesifikasi JS memperkenalkan sintaksis modular baru. Ini disebut ECMAScript 2015 (ES2015) atau ECMAScript 6 (ES6). Dasar dari sintaks baru adalah kata kunci importdan export. Kode berikut menunjukkan penggunaan modul ES untuk impor / ekspor bernama dan default (default):

    //  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
    }

Untuk menggunakan file modul dalam browser, menambahkan tag <script>dan mengidentifikasinya sebagai modul: <script type="module" src="esCounterModule.js"></script>. Untuk menggunakan modul ini di Node.js, ubah ekstensinya menjadi .mjs:

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


Untuk kompatibilitas mundur di browser, Anda dapat menambahkan tag <script>dengan atribut nomodule:

    <script nomodule>
        lansiran ('Tidak didukung.')
    </script>

Modul dinamis ES: Modul dinamis ECMAScript2020 atau ES11


Versi 11 terbaru dari spesifikasi JS 2020 memperkenalkan fungsi bawaan importuntuk penggunaan dinamis modul ES. Fungsi ini mengembalikan janji, sehingga Anda dapat menggunakan modul dengan then:

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

Karena fakta bahwa fungsi importmengembalikan janji, ia dapat menggunakan kata kunci await:

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

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

Modul Sistem: Modul SystemJS


SystemJS adalah pustaka untuk mendukung modul ES di browser lama. Misalnya, modul berikut ditulis menggunakan sintaks ES6:

    //  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
    }

Kode ini tidak akan berfungsi di browser yang tidak mendukung sintaks ES6. Salah satu solusi untuk masalah ini adalah menerjemahkan kode menggunakan System.registerantarmuka perpustakaan SystemJS:

    //  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
                })
            }
        }
    })

Sintaks ES6 modular baru hilang. Tetapi kode ini akan berfungsi dengan baik di browser lama. Transpilasi ini dapat dilakukan secara otomatis menggunakan Webpack, TypeScript, dll.

Memuat modul dinamis


SystemJS juga berisi fungsi importuntuk impor dinamis:

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

Modul Webpack: kompilasi dan perakitan modul CJS, AMD dan ES


Webpack adalah pembangun modul. Transpilernya menggabungkan modul CommonJS, AMD dan ES ke dalam template modular tunggal yang seimbang dan mengumpulkan semua kode ke dalam satu file. Misalnya, dalam 3 file berikut, 3 modul didefinisikan menggunakan sintaks yang berbeda:

    //  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
    }

Kode berikut menunjukkan penggunaan modul ini:

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

Webpack dapat menggabungkan file-file ini, meskipun faktanya mereka adalah sistem modular yang berbeda, menjadi satu file main.js:

    akar
        dist
            main.js (kumpulan file yang terletak di folder src)
        src
            amdDependencyModule1.js
            commonJSDependencyModule2.js
            esCounterModule.js
            index.js
        webpack.config.js

Karena Webpack didasarkan pada Node.js, ia menggunakan sintaksis modular CommonJS. Dalam webpack.config.js:

    const path = require('path')

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

Untuk mengkompilasi dan membangun, Anda harus menjalankan perintah berikut:

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

Akibatnya, Webpack akan membuat file main.js. Kode berikut main.jsdiformat untuk meningkatkan keterbacaan:

    (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
        }
    ])

Dan lagi, ini hanya IIFE. Kode dari 4 file dikonversi menjadi 4 fungsi array. Dan array ini diteruskan ke fungsi anonim sebagai parameter.

Modul Babel: transpilasi modul ES


Babel adalah transporter lain untuk mendukung kode ES6 + di browser lama. Modul ES6 + di atas dapat dikonversi ke modul Babel sebagai berikut:

    // 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
    }

Dan ini adalah kodenya index.js, yang menunjukkan penggunaan modul ini:

    // 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()

Ini adalah transpilasi default. Babel juga tahu cara bekerja dengan alat lain.

Babel dan SystemJS


SystemJS dapat digunakan sebagai plugin untuk Babel:

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


Plugin ini harus ditambahkan ke babel.config.json:

    {
        'plugins': ['@ babel / plugin-transform-modules-systemjs'],
        'preset': [
            [
            '@ babel / env',
                {
                    'target': {
                        'ie': '11'
                    }
                }
            ]
        ]
    }

Sekarang Babel dapat bekerja dengan SystemJS untuk mentransformasikan modul CommonJS / Node.js, AMD / RequireJS dan ES:

    npx babel src --out-dir lib

Hasil:

    akar
        Lib
            amdDependencyModule1.js (dialihkan menggunakan SystemJS)
            commonJSDependencyModule2.js (dialihkan menggunakan SystemJS)
            esCounterModule.js (dialihkan menggunakan SystemJS)
            index.js (dialihkan menggunakan SystemJS)
        src
            amdDependencyModule1.js
            commonJSDependencyModule2.js
            esCounterModule.js
            index.js
        babel.config.json

Seluruh sintaks modul AMD, CommonJS dan ES ditransformasikan ke dalam sintaksis SystemJS:

    //  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()
            }
        }
    })

Modul TypeScript: transpilasi modul CJS, AMD, ES dan SystemJS


TypeScript mendukung semua rasa sintaks JS, termasuk ES6. Selama transpilasi, sintaks modul ES6 dapat disimpan atau dikonversi ke format lain, termasuk CommonJS / Node.js, AMD / RequireJS, UMD / UmdJS atau SystemJS sesuai dengan pengaturan transpilasi di tsconfig.json:

    {
        'compilerOptions': {
            'modul': 'ES2020' // Tidak ada, CommonJS, AMD, System,
            UMD, ES6, ES2015, ESNext
        }
    }

Contohnya:

    // 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
                })
            }
        }
    })

Sintaks ES modular yang didukung oleh TypeScript disebut modul eksternal.

Modul Internal dan Namespace


TypeScript juga memiliki kata kunci moduledan namespace. Mereka disebut modul internal:

    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(' .')
        }
    }

Keduanya ditransformasikan menjadi objek JS:

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

Modul dan namespace TypeScript dapat memiliki beberapa tingkat bersarang melalui pemisah .:

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

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

Sub modul dan sub namespace dipindahkan ke properti objek:

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

Modul dan namespace TypeScript juga dapat digunakan dalam pernyataan 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
        }
    }

Kode di atas juga diterjemahkan ke dalam sub module dan sub namespace:

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

Kesimpulan


Selamat datang di JS, yang memiliki 10+ sistem / format modulasi / namespaces:

  • Modul IIFE: Templat modul JS
  • Buka modul: buka templat modul JS
  • Modul CJS: Modul CommonJS atau modul Node.js
  • Modul AMD: definisi modul asinkron atau modul RequireJS
  • Modul UMD: definisi modul universal atau modul UmdJS
  • Modul ES: modul ECMAScript2015 atau ES6
  • Modul dinamis ES: Modul dinamis ECMAScript2020 atau ES11
  • Modul Sistem: Modul SystemJS
  • Modul Webpack: kompilasi dan perakitan modul CJS, AMD dan ES
  • Modul Babel: transpilasi modul ES
  • Modul TypeScript dan namespace

Untungnya, JS saat ini memiliki alat bawaan bawaan untuk bekerja dengan modul yang didukung oleh Node.js dan semua peramban modern. Untuk browser yang lebih lama, Anda dapat menggunakan sintaks ES modular baru, menerjemahkannya ke dalam sintaks yang kompatibel menggunakan Webpack / Babel / SystemJS / TypeScript.

Terima kasih atas waktu Anda. Saya harap itu dihabiskan dengan baik.

All Articles