Banyak artikel sedang ditulis tentang Elemen Sudut dan secara teratur membaca laporan. Seperti, Anda tidak perlu lagi menggunakan beberapa angulars penuh - kumpulkan saja komponen web dan gunakan di halaman Anda.
Tetapi, sebagai aturan, bahan-bahan ini terbatas untuk mempertimbangkan situasi yang agak utopis: kami membuat proyek terpisah, membuat komponen bersudut, mengonfigurasi proyek untuk merakit Elemen dan, akhirnya, mengkompilasi beberapa file JS, menghubungkannya ke halaman biasa akan memberi kami hasil yang diinginkan. Hore, komponennya bekerja! ..

Dalam praktiknya, diperlukan untuk menarik beberapa komponen dari proyek sudut kerja siap pakai, lebih lanjut, lebih disukai agar tidak mempengaruhi pengembangan dan penggunaannya saat ini. Artikel ini ternyata hanya karena salah satu dari situasi ini: Saya ingin tidak hanya mengumpulkan elemen-elemen individual dari proyek, tetapi untuk membuat proses mengkompilasi seluruh perpustakaan UI pada Angular menjadi satu set file dengan komponen web asli.
Persiapan modul
Pertama, mari kita ingat seperti apa bentuk modul untuk menyusun Elemen Sudut.
@NgModule({ imports: [BrowserModule], entryComponents: [SomeComponent], }) export class AppModule { constructor(readonly injector: Injector) { const ngElement = createCustomElement(SomeComponent, { injector, }); customElements.define('some-component', ngElement); } ngDoBootstrap() {} }
Kami membutuhkan:
- Tambahkan ke entriKomponen komponen yang kami rencanakan untuk membuat elemen sudut, impor modul yang diperlukan untuk komponen.
- Buat elemen sudut menggunakan createCustomElement dan injektor.
- Deklarasikan komponen web di customElements browser Anda.
- Ganti metode ngDoBootstrap menjadi kosong.
Item pertama adalah penunjukan komponen itu sendiri dan dependensinya, dan tiga sisanya adalah proses yang diperlukan untuk penampilan komponen web di browser. Pemisahan ini memungkinkan Anda untuk menempatkan logika membuat elemen secara terpisah, dalam superclass abstrak:
export abstract class MyElementModule { constructor(injector: Injector, component: InstanceType<any>, name: string) { const ngElement = createCustomElement(component, { injector, }); customElements.define(`${MY_PREFIX}-${name}`, ngElement); } ngDoBootstrap() {} }
Superclass mampu merakit komponen asli lengkap dari injektor, komponen, dan nama dan mendaftarkannya. Modul untuk membuat elemen tertentu akan terlihat seperti ini:
@NgModule({ imports: [BrowserModule, MyButtonModule], entryComponents: [MyButtonComponent], }) export class ButtonModule extends MyElementModule { constructor(injector: Injector) { super(injector, MyButtonComponent, 'button'); } }
Dalam contoh ini, kami mengumpulkan modul tombol kami ke dalam metadata NgModule dan mendeklarasikan komponen dari modul ini di entryComponents, dan juga mendapatkan injektor dari mekanisme injeksi dependensi sudut.
Modul ini siap untuk perakitan dan akan memberi kita satu set file JS yang dapat dilipat menjadi komponen web yang terpisah. Dengan cara ini kita dapat membuat beberapa modul dan secara bergiliran merakit komponen web darinya.
Menyusun beberapa komponen
Sekarang kita perlu mengatur proses bootstrap dari modul yang dihasilkan. Yang paling penting, saya menyukai gagasan untuk menempatkan logika ini ke dalam file yang dapat dieksekusi terpisah, yang akan bertanggung jawab untuk mengkompilasi modul tertentu.
Struktur elemennya kira-kira seperti ini:

