Memahami organisasi entitas tempat Anda bekerja bukanlah sesuatu yang langsung datang dari pengembang yang menulis proyek pertamanya di Angular.
Dan salah satu masalah yang dapat Anda temukan adalah penggunaan modul Angular yang tidak efisien, khususnya modul aplikasi yang kelebihan beban: mereka membuat komponen baru, melemparkannya ke dalamnya, dan layanannya juga ada di sana. Dan semuanya tampak hebat, semuanya bekerja. Namun, seiring berjalannya waktu, proyek semacam itu akan sulit dipertahankan dan dioptimalkan.
Untungnya, Angular memberi pengembang kemampuan untuk membuat modul mereka sendiri, dan juga menyebutnya modul fitur.

Modul Fitur Domain
Modul aplikasi kelebihan beban perlu dipisah. Oleh karena itu, hal pertama yang harus dilakukan adalah memilih potongan besar dalam aplikasi dan menempatkannya dalam modul terpisah.
Pendekatan populer adalah membagi aplikasi menjadi modul fitur domain. Mereka dirancang untuk membagi antarmuka berdasarkan tugas utama (domain) yang dilakukan masing-masing bagian. Contoh modul fitur domain termasuk halaman pengeditan profil, halaman produk, dll. Sederhananya, semua itu bisa di bawah item menu.

Semua iklan dalam bingkai biru, serta konten item menu lainnya, pantas mendapatkan modul fitur domain mereka sendiri.
Modul fitur domain dapat menggunakan jumlah deklarasi yang tidak terbatas (komponen, arahan, pipa), namun mereka hanya mengekspor komponen yang mewakili UI modul ini. Modul fitur domain diimpor, biasanya dalam satu, modul yang lebih besar.
Modul Fitur Domain biasanya tidak menyatakan layanan dalam dirinya. Namun, jika mereka mengumumkan, maka umur layanan ini harus dibatasi pada umur modul. Ini dapat dicapai dengan menggunakan layanan pemuatan malas atau iklan di komponen eksternal modul. Metode-metode ini akan dibahas nanti dalam artikel.
Pemuatan Malas
Membagi aplikasi menjadi modul Fitur Domain memungkinkan Anda menggunakan pemuatan malas . Jadi, Anda dapat menghapus dari bundel asli apa yang tidak diperlukan pengguna saat membuka aplikasi untuk pertama kalinya: profil pengguna, halaman produk, halaman foto, dll. Semua ini dapat dimuat sesuai permintaan.
Layanan dan Injector
Aplikasi ini dibagi menjadi beberapa bagian - modul besar, dan beberapa modul ini dimuat sesuai permintaan. Pertanyaan: di mana layanan global harus diumumkan? Dan bagaimana jika kita ingin membatasi ruang lingkup layanan?
Injector dari modul malas dimuat
Tidak seperti yang dapat dideklarasikan, keberadaan yang harus dideklarasikan di setiap modul tempat mereka digunakan, layanan tunggal dideklarasikan sekali dalam salah satu modul menjadi tersedia di seluruh aplikasi.
Ternyata layanan dapat dideklarasikan dalam modul apa saja dan tidak perlu khawatir? Tidak terlalu seperti itu.
Hal di atas benar jika aplikasi hanya menggunakan injektor global, tetapi seringkali semuanya agak lebih menarik. Modul bermuatan luar biasa memiliki injektor sendiri (komponen juga, tetapi lebih lanjut tentang itu nanti). Mengapa modul yang dimuat dengan malas bahkan membuat injektor mereka sendiri? Alasannya terletak pada bagaimana injeksi ketergantungan bekerja di Angular.
Injektor dapat diisi ulang dengan penyedia baru sampai mulai digunakan. Segera setelah injektor menciptakan layanan pertama, itu ditutup untuk menambah penyedia baru.
Ketika aplikasi dimulai, Angular pertama-tama membuat injektor root, memperbaiki di dalamnya penyedia yang dideklarasikan dalam modul Aplikasi dan dalam modul yang diimpor ke dalamnya. Ini berlaku bahkan sebelum membuat komponen pertama dan sebelum memberikan mereka dependensi.
Dalam situasi di mana modul dimuat dengan malas, injektor global telah dikonfigurasi untuk waktu yang lama dan telah mulai beroperasi. Modul yang dimuat tidak memiliki pilihan selain membuat injektor sendiri. Injektor ini akan menjadi anak dari injektor yang digunakan dalam modul yang memulai beban. Ini mengarah ke perilaku yang akrab bagi pengembang javascript dalam rantai prototipe: jika layanan tidak ditemukan dalam injektor modul yang malas, kerangka kerja DI akan mencarinya dalam injector induk, dll.
Dengan demikian, modul yang dimuat dengan malas memungkinkan Anda untuk mendeklarasikan layanan yang hanya akan tersedia dalam kerangka modul ini. Penyedia juga dapat didefinisikan ulang, sekali lagi, sama seperti dalam prototipe javascript.
Kembali ke modul fitur domain, perilaku yang dijelaskan adalah salah satu cara untuk membatasi masa pakai penyedia yang diiklankan di dalamnya.
Modul Inti
Jadi, di mana layanan global harus diumumkan, seperti layanan otorisasi, layanan API, layanan Pengguna, dll.? Jawaban sederhana ada di modul Aplikasi. Namun, untuk memulihkan ketertiban dalam modul Aplikasi (ini yang kami lakukan), Anda harus mendeklarasikan layanan global dalam modul terpisah, yang disebut modul Inti, dan mengimpor HANYA ke dalam modul Aplikasi. Hasilnya akan sama seperti jika layanan dinyatakan secara langsung dalam modul Aplikasi.
Dimulai dengan versi 6, di sudut ada peluang untuk mendeklarasikan layanan global tanpa mengimpornya di mana pun. Yang perlu Anda lakukan adalah menambahkan opsi yang disediakan pada Injectable dan tentukan nilai 'root' di dalamnya. Layanan yang dideklarasikan dengan cara ini tersedia untuk seluruh aplikasi, dan oleh karena itu tidak perlu mendeklarasikannya dalam modul.
Selain fakta bahwa pendekatan ini melihat masa depan yang cerah dari sudut tanpa modul, juga membantu untuk memotong kode yang tidak perlu.
Tes Singleton
Tetapi bagaimana jika seseorang dalam proyek ingin mengimpor modul Core di tempat lain? Mungkinkah melindungi diri dari hal ini? Kamu bisa.
Tambahkan konstruktor ke modul Core yang meminta Anda untuk menyuntikkan modul Core ke dalamnya (itu benar, Anda sendiri), dan tandai deklarasi ini dengan dekorator Opsional dan SkipSelf. Jika injector meletakkan dependensi dalam variabel, maka seseorang mencoba mendeklarasikan ulang modul Core.

