MAM: perakitan frontend tanpa rasa sakit

Halo, nama saya Dmitry Karlovsky, dan saya ... suka MAM. M AM mengatur modul M Gnostik, menyelamatkan saya bagian terbesar dari rutinitas.


Modul Agnostik Khas


Modul agnostik , tidak seperti yang tradisional, bukan file sumber, tetapi direktori di dalamnya ada kode sumber dalam berbagai bahasa: logika program pada JS / TS , tes untuk itu pada TS / JS , komposisi komponen pada view.tree , styles di CSS , lokalisasi di locale=*.json , gambar, dll., dll. Jika diinginkan, tidak sulit untuk mempercepat dukungan untuk bahasa lain. Misalnya, Stylus untuk gaya penulisan, atau HTML untuk menjelaskan template.


Ketergantungan antar modul dilacak secara otomatis dengan menganalisis sumbernya. Jika modul dihidupkan, ia dihidupkan secara keseluruhan - setiap kode sumber modul ditransformasikan dan jatuh ke dalam bundel yang sesuai: skrip - secara terpisah, gaya - secara terpisah, tes - secara terpisah. Untuk platform yang berbeda - bundel mereka: untuk simpul - milik mereka sendiri, untuk browser - milik mereka sendiri.


Otomatisasi penuh, kurangnya konfigurasi dan pelat ketel, ukuran bundel minimal, pemompaan dependensi otomatis, pengembangan ratusan perpustakaan yang teralienasi dan aplikasi dalam satu basis kode tanpa rasa sakit dan penderitaan. Wah, itu kecanduan! Singkirkan anak-anak yang hamil, gugup, dari monitor dan selamat datang di kapal selam!


Filsafat


MAM adalah percobaan berani untuk secara radikal mengubah cara kode diatur dan proses bekerja dengannya. Inilah prinsip-prinsip dasar:


Konvensi bukan konfigurasi. Kesepakatan yang masuk akal, sederhana dan universal memungkinkan Anda untuk mengotomatiskan seluruh rutinitas, sambil menjaga kenyamanan dan keseragaman antara berbagai proyek.


Infrastrukturnya terpisah, kodenya terpisah. Situasi tidak jarang ketika Anda perlu mengembangkan lusinan, atau bahkan ratusan perpustakaan dan aplikasi. Jangan menggunakan infrastruktur perakitan, pengembangan, penyebaran, dll. Untuk masing-masing. Cukup bertanya sekali dan kemudian memukau aplikasi seperti pai.


Jangan membayar untuk apa yang tidak Anda gunakan. Anda menggunakan semacam modul - modul ini disertakan dalam bundel dengan semua dependensinya. Jangan gunakan - tidak menyala. Semakin kecil modul, semakin besar rinciannya dan semakin sedikit kode yang tidak perlu dalam bundel.


Kode redundan minimum. Memecah kode menjadi modul harus sesederhana menulis semua kode dalam satu file. Jika tidak, pengembang akan malas memecah modul besar menjadi kecil.


Tidak ada konflik versi. Hanya ada satu versi - versi saat ini. Tidak perlu menghabiskan sumber daya untuk mendukung versi lama, jika Anda dapat menghabiskannya untuk memperbarui yang terakhir.


Jaga jari pada denyut nadi. Umpan balik tercepat mengenai ketidakcocokan tidak akan membiarkan kode menjadi buruk.


Cara termudah adalah yang paling pasti. Jika jalan yang benar membutuhkan upaya tambahan, maka pastikan tidak ada yang akan pergi ke sana.


Impor / Ekspor


Kami membuka proyek pertama yang menggunakan sistem modul modern: Sebuah modul kurang dari 300 baris, 30 di antaranya adalah impor.


Tapi ini masih bunga: Untuk fungsi 9 baris, diperlukan 8 impor.


Dan favorit saya: Bukan satu baris kode yang berguna. 20 baris nilai pergeseran dari tumpukan modul menjadi satu, sehingga nanti Anda dapat mengimpor dari satu modul, dan bukan dari dua puluh.


