مساحات الأسماء في JavaScript

أنا معجب جدًا بمساحات الأسماء في لغات البرمجة مثل Java و PHP. لدرجة أنني كتبت بطريقة ما مقالًا عنهم في حبري. لقد مر ما يقرب من عامين منذ ذلك الحين ، ولكن لم تظهر مساحات الأسماء في JavaScript خلال هذا الوقت. " وإذا قمت بعمل مساحات الأسماء في JS لنفسي ، فماذا ستكون؟ " - فكرت. تحت القص - أفكاري ، ما هي مساحات الأسماء التي أحتاجها في JavaScript.

استهلالي

تنطبق جميع أسبابي أدناه على وحدات ES6 ولا تتطرق إلى التنسيقات الأخرى (AMD و UMD و CommonJS) لمجرد أنني مهتم بمعرفة أين تتجه JavaScript ، وليس إلى أين كانت . أيضًا ، في ممارستي ، واجهت بطريقة أو بأخرى GWT عن كثب ، وبعد ذلك طورت رفضًا مستمرًا للعديد من أجهزة النقل (بالإضافة إلى كومة ، ومُصغرات ومُعتِدات). لذلك فانيلا شبيبة ولا TS. حسنًا ، لدي مثل هذه العناصر.

وحدات ES6

الوحدة النمطية ES هي ملف مصدر منفصل يحدد بوضوح العناصر المتاحة خارج الوحدة:

export function fn() {/*...*/}

وبالتالي ، في البداية ، تحتاج إلى معالجة وحدات ES الفردية بطريقة ما داخل التطبيق بأكمله.

الحزم

تتكون التطبيقات الحديثة من حزم فردية ، يتم إدارة التبعيات بينها بواسطة مديري الحزم. وتتكون الحزم نفسها من وحدات منفصلة. يمكن للبائع الفردي تقسيم الكود الخاص به إلى حزم متعددة ، باستخدام نفس الحزم في تطبيقاته المختلفة. عادةً ما يتم وضع الكود المصدري للوحدات النمطية في دليل منفصل داخل الحزمة (على سبيل المثال ./src).

يضع مديرو الحزم جميع الحزم لتطبيق واحد في دليل node_modules. وبالتالي ، فإن بنية تطبيق nodejs المترجمة من حزم مطور معين قد تبدو كما يلي:

* node_modules
    * @vendor
        * package1
            * src
                * module1.js
                * ...
                * moduleN.js
        * ...
        * packageN
            * src
                * module1.mjs
                * ...
                * moduleN.mjs

وحدة عنونة

في بنية الملف ، تتم معالجة التعليمات البرمجية المصدر لأي وحدة ES من خلال المسار إلى الملف بالنسبة إلى جذر التطبيق:

./node_modules/@vendor/package1/src/module1.js
...
./node_modules/@vendor/packageN/src/moduleN.mjs

كجزء من أداة تحميل وحدة التطبيق nodejs ، ./node_modules/ يختفي الجزء  :

import SomeThing from '@vendor/package1/src/module1.js';

, , :

import SomeThing from './module1.js';

web- , web-  node_modules, web- ES-, , nodejs:

<script type="module">
    import {fn} from './@vendor/package1/src/module1.js'
    fn();
</script>

:

<script>
    import('./@vendor/package1/src/module1.js').then((mod) => {
        mod.fn();
    });
</script>

, web'  ./  . :

import {fn} from '@vendor/package1/src/module1.js'

:

Uncaught TypeError: Failed to resolve module specifier "@vendor/package1/src/module1.js". Relative references must start with either "/", "./", or "../".

, ES-:

  • ( ): ./module1.js

  • (nodejs): @vendor/package1/src/module1.js

  • (web): ./@vendor/package1/src/module1.js

./ nodejs-, ./ .

, JS- , , ( - ) , ( ).

" " ( , namespace'), ES- ( ), ES- , , nodejs, .

,  ./, , ( , ):

@vendor/package1/src/module1

- : ./src/./lib/./dist/. - , , :

@vendor/package1/module1

, , .

Namespace mapping

, , . - web-,  node_modules  web- ( - ./packages/):

const node = {
    '@vendor/package1': {path: '/.../node_modules/@vendor/package1/src', ext: 'js'},
    '@vendor/packageN': {path: '/.../node_modules/@vendor/packageN/src', ext: 'mjs'},
};
const browser = {
    '@vendor/package1': {path: 'https://.../packages/@vendor/package1/src', ext: 'js'},
    '@vendor/packageN': {path: 'https://.../packages/@vendor/packageN/src', ext: 'mjs'},
};

Module loader

, '' ( @vendor/package1/module1) ( - ) (node ):

@vendor/package1/module1 => /.../node_modules/@vendor/package1/src/module1.js       // node
@vendor/packageN/moduleN => https://.../packages/@vendor/packageN/src/moduleN.mjs   // browser

واستخدامها لاستيراد الوحدات ديناميكيًا. بالطبع ، ليست هناك حاجة لتعيين كل وحدة في الحزمة - ما عليك سوى تعيين جذر الحزمة. الإخراج شيء من هذا القبيل:

const loader = new ModuleLoader();
loader.addNamespace('@vendor/package1', {path: '/.../node_modules/@vendor/package1/src', ext: 'js'});
// ...
loader.addNamespace('@vendor/packageN', {path: '/.../node_modules/@vendor/packageN/src', ext: 'js'});
const module1 = await loader.import('@vendor/package1/module1');

يجب أن يكون استيراد الوحدات غير متزامن منذ ذلك الحين سيتم استخدام دالة غير متزامنة في الداخل import().

ملخص

بهذه الطريقة الأنيقة ، سيكون من الممكن التبديل من العنونة المادية لوحدات ES أثناء الاستيراد إلى العنونة المنطقية (مساحات الأسماء) واستخدام نفس الوحدات لكل من تطبيقات nodejs والمتصفح. لم يتم اختراع أي شيء جديد هنا ( تم بالفعل عمل شيء مشابه في PHP ، حيث سُرقت هذه الفكرة).




All Articles