Menggunakan pendekatan yang dijelaskan dalam BrowserModule .
Pendekatan ini dapat digunakan dengan modul dan layanan.
Pengumuman Layanan di Komponen
Kami telah mempertimbangkan cara untuk membatasi ruang lingkup penyedia menggunakan pemuatan yang malas, tetapi inilah yang lain.
Setiap instance komponen memiliki injektor sendiri, dan untuk mengkonfigurasinya, seperti dekorator NgModule, dekorator Komponen memiliki properti penyedia. Dan juga - properti tambahan viewProviders. Keduanya berfungsi untuk mengkonfigurasi komponen injektor, namun, penyedia menyatakan dalam setiap metode memiliki cakupan yang berbeda.
Untuk memahami perbedaannya, Anda perlu latar belakang pendek.
Komponen terdiri dari tampilan dan konten.

Lihat komponen

Komponen Konten
Semua yang ada di file html komponen adalah pandangannya, sedangkan yang dilewatkan antara tag komponen pembuka dan penutup adalah kontennya.
Hasil yang diperoleh:

Hasilnya
Jadi, penyedia yang ditambahkan ke penyedia tersedia baik dalam pandangan komponen di mana mereka dinyatakan, dan untuk konten yang diteruskan ke komponen. Sedangkan viewProviders, seperti namanya, membuat layanan terlihat hanya untuk melihat dan menutupnya ke konten.
Terlepas dari kenyataan bahwa itu adalah praktik terbaik untuk mendeklarasikan layanan di root injector, ada skenario ketika menggunakan komponen injector sudah dekat:
Yang pertama adalah ketika setiap instance komponen baru harus memiliki instance layanannya sendiri. Misalnya, layanan yang menyimpan data khusus untuk setiap instance komponen baru.
Untuk skenario lain, kita harus ingat bahwa, meskipun modul fitur Domain dapat mendeklarasikan beberapa penyedia yang mereka butuhkan saja, diharapkan bahwa penyedia ini mati dengan modul-modul ini. Dalam hal ini, kami akan mendeklarasikan penyedia di komponen paling eksternal, yang diekspor dari modul.
Misalnya, modul fitur domain yang bertanggung jawab untuk profil pengguna. Kami akan mendeklarasikan layanan yang diperlukan hanya untuk bagian aplikasi ini di penyedia komponen paling eksternal, UserProfileComponent. Sekarang semua deklarabel yang dideklarasikan dalam markup komponen ini, serta diteruskan ke dalamnya dalam konten, akan menerima contoh layanan yang sama.
Komponen yang Dapat Digunakan Kembali
Apa yang harus dilakukan dengan komponen yang ingin kita gunakan kembali? Tidak ada jawaban pasti untuk pertanyaan ini, tetapi ada pendekatan yang terbukti.
Modul bersama
Semua komponen yang digunakan dalam proyek dapat disimpan dalam satu modul, mengekspornya dari itu dan mengimpornya ke dalam modul-modul proyek di mana komponen-komponen ini mungkin diperlukan.
Dalam modul seperti itu, Anda dapat meletakkan komponen tombol, daftar drop-down, blok teks bergaya, dll., Serta arahan khusus dan pipa.
Modul semacam itu biasanya disebut SharedModule.
Penting untuk dicatat bahwa SharedModule tidak boleh mendeklarasikan layanan. Atau mendeklarasikan menggunakan pendekatan forRoot. Kami akan membicarakannya nanti.
Meskipun pendekatan SharedModules berfungsi, ada beberapa poin untuk itu:
- Kami tidak membuat struktur aplikasi lebih bersih, kami hanya memindahkan kekacauan dari satu tempat ke tempat lain;
- Pendekatan ini tidak melihat masa depan Angular yang cerah, yang tidak akan memiliki modul.
Pendekatan yang tanpa kekurangan ini adalah dan melibatkan pembuatan modul untuk setiap komponen.
Modul Per Komponen atau SCAM (modul sudut tunggal komponen)
Saat membuat komponen baru, Anda harus meletakkannya di modul Anda sendiri. Anda harus mengimpor dependensi komponen ke dalam modul yang sama.