Semua ini adalah boilerplate, yang mengarah pada fakta bahwa pengembang terlalu malas untuk mengalokasikan potongan kecil kode ke dalam modul terpisah, lebih memilih modul besar daripada yang kecil. Dan bahkan jika mereka tidak malas, ternyata banyak kode untuk mengimpor modul kecil, atau modul khusus yang mengimpor banyak modul ke dalam diri mereka sendiri dan mengekspor semuanya dalam jumlah besar.


Semua ini mengarah pada granularitas rendah dari kode dan menggembungkan ukuran bundel dengan kode yang tidak digunakan, yang cukup beruntung untuk menjadi dekat dengan yang digunakan. Untuk JS, mereka mencoba menyelesaikan masalah ini dengan menyulitkan jalur perakitan, dengan menambahkan apa yang disebut β€œpengocokan pohon”, yang memotong kelebihan dari apa yang Anda impor. Ini memperlambat perakitan, tetapi tidak semuanya terpotong.


Gagasan: Bagaimana jika kita tidak mengimpor, tetapi hanya mengambil dan menggunakan, dan pengumpul sendiri akan mencari tahu apa yang perlu diimpor?


IDE modern dapat secara otomatis menghasilkan impor untuk entitas yang Anda gunakan. Jika IDE dapat melakukan ini, lalu apa yang mencegah kolektor melakukan ini? Cukup memiliki konvensi sederhana tentang penamaan dan lokasi file, yang akan nyaman bagi pengguna dan dapat dimengerti oleh mesin. PHP telah lama memiliki konvensi standar: PSR-4 . MAM memperkenalkan hal yang sama untuk file .ts dan .jam.js: nama yang dimulai dengan $ adalah Nama yang Sepenuhnya Memenuhi Kualifikasi dari beberapa entitas global, yang kodenya dimuat di sepanjang jalur yang diperoleh dari FQN dengan mengganti pembatas dengan garis miring. Contoh sederhana dari dua modul:


/ alert / alert.ts saya


 const $my_alert = alert // FQN    

/ app / app.ts saya


 $my_alert( 'Hello!' ) // ,   /my/alert/ 

Seluruh modul dari satu baris - apa yang bisa lebih sederhana? Hasilnya tidak lama datang: kesederhanaan membuat dan menggunakan modul mengarah pada meminimalkan ukurannya. Hasilnya, memaksimalkan granularity. Dan seperti ceri - meminimalkan ukuran bundel tanpa pohon bergetar.


Contoh yang baik adalah keluarga JSON / mol / data keluarga modul validasi. Jika Anda menggunakan fungsi $mol_data_integer di suatu tempat dalam kode Anda, maka modul /mol/data/integer dan /mol/data/number , yang bergantung pada $mol_data_integer , akan dimasukkan dalam bundel. Tetapi, misalnya, kolektor /mol/data/email bahkan tidak akan membaca dari disk, karena tidak ada yang bergantung padanya.


Membuat berantakan


Sejak kami mulai menendang Angular, kami tidak akan berhenti. Di mana menurut Anda untuk mencari applyStyles fungsi applyStyles ? Anda tidak akan menebak di /packages/core/src/render3/styling_next/bindings.ts . Kemampuan untuk menempatkan apa pun di mana saja mengarah pada fakta bahwa dalam setiap proyek kami mengamati sistem lokasi file yang unik, sering tidak setuju dengan logika apa pun. Dan jika IDE sering disimpan oleh "lompat ke definisi", maka melihat kode pada github atau meninjau permintaan tarik akan kehilangan kesempatan ini.


Ide: Bagaimana jika nama entitas benar-benar sesuai dengan lokasi mereka?


