فهم (جميع) تنسيقات وأدوات JavaScript "المعيارية" والأدوات



يوم جيد يا اصدقاء!

أقدم لكم ترجمة مقالة "فهم (جميع) تنسيقات وحدة جافا سكريبت وأدواتها" بواسطة Dixin.

عند إنشاء تطبيق ، غالبًا ما تكون هناك رغبة في تقسيم التعليمات البرمجية إلى أجزاء أو كتل منطقية أو وظيفية (وحدات). ومع ذلك ، لم يكن جافا سكريبت في البداية يدعم الوحدة. وقد أدى ذلك إلى ظهور تقنيات معيارية مختلفة. تتناول هذه المقالة جميع المفاهيم الأساسية ، والقوالب ، والمكتبات ، وبناء الجملة ، وأدوات العمل مع الوحدات النمطية في JavaScript.


وحدة IIFE: قالب وحدة JS


من خلال تحديد متغير في JS ، نحدده كمتغير عام. هذا يعني أن هذا المتغير سيكون متاحًا في جميع ملفات JS التي تم تحميلها في الصفحة الحالية:

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

    //   
    increase()
    reset()

لتجنب تلوث مساحة الاسم العالمية ، يمكنك استخدام وظيفة مجهولة:

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

فويلا ، لم يعد هناك متغيرات عالمية. ومع ذلك ، لا يتم تنفيذ التعليمات البرمجية داخل الدالة.

IIFE: تعبير دالة فوري


من أجل تنفيذ التعليمات البرمجية داخل دالة f، يجب استدعاؤها باستخدام ()كيفية f(). لتنفيذ التعليمات البرمجية داخل وظيفة مجهولة (() => {})يجب أيضًا استخدامها (). يبدو هذا (() => {})():

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

وهذا ما يسمى IIFE (يسمى التعبير الوظيفي مباشرة). يمكن تعريف الوحدة على النحو التالي:

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

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

نلف رمز الوحدة النمطية في IIFE. تقوم دالة مجهولة بإرجاع كائن. هذا يحل محل واجهة التصدير. يوجد متغير عام واحد فقط - اسم الوحدة (أو مساحة الاسم الخاصة بها). في وقت لاحق ، يمكن استخدام اسم الوحدة النمطية لتسميتها (التصدير). وهذا ما يسمى قالب وحدة JS.

شوائب الاستيراد


عند تحديد وحدة ، قد تكون هناك حاجة لبعض التبعيات. عند استخدام قالب معياري ، تكون كل وحدة تابعة متغيرًا عامًا. يمكن تعريف الوحدات التابعة داخل دالة مجهولة أو تمريرها إليها كوسيطة:

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

استخدمت الإصدارات السابقة من المكتبات الشائعة مثل jQuery هذا القالب (يستخدم أحدث إصدار من jQuery وحدة UMD).

وحدة مفتوحة: افتح نموذج وحدة JS


صاغ قالب الوحدة المفتوحة من قبل كريستيان هيلمان. هذا القالب هو أيضًا IIFE ، ولكن التركيز على تحديد جميع الواجهات كمتغيرات محلية داخل دالة مجهولة:

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

        return {
            increase,
            reset
        }
    })()

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

هذا النحو يجعل من السهل فهم ما تتحمله كل واجهة (أو ما تفعله).

وحدة CJS: وحدة CommonJS أو وحدة Node.js


CommonJS ، المسمى أصلاً ServerJS ، هو قالب لتحديد الوحدات النمطية واستخدامها. وهي مدمجة في Node.js. بشكل افتراضي ، كل ملف JS هو CJS. توفر المتغيرات moduleأيضًا exportsتصدير الوحدة النمطية (ملف). requireتوفر الوظيفة التحميل واستخدام الوحدة. يوضح الكود التالي تعريف وحدة العداد في بناء جملة 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
    }

إليك كيفية استخدام هذه الوحدة:

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

في وقت تشغيل Node.js (المحرك) ، يتم استخدام هذا القالب من خلال التفاف الكود داخل الملف في دالة ، يتم تمرير المتغيرات exports, moduleوالدالة إليها كمعلمات 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 أو RequireJS module


