Alice
測試上線,發現包體積太大,加載太慢。決定啓用懶加載與預加載加速加載速度。typescript
整三天,課也沒去上。改得時候特別痛苦,哭了,爲何沒有早點發現惰性加載這個東西。小程序
星期一,從新設計前臺架構,重構前臺代碼。api
星期二,分模塊加載,啓用惰性加載與預加載。架構
星期三,修改單元測試,添加provide
。async
星期四,寫PPT
。ide
星期五,.NET
考試。單元測試
重構前臺以後,以爲本身當前設計的架構很合理,遂分享出來,供你們學習交流。學習
架構理論主要參考外國老哥的一篇文章,Angular (2+): Core vs Shared Modules測試
CoreModule
:核心模塊,只被AppModule
引用,保證全局單例。spa
ShareModule
:共享模塊,被各業務模塊引用,存儲各模塊必備的組件、管道以及模板。
CoreModule
核心Module
,全局只導入一次。
稱之爲核心,由於沒有它應用跑不起來。
核心模塊存放攔截器和服務,不過與正常的有些區別。
攔截器
@Injectable() export class YunzhiInterceptor implements HttpInterceptor { }
@NgModule({ imports: [ NgZorroAntdModule, RouterModule ], providers: [ {provide: HTTP_INTERCEPTORS, useClass: YunzhiInterceptor, multi: true} ] }) export class CoreModule { }
服務
@Injectable({ providedIn: CoreModule }) export class CollegeService { }
如今不往root
裏注入了,由於發現有的時候寫root
有人會搞不清楚模塊的層級關係,而後就懵圈了。
爲了規避這種問題,直接注入到核心模塊中,防止有人誤解。
norm
實際上是想起一個規範的英文的,可是spec
卻被測試給用了,因此就去百度翻譯了個放這了。
這個包主要是存儲數據規範的。
entity
存儲實體,對應後臺實體。
target
存儲自定義的規範對象,歷史的教訓告訴咱們,若是把全部都放到實體包裏,這很糟糕。
page
這個是向小程序抄來的,小組件能夠複用,大組件就須要單建目錄了,都放一塊兒看着混亂。
分模塊加載,每一個功能一個單獨的模塊,模塊職責劃分清晰。
@NgModule({ declarations: [ SetupComponent ], imports: [ SetupRouteModule, ShareModule ] }) export class SetupModule { }
模塊中就這幾行,什麼廢話都不要寫,就聲明本模塊的組件,並導入本模塊的路由和Share
模塊。其餘的都不要寫,第三方的導入交給ShareModule
去處理。本模塊只負責業務,不負責代碼。
ShareModule
全局複用的組件,全局複用的管道,全局複用的驗證器,以及其餘第三方組件的導入導出。
@NgModule({ imports: [ ComponentModule, PipeModule, RouterModule ], exports: [ ComponentModule, PipeModule, RouterModule ] }) export class ShareModule { }
規規矩矩,整整潔潔。
ShareModule
的子模塊的實現都放在api
目錄裏。
子模塊示例:
@NgModule({ declarations: [ CourseTypePipe, SemesterStatusPipe, YunzhiGradeStatusPipe, YunzhiKlassStatusPipe, YunzhiScoreStatusPipe ], exports: [ CourseTypePipe, SemesterStatusPipe, YunzhiGradeStatusPipe, YunzhiKlassStatusPipe, YunzhiScoreStatusPipe ] }) export class PipeModule { }
spec
測試目錄,爲何單拿出來這個目錄,主要是爲了解決Service
的測試數據問題。
本模塊存儲全部以.test.service.ts
結尾的測試service
。
而後全部的測試Service
去繼承原Service
,並重寫裏面的方法,這裏的@Injectable()
註解中不用加providedIn
,由於沒有專業的測試模塊,每一個測試用例中咱們使用provide
進行注入。
@Injectable() export class CollegeTestService extends CollegeService { }
原來直接跑ng test
特別快,根本看不清楚組件的建立,這兩天發現了一個新套路,跑測試的時候上YouTube
點開個視頻看,而後電腦就特別卡,測試跑的時候就慢了。
而後就能夠清楚地看到每一個測試用例的執行過程,看到每一個組件如何建立並顯示。也不知道改了哪裏,如今Alice
跑測試的時候最後給出一個Karma
的測試報告。
直接把錯誤報出來,也好修改。
測試最後怎麼設計的呢?也說不明白,看代碼就是了。最近才發現以前的測試用例寫得都不正確。
其實一個測試,就是構建了一個測試的模塊,該模塊和其餘模塊都相同。
發現不少測試中爲了能跑過,直接把公共組件或公共管道寫在了declarations
裏,這是不合理的,雖然測試能跑過,可是理論上,這個測試就是測這個的,因此模塊中的declarations
只有它本身。
而後這裏的imports
也是通過反覆的測試,導入BrowserAnimationsModule
、HttpClientTestingModule
、RouterTestingModule
、ShareModule
這四個模塊,這個測試的全部依賴就都有了,其餘的什麼都不要導入,看着混亂。
providers
聲明本模塊中要注入的對象,這裏受益於CoreModule
的設計,Service
都放在了CoreModule
裏,而業務模塊是不能導入CoreModule
的,只能導入ShareModule
,因此模塊中是用不了已有的Service
。
因此,乖乖地給我建一個測試的Service
,而後注入進去。也算是強制組員寫測試的一種手段。
describe('SetupComponent', () => { let component: SetupComponent; let fixture: ComponentFixture<SetupComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [SetupComponent], imports: [ BrowserAnimationsModule, HttpClientTestingModule, RouterTestingModule, ShareModule ], providers: [ { provide: UserService, useClass: UserTestService } ] }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(SetupComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });
最佳實踐,都是從坑裏爬出來後才總結出來的。
上次我感慨Angular
架構設計難的時候是4
月26
日,當時只是對Alice
進行小改,還不到一月,現在一次性對前臺作了這麼大的改動,坑也踩得多了,爬出坑後,最佳實踐,其實就在眼前。
此次的架構設計得很整潔,打完包後也很快,我很滿意。
古人學問無遺力,少壯工夫老始成。
紙上得來終覺淺,絕知此事要躬行。
——陸游《冬夜讀書示子聿》之後再設計不能紙上談兵,要努力去實踐,經歷得多了,最佳實踐天然就出來了。