Untuk menempatkan kode dalam file /angular/packages/core/src/render3/stylingNext/bindings.ts , dalam arsitektur MAM Anda harus memberi nama entitas $angular_packages_core_src_render3_stylingNext_applyStyles , tapi tentu saja, tidak ada yang akan bertindak, karena ada begitu banyak nama tambahan. Tetapi nama-nama dalam kode yang ingin saya lihat singkat dan ringkas, sehingga pengembang akan mencoba untuk mengecualikan semua yang tidak perlu dari nama, hanya menyisakan yang penting: $angular_render3_applyStyles . Dan itu akan ditempatkan sesuai di /angular/render3/applyStyles/applyStyles.ts .


Perhatikan bagaimana MAM menggunakan kelemahan pengembang untuk mencapai hasil yang diinginkan: setiap entitas mendapatkan nama pendek global unik yang dapat digunakan dalam konteks apa pun. Misalnya, dalam pesan komit, nama-nama ini memungkinkan Anda menangkap dengan cepat dan akurat apa yang mereka bicarakan:


 73ebc45e517ffcc3dcce53f5b39b6d06fc95cae1 $mol_vector: range expanding support 3a843b2cb77be19688324eeb72bd090d350a6cc3 $mol_data: allowed transformations 24576f087133a18e0c9f31e0d61052265fd8a31a $mol_data_record: support recursion 

Atau, katakanlah Anda ingin menemukan semua sebutan modul $ mol_fiber di Internet - membuatnya lebih mudah dari sebelumnya berkat FQN.


Ketergantungan siklik


Mari kita menulis 7 baris kode sederhana dalam satu file:


 export class Foo { get bar() { return new Bar(); } } export class Bar extends Foo {} console.log(new Foo().bar); 

Meskipun ada ketergantungan siklik, ia bekerja dengan benar. Kami memecahnya menjadi 3 file:


/ foo.js saya


 import { Bar } from './bar.js'; export class Foo { get bar() { return new Bar(); } } 

/ bar.js saya


 import { Foo } from './foo.js'; export class Bar extends Foo {} 

/ app.js saya


 import { Foo } from './foo.js'; console.log(new Foo().bar); 

Ups, ReferenceError: Cannot access 'Foo' before initialization . Omong kosong macam apa? Untuk memperbaikinya, app.js kami perlu tahu bahwa foo.js bergantung pada bar.js Karena itu, pertama-tama kita perlu mengimpor bar.js , yang mengimpor foo.js Setelah itu kita sudah bisa mengimpor foo.js tanpa kesalahan:


/ app.js saya


 import './bar.js'; import { Foo } from './foo.js'; console.log(new Foo().bar); 

Browser itu, NodeJS itu, Webpack itu, Parcel itu - semuanya bekerja bengkok dengan dependensi melingkar. Dan yah, mereka hanya akan melarang mereka - orang bisa segera menyulitkan kode sehingga tidak ada loop. Tapi mereka bisa bekerja dengan baik, dan kemudian bam, dan memberikan kesalahan yang tidak bisa dimengerti.


Ide: Bagaimana jika selama perakitan kita hanya merekatkan file dalam urutan yang benar, seolah-olah semua kode awalnya ditulis dalam satu file?


Mari kita membagi kode menggunakan prinsip-prinsip MAM:


/ foo / foo.ts saya


 class $my_foo { get bar() { return new $my_bar(); } } 

/ bar / bar.ts saya


 class $my_bar extends $my_foo {} 

/ app / app.ts saya


 console.log(new $my_foo().bar); 

Semua 7 baris kode yang sama yang awalnya. Dan mereka hanya bekerja tanpa perdukunan tambahan. Masalahnya adalah bahwa kolektor memahami bahwa ketergantungan my/bar my/foo pada my/foo lebih ketat daripada my/foo pada my/bar . Ini berarti Anda harus menyertakan modul-modul ini dalam bundel dalam urutan ini: my/foo , my/bar , my/app .


