Namespaces em JavaScript

Estou muito impressionado com os namespaces em linguagens de programação como Java e PHP. Tanto que até de alguma forma escrevi um artigo sobre eles no Habré. Quase dois anos se passaram desde então, mas os namespaces não apareceram em JavaScript durante esse tempo. E se eu fizesse namespaces em JS para mim, o que seriam? ” - pensei. Sob o corte - meus pensamentos, quais namespaces eu preciso em JavaScript.

Introdutório

Todo o meu raciocínio abaixo se aplica aos módulos ES6 e não toca em outros formatos (AMD, UMD, CommonJS) simplesmente porque estou interessado em ver para onde o JavaScript está indo, não para onde estava . Além disso, na minha prática, de alguma forma encontrei o GWT bastante próximo, após o que desenvolvi uma rejeição persistente de vários transpilers (bem como, para um heap, minificadores e ofuscadores). Portanto, JS vanilla e não TS. Bem, eu tenho esses itens.

Módulos ES6

Um módulo ES é um arquivo de origem separado que define explicitamente os elementos disponíveis fora do módulo:

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

Portanto, para começar, você precisa abordar de alguma forma os módulos ES individuais em todo o aplicativo.

Pacotes

, . . (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

e usá-lo para importar módulos dinamicamente. Obviamente, não há necessidade de mapear todos os módulos do pacote - você só precisa mapear a raiz do pacote. A saída é mais ou menos assim:

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

A importação de módulos deve ser assíncrona, uma vez que uma função assíncrona será usada internamente import().

Resumo

De forma tão elegante, seria possível alternar do endereçamento físico de módulos ES durante a importação para seu endereçamento lógico (namespaces) e usar os mesmos módulos para aplicativos nodejs e no navegador. Nada de novo foi inventado aqui ( algo semelhante já foi feito no PHP, de onde essa ideia foi roubada).




All Articles