AMD ( تعريف الوحدة غير المتزامنة ) هو قالب لتحديد واستخدام الوحدات. يتم استخدامه في مكتبة RequireJS . يحتوي AMD على وظيفة defineتعريف الوحدة التي تقبل اسم الوحدة وأسماء التبعيات ووظيفة المصنع:

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

        return {
            increase,
            reset
        }
    })

يحتوي أيضًا على وظيفة requireلاستخدام الوحدة:

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


requireيختلف AMD عن requireCommonJS في أنه يأخذ أسماء الوحدات والوحدات نفسها كوسيطة للدالة.

تحميل ديناميكي


الوظيفة defineلها غرض مختلف. يأخذ وظيفة رد الاتصال ويمرر requireوظيفة شبيهة CommonJS إلى هذه الوظيفة. داخل وظيفة رد الاتصال ، يتم استدعاء مطلوب لتحميل الوحدة بشكل ديناميكي:

    //   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 من وحدة CommonJS


الدالة أعلاه define، بالإضافة require، يمكن أن تأخذ المتغيرات exportsو كوسائط module. لذلك ، defineيمكن تنفيذ التعليمات البرمجية من CommonJS داخل :

    //  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: تعريف الوحدة العالمي أو وحدة UmdJS


UMD ( تعريف الوحدة العالمية ) - مجموعة من القوالب لضمان تشغيل الوحدة في بيئات وقت التشغيل المختلفة.

UMD لـ AMD (RequireJS) والمتصفح


يوفر الكود التالي الوحدة النمطية في كل من AMD (RequireJS) والمتصفح:

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

يبدو الأمر معقدًا ، ولكنه IIFE فقط. تحدد الدالة المجهولة ما إذا كانت هناك وظيفة defineمن AMD / RequireJS.

  • إذا تم defineالكشف عن ذلك ، يتم استدعاء وظيفة المصنع من خلاله.
  • إذا defineلم يتم العثور عليها ، يتم استدعاء وظيفة المصنع مباشرة. عند هذه النقطة ، الحجة rootهي كائن نافذة المستعرض. يتلقى وحدات تابعة من المتغيرات العالمية (خصائص كائن النافذة). عندما factoryتعود الوحدة النمطية ، فإنها تصبح أيضًا متغيرًا عامًا (خاصية لكائن النافذة).

UMD لـ AMD (RequireJS) و CommonJS (Node.js)


يوفر الكود التالي الوحدة النمطية في كل من AMD (RequireJS) و 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)

لا تخف ، إنها IIFE فقط مرة أخرى. عندما يتم استدعاء دالة مجهولة ، يتم تقييم حجتها. تقييم الحجة لتحديد بيئة التنفيذ (المحددة من خلال وجود المتغيرات moduleو exportsCommonJS / Node.js ، ووظائف defineAMD / RequireJS).

  • إذا كان وقت التشغيل هو CommonJS / Node.js ، فإن وسيطة الدالة المجهولة تنشئ الوظيفة يدويًا define.
  • إذا كان وقت التشغيل هو AMD / RequireJS ، فإن وسيطة الدالة المجهولة هي دالة defineمن تلك البيئة. يضمن أداء وظيفة مجهولة أن تعمل الوظيفة define. داخل دالة مجهولة ، يتم استدعاء دالة لإنشاء الوحدة النمطية define.

وحدة ES: وحدة ECMAScript2015 أو ES6


في عام 2015 ، قدم الإصدار 6 من مواصفات JS بناءًا معياريًا جديدًا. وهذا ما يسمى ECMAScript 2015 (ES2015) أو ECMAScript 6 (ES6). أساس بناء الجملة الجديد هو الكلمات الرئيسية importو export. يوضح الكود التالي استخدام وحدة ES للاستيراد / التصدير الافتراضي (الافتراضي) المسمى:

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

لاستخدام ملف وحدة في المتصفح، إضافة العلامة <script>والتعرف عليه وحدة نمطية: <script type="module" src="esCounterModule.js"></script>. لاستخدام هذه الوحدة في Node.js ، قم بتغيير امتدادها إلى .mjs:

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