Setiap kali komponen tertentu diperlukan di setiap tempat dalam aplikasi, semua yang perlu dilakukan adalah mengimpor modul komponen ini.
Dalam bahasa Inggris, pendekatan ini disebut modul per komponen atau SCAM - modul sudut komponen tunggal. Meskipun namanya mengandung komponen kata, pendekatan ini juga berlaku untuk pipa dan arahan (SPAM, SDAM).
Mungkin keunggulan paling signifikan dari pendekatan ini adalah fasilitasi pengujian komponen. Karena modul yang dibuat untuk komponen mengekspornya, dan juga sudah berisi semua dependensi yang diperlukan, untuk mengkonfigurasi TestBed, cukup masukkan modul ini ke impor.
Pendekatan ini berkontribusi pada urutan dan struktur dalam kode proyek, dan juga mempersiapkan kita untuk masa depan tanpa modul, di mana untuk menggunakan satu komponen dalam tata letak yang lain, Anda hanya perlu mendeklarasikan dependensi dalam direktif Komponen. Anda dapat melihat sedikit ke masa depan melalui artikel ini .
ModuleWithProviders Interface
Jika modul yang berisi deklarasi layanan XYZ dimulai di proyek, dan kebetulan modul ini mulai digunakan di mana-mana, setiap impor modul ini akan mencoba menambahkan layanan XYZ ke injector yang sesuai, yang pasti akan mengarah pada tabrakan. Angular memiliki seperangkat aturan untuk kasus ini, yang mungkin tidak sesuai dengan apa yang diharapkan pengembang. Hal ini terutama berlaku untuk modul malas yang di-injector.
Untuk menghindari masalah tabrakan, Angular menyediakan antarmuka ModuleWithProviders , yang memungkinkan Anda untuk melampirkan penyedia ke modul, sambil membiarkan penyedia modul itu sendiri tidak tersentuh. Dan inilah yang dibutuhkan dalam kasus yang dijelaskan di atas.
Strategi forRoot (), forChild ()
Agar layanan dapat diperbaiki secara tepat di injektor global, modul dengan penyedia diimpor hanya di AppModule. Dari sisi modul yang diimpor, Anda hanya perlu membuat metode statis yang mengembalikan ModuleWithProviders, yang secara historis menerima nama forRoot.

Metode yang mengembalikan ModuleWithProviders dapat berupa angka apa saja, dan mereka dapat dinamai sesuka Anda. forRoot adalah konvensi yang lebih nyaman daripada persyaratan.
Misalnya, RouterModule memiliki metode forChild statis, yang digunakan untuk mengonfigurasi perutean dalam modul yang dimuat dengan malas.
Kesimpulan:
- Pisahkan antarmuka pengguna dengan tugas-tugas utama dan buat modul Anda sendiri untuk setiap bagian yang dipilih: selain lebih nyaman untuk memahami struktur kode proyek, dapatkan kesempatan untuk dengan malas memuat bagian-bagian antarmuka
- Gunakan injektor modul dan komponen yang malas jika arsitektur aplikasi membutuhkannya
- Posting pengumuman layanan global dalam modul terpisah, modul Core, dan impor hanya di modul aplikasi. Ini akan membantu dalam membersihkan modul aplikasi.
- Lebih baik, gunakan opsi yang disediakan dengan nilai root dari dekorator injeksi.
- Gunakan retas dengan dekorator Opsional dan SkipSelf untuk mencegah impor ulang modul dan layanan
- Simpan komponen, arahan, dan pipa yang dapat digunakan kembali dalam modul Shared
- Namun, pendekatan terbaik, yang juga melihat ke masa depan, dan memfasilitasi pengujian adalah membuat modul untuk setiap komponen (arahan dan pipa juga)
- Gunakan antarmuka ModuleWithProviders jika Anda ingin menghindari konflik penyedia. Pendekatan yang populer adalah menerapkan metode forRoot untuk menambahkan penyedia ke modul root