File kompilasi terpisah dalam versi paling sederhana akan terlihat seperti ini:
enableProdMode(); platformBrowserDynamic() .bootstrapModule(ButtonModule) .catch(err => console.error(err));
Pendekatan ini akan membantu memotong modul yang disiapkan dengan mudah dan mempertahankan struktur proyek dengan Elemen yang jelas dan sederhana.
Di pengaturan build angular.json, kami menentukan path file yang dikumpulkan ke folder sementara tertentu di dalam dist:
"outputPath": "projects/elements/dist/tmp"
Akan ada jatuh satu set file output setelah membangun modul.
Untuk perakitan itu sendiri, gunakan perintah build yang biasa di angular-cli:
ng run elements:build:production --main='projects/elements/src/${project}/${component}/compile.ts'
Elemen terpisah akan menjadi produk akhir, jadi kami mengaktifkan flag produksi dengan kompilasi Ahead-of-Time, dan setelah itu kami mengganti path ke file executable, yang terdiri dari proyek dan nama komponen.
Sekarang kami akan mengumpulkan hasilnya dalam file terpisah, yang akan menjadi bundel terakhir dari komponen web kami yang terpisah. Untuk melakukan ini, gunakan kucing biasa:
cat dist/tmp/runtime.js dist/tmp/main.js > dist/tmp/my-${component}.js
Penting untuk dicatat di sini bahwa kami tidak meletakkan file polyfills.js di bundel setiap komponen, karena kami mendapatkan duplikasi jika kami menggunakan beberapa komponen pada halaman yang sama di masa mendatang. Tentu saja, Anda harus menonaktifkan opsi outputHashing di angular.json.
Kami akan mentransfer bundel yang dihasilkan dari folder sementara ke folder untuk menyimpan komponen. Misalnya, seperti ini:
cp dist/tmp/my-${component}.js dist/components/
Tetap hanya menyatukan semuanya - dan skrip kompilasi siap:
Sekarang kami memiliki ayah yang rapi dengan serangkaian komponen web:

Hubungkan komponen ke halaman reguler
Komponen web rakitan kami dapat dimasukkan secara independen ke halaman, menghubungkan bundel JS mereka sesuai kebutuhan:
<my-elements-input id="input"> </<my-elements-input> <script src="my-input.js"></script>
Agar tidak menyeret seluruh zone.js dengan setiap komponen, kami menyambungkannya sekali di awal dokumen:
<script src="zone.min.js"></script>
Komponen ditampilkan pada halaman, dan semuanya baik-baik saja.
Dan mari kita tambahkan tombol:
<my-elements-button size="l" onclick="onClick()"></my-elements-button> <script src="my-button.js"></script>
Kami meluncurkan halaman dan ...

Oh, ini rusak!
Jika kita melihat ke dalam bundel, kita menemukan ada garis yang tidak mencolok:
window.webpackJsonp=window.webpackJsonp||[]

Jendela patch webpack, agar tidak menduplikasi pemuatan modul yang sama. Ternyata hanya komponen pertama yang ditambahkan ke halaman yang dapat menambahkan dirinya sendiri ke customElements.
Untuk mengatasi masalah ini, kita perlu menggunakan custom-webpack:
- Tambahkan custom-webpack ke proyek dengan elemen:
ng add @angular-builders/custom-webpack --project=elements
- Mengkonfigurasi angular.json:
"builder": "@angular-builders/custom-webpack:browser", "options": { "customWebpackConfig": { "path": "./projects/elements/elements-webpack.config.js" }, ...
- Buat file konfigurasi custom-webpack:
module.exports = { output: { jsonpFunction: 'myElements-' + uuidv1(), library: 'elements', }, };
Di dalamnya, kita perlu membuat id unik untuk setiap perakitan dengan cara yang nyaman. Saya memanfaatkan uuid.
Anda dapat menjalankan skrip build lagi - komponen baru rukun di halaman yang sama.
Membawa kecantikan
Komponen kami menggunakan variabel CSS global yang menentukan tema warna dan ukuran komponen.
Dalam aplikasi sudut menggunakan perpustakaan kami, mereka diletakkan di komponen root proyek. Dengan komponen web independen, ini tidak mungkin, jadi hanya mengkompilasi gaya dan terhubung ke halaman di mana komponen web digunakan.
Kami menggunakan lebih sedikit, jadi kompilasi variabel lessc kami dan letakkan file yang dihasilkan di folder helpers.
Pendekatan ini memungkinkan Anda untuk mengontrol gaya semua komponen web halaman tanpa perlu mengkompilasi ulang.
Naskah akhir
Bahkan, seluruh proses perakitan elemen yang dijelaskan di atas dapat direduksi menjadi serangkaian tindakan:
Tetap hanya untuk memanggil skrip ini dari package.json utama untuk mengurangi seluruh proses kompilasi komponen sudut aktual untuk peluncuran perintah tunggal.
Semua skrip yang dijelaskan di atas, serta demo untuk menggunakan komponen sudut dan asli, dapat ditemukan di
github .
Total
Kami mengorganisasikan suatu proses di mana menambahkan komponen web baru hanya membutuhkan beberapa menit, sambil mempertahankan struktur proyek sudut utama dari mana mereka diambil.
Pengembang apa pun dapat menambahkan komponen ke serangkaian elemen dan menggabungkannya ke dalam kumpulan bundel JS terpisah dari komponen web tanpa mempelajari spesifikasi bekerja dengan Elemen Sudut.