للتوافق مع الإصدارات السابقة في المتصفح ، يمكنك إضافة علامة <script>بالسمة nomodule:

    <رمز البرنامج النصي>
        تنبيه ("غير مدعوم")
    </script>

الوحدة الديناميكية ES: الوحدة الديناميكية ECMAScript2020 أو ES11


يقدم أحدث إصدار من مواصفات JS 2020 وظيفة مدمجة importللاستخدام الديناميكي لوحدات ES. تُرجع هذه الوظيفة الوعد ، لذا يمكنك استخدام الوحدة مع then:

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

نظرًا لأن الدالة importترجع الوعد ، يمكنها استخدام الكلمة الأساسية await:

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

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

وحدة النظام: SystemJS Module


SystemJS هي مكتبة لدعم وحدات ES في المتصفحات القديمة. على سبيل المثال ، تتم كتابة الوحدة النمطية التالية باستخدام بناء جملة 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
    }

لن يعمل هذا الرمز في المستعرضات التي لا تدعم بناء جملة ES6. أحد حلول هذه المشكلة هو ترجمة التعليمات البرمجية باستخدام System.registerواجهة مكتبة 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
                })
            }
        }
    })

اختفى بناء وحدات ES6 الجديد. لكن الكود سيعمل بشكل جيد في المتصفحات القديمة. يمكن إجراء هذا النقل تلقائيًا باستخدام Webpack و TypeScript وما إلى ذلك.

تحميل وحدة ديناميكية


يحتوي SystemJS أيضًا على وظيفة importللاستيراد الديناميكي:

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

وحدة Webpack: تجميع وتجميع وحدات CJS و AMD و ES


Webpack هو منشئ الوحدات النمطية. يجمع ناقلها بين وحدات CommonJS و AMD و ES في قالب نمطي متوازن واحد ويجمع كل الشفرة في ملف واحد. على سبيل المثال ، في الملفات الثلاثة التالية ، يتم تعريف 3 وحدات باستخدام بناء جملة مختلف:

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

يوضح الكود التالي استخدام هذه الوحدة:

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

Webpack قادر على دمج هذه الملفات ، على الرغم من حقيقة أنها أنظمة وحدات مختلفة ، في ملف واحد main.js:

    جذر
        dist
            main.js (تجميع الملفات الموجودة في المجلد src)
        src
            amdDependencyModule1.js
            المشتركة JSDependencyModule2.js
            esCounterModule.js
            index.js
        webpack.config.js

نظرًا لأن Webpack يعتمد على Node.js ، فإنه يستخدم بناء الجملة المعياري لـ CommonJS. في webpack.config.js:

    const path = require('path')

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

للترجمة والبناء ، يجب تشغيل الأوامر التالية:

    npm تثبيت webpack webpack-cli - حفظ-ديف
    npx webpack --config webpack.config.js

نتيجة لذلك ، سيقوم Webpack بإنشاء الملف main.js. تم main.jsتنسيق التعليمات البرمجية التالية لتحسين إمكانية القراءة:

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

ومرة أخرى ، هذا مجرد IIFE. يتم تحويل الرمز من 4 ملفات إلى صفيف من 4 وظائف. ويتم تمرير هذا الصفيف إلى الدالة المجهولة كمعلمة.

وحدة بابل: transpilation of ES module


Babel هو ناقل آخر لدعم كود ES6 + في المتصفحات القديمة. يمكن تحويل وحدة ES6 + المذكورة أعلاه إلى وحدة بابل على النحو التالي:

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

وها هو الكود الذي index.jsيوضح استخدام هذه الوحدة:

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

هذا هو transpilation الافتراضي. يعرف بابل أيضًا كيفية العمل مع أدوات أخرى.

بابل و SystemJS


يمكن استخدام SystemJS كمكوِّن إضافي لبرنامج Babel:

    npm install - حفظ @ devel / plugin-convert-modules-systemjs


