Saya sangat terkesan dengan namespace dalam bahasa pemrograman seperti Java dan PHP. Sedemikian rupa sehingga saya bahkan entah bagaimana menulis artikel tentang mereka di HabrΓ©. Hampir dua tahun telah berlalu sejak saat itu, namun namespace belum muncul di JavaScript selama ini. " Dan jika saya membuat namespace di JS untuk diri saya sendiri, apakah itu? " - Saya pikir. Di bawah cut - pikiran saya, namespace apa yang saya butuhkan di JavaScript.
Pengantar
Semua alasan saya di bawah ini berlaku untuk modul ES6 dan tidak menyentuh pada format lain (AMD, UMD, CommonJS) hanya karena saya tertarik dalam melihat mana JavaScript pergi, tidak di mana itu adalah . Juga, dalam praktik saya, saya entah bagaimana bertemu dengan GWT cukup dekat, setelah itu saya mengembangkan penolakan terus-menerus terhadap berbagai transpiler (serta, ke heap, minifier dan obfuscators). Oleh karena itu vanilla JS dan tidak ada TS. Nah, saya punya barang seperti itu.
Modul ES6
Modul ES adalah file sumber terpisah yang secara eksplisit mendefinisikan elemen yang tersedia di luar modul:
export function fn() {/*...*/}Jadi, untuk memulainya, Anda perlu membahas modul ES individual dalam keseluruhan aplikasi.
Paket
, . . (vendor) , . (, ./src).
node_modules. , nodejs-, , :
* node_modules
* @vendor
* package1
* src
* module1.js
* ...
* moduleN.js
* ...
* packageN
* src
* module1.mjs
* ...
* moduleN.mjsES- :
./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 // browserdan menggunakannya untuk mengimpor modul secara dinamis. Tentu saja, tidak perlu memetakan setiap modul dalam paket - Anda hanya perlu memetakan root paket. Outputnya seperti ini:
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');Impor modul harus asynchronous, karena fungsi asynchronous akan digunakan di dalam import().
Ringkasan
Dengan cara yang elegan, dimungkinkan untuk beralih dari pengalamatan fisik modul ES selama impor ke pengalamatan logis (ruang nama) dan menggunakan modul yang sama baik untuk aplikasi nodejs maupun di browser. Tidak ada hal baru yang ditemukan di sini ( sesuatu yang serupa telah dilakukan di PHP, dari mana ide ini dicuri).