Bagaimana kolektor memahami ini? Sekarang heuristik sederhana - dengan jumlah lekukan di baris di mana ketergantungan terdeteksi. Harap perhatikan bahwa ketergantungan yang lebih kuat pada contoh kami memiliki indentasi nol, dan yang lemah memiliki indentasi ganda.


Bahasa yang berbeda


Kebetulan bahwa untuk hal-hal yang berbeda kami memiliki bahasa yang berbeda untuk hal-hal yang berbeda juga dipertajam. Yang paling umum adalah: JS, TS, CSS, HTML, SVG, SCSS, Less, Stylus. Masing-masing memiliki sistem modul sendiri, yang tidak berinteraksi dengan bahasa lain dengan cara apa pun. Tak perlu dikatakan, sekitar 100500 jenis bahasa yang lebih spesifik. Akibatnya, untuk menghubungkan komponen, Anda harus menghubungkan skrip, gaya terpisah, mendaftarkan templat secara terpisah, secara terpisah mengkonfigurasi penyebaran file statis yang diperlukan, dll., Dll.


Terima kasih kepada loader, Webpack berusaha menyelesaikan masalah ini. Tapi dia memiliki entry point yaitu skrip yang sudah menghubungkan file dalam bahasa lain. Dan jika kita tidak membutuhkan skrip? Sebagai contoh, kami memiliki modul dengan gaya yang indah untuk piring dan kami ingin mereka memiliki warna yang sama dalam tema terang dan yang lain dalam gelap:


 .dark-theme table { background: black; } .light-theme table { background: white; } 

Selain itu, jika kita bergantung pada topik, maka skrip harus dimuat yang akan menginstal topik yang diinginkan tergantung pada waktu hari. Artinya, CSS sebenarnya tergantung pada JS.


Ide: Bagaimana jika sistem modular tidak bergantung pada bahasa?


Karena dalam MAM sistem modular dipisahkan dari bahasa, dependensinya dapat lintas-bahasa. CSS mungkin tergantung pada JS, yang mungkin tergantung pada TS, yang mungkin tergantung pada JS lain. Ini dicapai karena fakta bahwa dependensi sumber terdeteksi pada modul, dan modul terhubung seluruhnya dan dapat berisi kode sumber dalam bahasa apa pun. Dalam contoh contoh tema, tampilannya seperti ini:


/my/table/table.css


 /* ,   /my/theme */ [my_theme="dark"] table { background: black; } [my_theme="light"] table { background: white; } 

/my/theme/theme.js


 document.documentElement.setAttribute( 'my_theme' , ( new Date().getHours() + 15 ) % 24 < 12 ? 'light' : 'dark' , ) 

Dengan menggunakan teknik ini, Anda dapat mengimplementasikan Modernizr Anda, tetapi tanpa 300 pemeriksaan yang tidak Anda perlukan, karena hanya pemeriksaan yang bergantung pada CSS Anda yang akan dimasukkan dalam bundel.


Banyak perpustakaan


Biasanya, titik masuk untuk membangun bundel adalah beberapa jenis file. Dalam hal Webpack, ini adalah JS. Jika Anda mengembangkan banyak perpustakaan dan aplikasi yang dapat dialienasi, maka Anda memerlukan banyak bundel. Dan untuk setiap bundel Anda perlu membuat titik masuk yang terpisah. Dalam kasus Parcel, titik masuknya adalah HTML, yang untuk aplikasi harus dibuat. Tetapi untuk perpustakaan, ini entah bagaimana sangat tidak cocok.


Ide: Bagaimana jika ada modul yang dapat dirangkai menjadi bundel independen tanpa persiapan awal?


Mari kita kumpulkan versi terbaru dari pembuat proyek MAM $ mol_build:


 mam mol/build 

Sekarang jalankan kolektor ini dan biarkan dia merakit dirinya sendiri lagi untuk memastikan bahwa dia masih bisa merakit dirinya sendiri:


 node mol/build/-/node.js mol/build 

Meskipun, tidak, mari kita memintanya untuk melakukan tes bersama dengan majelis:


 node mol/build/-/node.test.js mol/build 