يجب إضافة هذا البرنامج المساعد إلى babel.config.json:

    {
        "plugins": ["@ babel / plugin-convert-modules-systemjs"] ،
        "إعدادات مسبقة": [
            [
            "@ babel / env" ،
                {
                    "الأهداف": {
                        "ie": "11"
                    }}
                }}
            ]
        ]
    }}

يمكن لـ Babel الآن العمل مع SystemJS لنقل وحدات CommonJS / Node.js و AMD / RequireJS و ES:

    npx babel src - خارج دير ليب

نتيجة:

    جذر
        ليب
            amdDependencyModule1.js (المنقولة باستخدام SystemJS)
            CommonJSDependencyModule2.js (المنقولة باستخدام SystemJS)
            esCounterModule.js (المنقولة باستخدام SystemJS)
            index.js (المنقولة باستخدام SystemJS)
        src
            amdDependencyModule1.js
            المشتركة JSDependencyModule2.js
            esCounterModule.js
            index.js
        babel.config.json

يتم تحويل الصيغة الكاملة لوحدات AMD و CommonJS و ES إلى بنية 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()
            }
        }
    })

وحدة TypeScript: نقل وحدات CJS و AMD و ES و SystemJS


يدعم TypeScript جميع نكهات تركيب JS ، بما في ذلك ES6. أثناء النقل ، يمكن حفظ بناء جملة وحدة ES6 أو تحويلها إلى تنسيق آخر ، بما في ذلك CommonJS / Node.js أو AMD / RequireJS أو UMD / UmdJS أو SystemJS وفقًا لإعدادات النقل في tsconfig.json:

    {
        'compilerOptions': {
            'module': 'ES2020' // None، CommonJS، AMD، System،
            UMD ، ES6 ، ES2015 ، ESNext
        }}
    }}

على سبيل المثال:

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

يسمى بناء الجملة ES المعياري الذي تدعمه TypeScript الوحدات الخارجية.

الوحدات الداخلية ومساحة الأسماء


يحتوي TypeScript أيضًا على كلمات رئيسية moduleو namespace. تسمى الوحدات الداخلية:

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

يتم نقل كلاهما إلى كائنات JS:

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

يمكن أن تحتوي وحدة TypeScript ومساحة الاسم على عدة مستويات من التداخل من خلال الفاصل .:

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

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

يتم تحويل الوحدة الفرعية ومساحة الاسم الفرعية إلى خصائص الكائن:

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

يمكن أيضًا استخدام وحدة TypeScript ومساحة الاسم في بيان 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
        }
    }

يترجم الرمز أعلاه أيضًا إلى الوحدة الفرعية ومساحة الاسم الفرعية:

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

استنتاج


مرحبًا بك في JS ، التي تحتوي على أكثر من 10 أنظمة / تنسيقات تعديل / مساحات أسماء:

  • وحدة IIFE: قالب وحدة JS
  • وحدة مفتوحة: افتح نموذج وحدة JS
  • وحدة CJS: وحدة CommonJS أو وحدة Node.js
  • وحدة AMD: تعريف الوحدة غير المتزامنة أو وحدة RequireJS
  • وحدة UMD: تعريف الوحدة العالمي أو وحدة UmdJS
  • وحدة ES: وحدة ECMAScript2015 أو ES6
  • الوحدة الديناميكية ES: الوحدة الديناميكية ECMAScript2020 أو ES11
  • وحدة النظام: SystemJS Module
  • وحدة Webpack: تجميع وتجميع وحدات CJS و AMD و ES
  • وحدة بابل: transpilation of ES module
  • وحدة TypeScript ومساحة الاسم

لحسن الحظ ، يحتوي JS حاليًا على أدوات قياسية قياسية للعمل مع الوحدات التي تدعمها Node.js وجميع المتصفحات الحديثة. بالنسبة إلى المتصفحات القديمة ، يمكنك استخدام بنية ES الجديدة المعيارية ، وترجمتها إلى بنية متوافقة باستخدام Webpack / Babel / SystemJS / TypeScript.

شكرا لك على وقتك. آمل أن يكون قد أنفق بشكل جيد.

All Articles