Espaces de noms en JavaScript

Je suis très impressionné par les espaces de noms dans les langages de programmation tels que Java et PHP. A tel point que j'ai même en quelque sorte écrit un article à leur sujet sur Habré. Près de deux ans se sont écoulés depuis lors, mais les espaces de noms ne sont pas apparus dans JavaScript pendant cette période. " Et si je faisais des espaces de noms dans JS pour moi-même, quels seraient-ils? " - J'ai pensé. Sous la coupe - mes pensées, quels espaces de noms j'ai besoin en JavaScript.

Introduction

Tout mon raisonnement ci-dessous s'applique aux modules ES6 et ne touche pas aux autres formats (AMD, UMD, CommonJS) simplement parce que je suis intéressé à voir où va JavaScript, pas où il était . De plus, dans ma pratique, je suis tombé sur GWT assez étroitement, après quoi j'ai développé un rejet persistant de divers transpilers (ainsi que, à un tas, des minifiers et des obfuscators). Donc vanille JS et pas TS. Eh bien, j'ai de tels articles.

Modules ES6

Un module ES est un fichier source distinct qui définit explicitement les éléments disponibles en dehors du module:

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

Ainsi, pour commencer, vous devez en quelque sorte adresser des modules ES individuels dans toute l'application.

Paquets

, . . (vendor) , . (, ./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

et utilisez-le pour importer dynamiquement des modules. Bien sûr, il n'est pas nécessaire de mapper chaque module du paquet - il vous suffit de mapper la racine du paquet. La sortie est quelque chose comme ceci:

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');

L'importation des modules doit être asynchrone, car une fonction asynchrone sera utilisée à l'intérieur import().

Sommaire

De manière si élégante, il serait possible de passer de l'adressage physique des modules ES lors de l'importation à leur adressage logique (espaces de noms) et d'utiliser les mêmes modules à la fois pour les applications nodejs et dans le navigateur. Rien de nouveau n'a été inventé ici ( quelque chose de similaire a déjà été fait en PHP, d'où cette idée est volée).




All Articles