SudutProjek ini terlalu besar, bagaimana untuk membahagikannya secara munasabah? Artikel berikut akan memperkenalkan kepada anda cara membahagikan projek Angular secara munasabah. Saya harap ia akan membantu anda!
Salah satu kritikan tentang Angular ialah ia sangat besar selepas pembungkusan Jika anda tidak berhati-hati main.js
ia menjadi besar yang tidak masuk akal , sama ada saiz besar , data besar atau trafik besar, hanya ada satu idea: pemisahan. Ditambah dengan mekanisme caching pelayar, kelajuan capaian projek boleh dioptimumkan. [Tutorial berkaitan yang disyorkan: "tutorial sudut"]
Kod yang berkaitan untuk artikel ini ialah di: https://github.com/Vibing/angular-webpack
Keseluruhan projek termasuk: pustaka pergantungan yang kukuh (rangka kerja sudut itu sendiri), pustaka komponen UI dan pustaka pihak ketiga, dan bahagian kod perniagaan;
Dimensi tingkah laku pengguna: semua lawatan pengguna adalah berdasarkan laluan, satu laluan setiap halaman; dua perkara di atas, berdasarkan yang pertama Anda boleh membungkus perpustakaan dan perpustakaan yang sangat bergantung kepada yang jarang berubah menjadi
, yang boleh termasuk, vendor_library
dan pakej lain yang serupa, UI perpustakaan komponen atau @angular/common
Tidak disyorkan untuk membungkus jenis perpustakaan ini bersama-sama, kerana kita perlu menggunakan TreeShaking, dan tidak perlu membungkus kod yang tidak digunakan, jika tidak, ia hanya akan meningkatkan saiz. @angular/core
@angular/forms
Memandangkan pakej pergantungan yang kukuh telah sedia, mari pakejkan kod perniagaan berdasarkan perkara 2. Kami menggunakan @angular/router
berasaskan penghalaan untuk pembungkusan. Ideanya sangat mudah. Mana-mana halaman yang dilawati pengguna, js yang sepadan dengan halaman itu dimuat turun Tidak perlu membungkus halaman yang tidak dilawati ini bukan sahaja akan meningkatkan saiz, tetapi juga meningkatkan masa muat turun, dan pengguna pengalaman juga akan merosot. lodash
Konfigurasi webpack tersuaicode spliting
Pasang
dan@angular-builders/custom-webpack
@angular-devkit/build-angular
Buat yang baharu webpack.extra.config.ts digunakan untuk konfigurasi webpack
Buat pengubahsuaian berikut dalam angular.json
... "architect": { "build": { "builder": "@angular-builders/custom-webpack:browser", "options": { ... "customWebpackConfig": { // 引用要拓展的 webpack 配置 "path": "./webpack.extra.config.ts", // 是否替换重复插件 "replaceDuplicatePlugins": true } } }, "serve": { "builder": "@angular-builders/custom-webpack:dev-server", "options": { "browserTarget": "angular-webpack:build" } } ...
const path = require("path"); const webpack = require("webpack"); module.exports = { mode: "production", entry: { vendor: [ "@angular/platform-browser", "@angular/platform-browser-dynamic", "@angular/common", "@angular/core", "@angular/forms", "@angular/router" ], }, output: { path: path.resolve(__dirname, "./dll"), filename: "[name].dll.js", library: "[name]_library", }, plugins: [ new webpack.DllPlugin({ context: path.resolve(__dirname, "."), path: path.join(__dirname, "./dll", "[name]-manifest.json"), name: "[name]_library", }), ], };
Selepas melaksanakan
, akan ada folder dll pada akar projek, yang mengandungi kandungan berpakej:import * as path from 'path'; import * as webpack from 'webpack'; export default { plugins: [ new webpack.DllReferencePlugin({ manifest: require('./dll/vendor-manifest.json'), context: path.resolve(__dirname, '.'), }) ], } as webpack.Configuration;
"dll": "rm -rf dll && webpack --config webpack.dll.js"
npm run dll
dalam projek dan mengkonfigurasinya dalam :
vendor.dll.js
Anda boleh melihatnya selepas pembungkusan Bagi angular.json
, ia telah diperkenalkan:
"architect": { ... "build": { ... "options": { ... "scripts": [ { "input": "./dll/vendor.dll.js", "inject": true, "bundleName": "vendor_library" } ] } } }
vendor_library.js
dan menyimpannya di cache Setiap lawatan berikutnya akan diambil terus daripada cache Penyemak imbas hanya akan memuat turun js kod perniagaan dan tidak akan memuat turun rangka kerja kod, yang meningkatkan prestasi kelajuan pemuatan aplikasi meningkatkan pengalaman pengguna.
ps: Cincang di belakang vendor_library hanya akan ditukar jika kod di dalamnya ditukar semasa pembungkusan, jika tidak, ia tidak akan berubah.vendor_library.js
{ path:'/home', component: () => import('./home') }
{ path:'/home', loadChild: ()=> import('./home.module').then(m => m.HomeModule) }
komponen dalam penghala, Angular menyediakan
import dinamik komponenimport { HomeComponent } from './home.component' { path:'', component: HomeComponent }
import()
Dengan cara ini, apabila mengakses halaman tertentu melalui penghalaan, selagi kandungan halaman yang diakses digunakan import() dan diimport secara dinamik dengan komponen
@Component({ selector: 'app-home', template: ``, }) export class HomeContainerComponent implements OnInit { constructor( private vcref: ViewContainerRef, private cfr: ComponentFactoryResolver ){} ngOnInit(){ this.loadGreetComponent() } async loadGreetComponent(){ this.vcref.clear(); // 使用 import() 懒加载组件 const { HomeComponent } = await import('./home.component'); let createdComponent = this.vcref.createComponent( this.cfr.resolveComponentFactory(HomeComponent) ); } }
答案是可以的。但是这样会有一个大问题:被 lazyLoad 的组件中,其内容仅仅是当前组件的代码,并不包含引用的其他模块中组件的代码。
原因是 Angular 应用由多个模块组成,每个模块中需要的功能可能来自其他模块,比如 A 模块里要用到 table
组件,而 table
需取自于 ng-zorro-antd/table
模块。打包时 Angular 不像 React 或 Vue 可以把当前组件和用到的其他包一起打包,以 React 为例:在 A 组件引入 table 组件,打包时 table 代码会打包到 A 组件中。而 Angular 中,在 A 组件中使用 table 组件时,并且使用 imprt()
对 A 组件进行动态加载,打包出来的 A 组件并不包含 table 的代码, 而是会把 table 代码打包到当前模块中去,如果一个模块中包含多个页面,这么多页面用了不少UI组件,那么打包出来的模块肯定会很大。
那么就没有别的方法了吗?答案是有的,那就是把每个页面拆成一个 module,每个页面所用到的其他模块或组件由当前页面对应的模块所承担。
上图中 dashboard
作为一个模块,其下有两个页面,分别是 monitor
和 welcome
dashboard.module.ts:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: 'welcome', loadChildren: () => import('./welcome/welcome.module').then((m) => m.WelcomeModule), }, { path: 'monitor', loadChildren: () => import('./monitor/monitor.module').then((m) => m.MonitorModule), }, ]; @NgModule({ imports: [CommonModule, RouterModule.forChild(routes)], exports: [RouterModule], declarations: [], }) export class DashboardModule {}
在模块中使用路由 loadChildren 来 lazyLoad 两个页面模块,现在再看看 WelcomeModule:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { WelcomeComponent } from './welcome.component'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: '', component: WelcomeComponent } ]; @NgModule({ declarations: [WelcomeComponent], imports: [RouterModule.forChild(routes), CommonModule] }) export class WelcomeModule {}
就是这么简单,就把页面级的 lazyLoad 完成了。当需要使用外部组件时,比如 table 组件,只要在 imports 引入即可:
import { NzTableModule } from 'ng-zorro-antd/table'; @NgModule({ ... imports: [..., NzTableModule] }) export class WelcomeModule {}
题外话:我更喜欢 React 的拆分方式,举个例子:React 中使用 table 组件,table 组件本身代码量比较大,如果很多页面都使用 table,那么每个页面都会有 table 代码,造成不必要的浪费。所以可以配合 import()
把 table
组件单拉出来,打包时 table
作为单独的 js
被浏览器下载并提供给需要的页面使用,所有页面共享这一份 js
即可。但 Angular 做不到,它无法在模块的 imports
中使用 import()
的模块 。
以上都是对项目代码做了比较合理的拆分,后续会对 Angular 性能上做合理的优化,主要从编译模式、变更检测、ngFor、Worker等角度来阐述。
更多编程相关知识,请访问:编程视频!!
Atas ialah kandungan terperinci Apakah yang perlu saya lakukan jika projek itu terlalu besar? Bagaimana untuk membahagikan projek Angular dengan munasabah?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!