Dan jika semuanya berjalan dengan baik, publikasikan hasilnya di NPM:


 npm publish mol/build/- 

Seperti yang Anda lihat, saat merakit modul, subdirektori dibuat dengan nama - dan semua artefak rakitan ditempatkan di sana. Mari kita telusuri file yang dapat Anda temukan di sana:


  • web.dep.json - semua informasi tentang grafik ketergantungan
  • web.js - bundel skrip browser
  • web.js.map - sorsmaps untuknya
  • web.esm.js - itu dalam bentuk modul-es
  • web.esm.js.map - dan sorsmaps untuk itu
  • web.test.js - bundel uji
  • web.test.js.map - dan untuk tes sorsmap
  • web.d.ts - bundel dengan jenis segala sesuatu yang ada dalam bundel skrip
  • web.css - bundel dengan gaya
  • web.css.map - dan sortmaps untuk itu
  • web.test.html - titik masuk untuk menjalankan tes kinerja di browser
  • web.view.tree - deklarasi semua komponen yang termasuk dalam bundel view.tree
  • web.locale=*.json - bundel dengan teks terlokalisasi, masing-masing bundel memiliki bundel sendiri
  • package.json - memungkinkan Anda untuk segera menerbitkan modul rakitan di NPM
  • node.dep.json - semua informasi tentang grafik ketergantungan
  • node.js - bundel skrip simpul
  • node.js.map - sorsmaps untuk itu
  • node.esm.js - itu dalam bentuk modul-es
  • node.esm.js.map - dan sorsmaps untuk itu
  • node.test.js - bundel yang sama, tetapi juga dengan tes
  • node.test.js.map - dan sorsmaps untuk itu
  • node.d.ts - bundel dengan jenis segala sesuatu yang ada dalam bundel skrip
  • node.view.tree - deklarasi semua komponen yang termasuk dalam bundel view.tree
  • node.locale=*.json - bundel dengan teks yang dilokalkan, masing-masing bundel memiliki bundel sendiri

Statika disalin bersama jalurnya. Sebagai contoh, ambil aplikasi yang menampilkan kode sumbernya sendiri . Sumbernya ada di sini:


  • /mol/app/quine/quine.view.tree
  • /mol/app/quine/quine.view.ts
  • /mol/app/quine/index.html
  • /mol/app/quine/quine.locale=ru.json

Sayangnya, dalam kasus umum, kolektor tidak dapat mengetahui bahwa kami akan memerlukan file-file ini dalam runtime. Tapi kita bisa memberitahunya ini dengan meletakkan file khusus di dekatnya:


/mol/app/quine/quine.meta.tree


 deploy \/mol/app/quine/quine.view.tree deploy \/mol/app/quine/quine.view.ts deploy \/mol/app/quine/index.html deploy \/mol/app/quine/quine.locale=ru.json 

Sebagai hasil dari perakitan /mol/app/quine , mereka akan disalin dengan cara berikut:


  • /mol/app/quine/-/mol/app/quine/quine.view.tree
  • /mol/app/quine/-/mol/app/quine/quine.view.ts
  • /mol/app/quine/-/mol/app/quine/index.html
  • /mol/app/quine/-/mol/app/quine/quine.locale=ru.json

Sekarang direktori /mol/app/quine/- dapat diletakkan di sembarang hosting statis dan aplikasi akan berfungsi penuh.


Platform target


JS dapat dieksekusi baik di klien maupun di server. Dan betapa kerennya ketika Anda dapat menulis satu kode dan itu akan bekerja di mana-mana. Namun, terkadang implementasi hal yang sama pada klien dan server pada dasarnya berbeda. Dan saya ingin, misalnya, satu implementasi digunakan untuk node, dan yang lain untuk browser.


Ide: Bagaimana jika tujuan file tercermin dalam namanya?


MAM menggunakan sistem tag dalam nama file. Sebagai contoh, modul $mol_state_arg menyediakan akses ke parameter aplikasi yang ditentukan pengguna. Di browser, parameter ini ditetapkan melalui bilah alamat. Dan di simpul, melalui argumen baris perintah. $mol_sate_arg mengabstraksi sisa aplikasi dari nuansa ini dengan mengimplementasikan kedua opsi dengan antarmuka tunggal, menempatkannya dalam file:


  • / mol / state / arg / arg. web .ts - implementasi untuk browser
  • / mol / state / arg / arg. simpul .ts - implementasi untuk suatu simpul

Sumber yang tidak ditandai dengan tag ini disertakan terlepas dari platform target.


Situasi serupa diamati dengan tes - mereka ingin disimpan di sebelah sumber lain, tetapi mereka tidak ingin dimasukkan dalam bundel yang masuk ke pengguna akhir. Karenanya, pengujian juga ditandai dengan tag terpisah:


  • / mol / state / arg / arg. test .ts - tes modul, mereka akan jatuh ke dalam bundel tes

Tag bisa parametrik. Misalnya, dengan setiap modul teks dalam berbagai bahasa dapat datang dan harus dimasukkan dalam bundel bahasa yang sesuai. File teks adalah kamus JSON biasa yang diberi nama lokal dalam namanya:


  • / mol / app / hidup / kehidupan. locale = ru .json - teks untuk bahasa Rusia
  • / mol / app / hidup / kehidupan. locale = jp .json - teks untuk bahasa Jepang

Akhirnya, bagaimana jika kita ingin meletakkan file di dekatnya, tetapi ingin kolektor mengabaikannya dan tidak secara otomatis memasukkannya ke dalam bundel? Cukup menambahkan di awal nama mereka karakter non-alfanumerik. Sebagai contoh:


  • / hyoo / mainan / . git - dimulai dengan tanda titik, sehingga kolektor akan mengabaikan direktori ini

Versi


Google pertama kali merilis AngularJS dan menerbitkannya dalam NPM sebagai angular . Kemudian ia menciptakan kerangka kerja yang sama sekali baru dengan nama yang mirip - Angular dan menerbitkannya dengan nama yang sama, tetapi sudah versi 2. Sekarang kedua kembang api ini berkembang secara mandiri. Hanya satu perubahan pemecah API yang terjadi antara versi utama. Dan yang lainnya - antara anak di bawah umur . Dan karena tidak mungkin untuk menempatkan dua versi dari ketergantungan yang sama pada tingkat yang sama, tidak ada pembicaraan tentang transisi yang mulus, ketika dua versi perpustakaan secara bersamaan hidup berdampingan untuk beberapa waktu dalam aplikasi.


Tampaknya tim Angular telah menginjak semua kemungkinan garu. Dan satu hal lagi: kode kerangka kerja dibagi menjadi beberapa modul besar. Pada awalnya mereka memvariasikannya secara independen, tetapi sangat cepat bahkan mereka sendiri mulai bingung dengan versi modul mana yang kompatibel satu sama lain, apalagi pengembang biasa. Oleh karena itu, Angular beralih ke versi end-to-end , di mana versi utama modul dapat berubah bahkan tanpa ada perubahan dalam kode. Dukungan untuk beberapa versi dari banyak modul merupakan masalah besar baik bagi pengelola sendiri maupun bagi ekosistem secara keseluruhan. Lagi pula, banyak sumber daya dari semua anggota masyarakat dihabiskan untuk memastikan kompatibilitas dengan modul yang sudah usang.


Ide indah Semantic Versioning terurai menjadi kenyataan pahit - Anda tidak pernah tahu apakah ada sesuatu yang pecah ketika Anda mengubah versi minor atau bahkan versi tambalan . Oleh karena itu, dalam banyak proyek, versi tertentu dari ketergantungan diperbaiki. Namun, perbaikan semacam itu tidak memengaruhi dependensi transitif, yang dapat ditarik ke versi terbaru saat menginstal dari awal, tetapi mungkin tetap sama jika sudah diinstal. Kekacauan ini mengarah pada fakta bahwa Anda tidak pernah bisa bergantung pada versi yang telah diperbaiki dan Anda perlu memeriksa kompatibilitas dengan versi terkini dari dependensi (setidaknya transitif).


Tapi bagaimana dengan file kunci ? Jika Anda sedang mengembangkan perpustakaan yang diinstal melalui dependensi, file kunci tidak akan membantu Anda, karena akan diabaikan oleh manajer paket. Untuk aplikasi terakhir, file kunci akan memberi Anda apa yang disebut "reproducibility of assemblies." Tapi mari kita jujur. Berapa kali Anda perlu membangun aplikasi final dari sumber yang sama? Tepat sekali. Menerima output, terlepas dari NPM, artefak perakitan: biner yang dapat dieksekusi, wadah buruh pelabuhan atau hanya arsip dengan semua kode yang diperlukan untuk menjalankannya. Saya harap Anda tidak melakukan npm install di prod?


Beberapa menemukan penggunaan file kunci untuk memiliki server CI merakit persis apa yang telah dilakukan pengembang. Tapi tunggu, pengembang sendiri dapat dengan mudah merakitnya di komputer lokalnya. , , , . Continuous Integration , , , , - . CI , .


, , . , Angular@4 ( 3). , , " " " ". Angular@4 , Angular@5. Angular@6, . Angular TypeScript . . , 2 , … , business value , , , , .


, , , , 2 . : , β€” , β€” . 3 React, 5 jQuery, 7 lodash.


: β€” ?


. - . , . , . , . , . , . , , . : issue, , workaround, pull request, , . , , . . .


, . , , . . . : , , -. - β€” . , , - . , , , NPM . , . .


, ? β€” . mobx , mobx2 API . β€” , : , . mobx mobx2 , API. API, .


. β€” . , :


 var pages_count = $mol_atom2_sync( ()=> $lib_pdfjs.getDocument( uri ).promise ).document().numPages 

mol_atom2_sync lib_pdfjs , :


 npm install mol_atom2_sync@2.1 lib_pdfjs@5.6 

, , β€” , . ? β€” , *.meta.tree , :


/.meta.tree


 pack node git \https://github.com/nin-jin/pms-node.git pack mol git \https://github.com/eigenmethod/mol.git pack lib git \https://github.com/eigenmethod/mam-lib.git 

. .


NPM


MAM β€” NPM . , β€” . , , NPM .


NPM , $node. , - -:


/my/app/app.ts


 $node.portastic.find({ min : 8080 , max : 8100 , retrieve : 1 }).then( ( ports : number[] ) => { $node.express().listen( ports[0] ) }) 

, . - lib NPM . , NPM- pdfjs-dist :


/lib/pdfjs/pdfjs.ts


 namespace $ { export let $lib_pdfjs : typeof import( 'pdfjs-dist' ) = require( 'pdfjs-dist/build/pdf.min.js' ) $lib_pdfjs.disableRange = true $lib_pdfjs.GlobalWorkerOptions.workerSrc = '-/node_modules/pdfjs-dist/build/pdf.worker.min.js' } 

/lib/pdfjs/pdfjs.meta.tree


 deploy \/node_modules/pdfjs-dist/build/pdf.worker.min.js 

, .



. create-react-app angular-cli , . , , eject . . , , .


: ?


MAM . .


MAM MAM , :


 git clone https://github.com/eigenmethod/mam.git ./mam && cd mam npm install npm start 

8080 . , β€” MAM.


( β€” acme ) ( β€” hello home ):


/acme/acme.meta.tree


 pack hello git \https://github.com/acme/hello.git pack home git \https://github.com/acme/home.git 

npm start :


 npm start acme/hello acme/home 

. β€” . , , . β€” : https://t.me/mam_mol

Source: https://habr.com/ru/post/id456288/


All Articles