Angular 架构设计

引言

Alice测试上线,发现包体积太大,加载太慢。决定启用懒加载与预加载加速加载速度。typescript

整三天,课也没去上。改得时候特别痛苦,哭了,为何没有早点发现惰性加载这个东西。小程序

clipboard.png

星期一,从新设计前台架构,重构前台代码。api

星期二,分模块加载,启用惰性加载与预加载。架构

星期三,修改单元测试,添加provideasync

星期四,写PPTide

星期五,.NET考试。单元测试

重构前台以后,以为本身当前设计的架构很合理,遂分享出来,供你们学习交流。学习

架构

理论

架构理论主要参考外国老哥的一篇文章,Angular (2+): Core vs Shared Modules测试

clipboard.png

CoreModule:核心模块,只被AppModule引用,保证全局单例。spa

ShareModule:共享模块,被各业务模块引用,存储各模块必备的组件、管道以及模板。

实践

CoreModule

核心Module,全局只导入一次。

称之为核心,由于没有它应用跑不起来。

clipboard.png

核心模块存放拦截器和服务,不过与正常的有些区别。

拦截器

@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却被测试给用了,因此就去百度翻译了个放这了。

clipboard.png

这个包主要是存储数据规范的。

entity存储实体,对应后台实体。

target存储自定义的规范对象,历史的教训告诉咱们,若是把全部都放到实体包里,这很糟糕。

page

这个是向小程序抄来的,小组件能够复用,大组件就须要单建目录了,都放一块儿看着混乱。

clipboard.png

分模块加载,每一个功能一个单独的模块,模块职责划分清晰。

@NgModule({
    declarations: [
        SetupComponent
    ],
    imports: [
        SetupRouteModule,
        ShareModule
    ]
})
export class SetupModule {
}

模块中就这几行,什么废话都不要写,就声明本模块的组件,并导入本模块的路由和Share模块。其余的都不要写,第三方的导入交给ShareModule去处理。本模块只负责业务,不负责代码。

ShareModule

clipboard.png

全局复用的组件,全局复用的管道,全局复用的验证器,以及其余第三方组件的导入导出。

@NgModule({
    imports: [
        ComponentModule,
        PipeModule,
        RouterModule
    ],
    exports: [
        ComponentModule,
        PipeModule,
        RouterModule
    ]
})
export class ShareModule {
}

规规矩矩,整整洁洁。

clipboard.png

ShareModule的子模块的实现都放在api目录里。

子模块示例:

@NgModule({
    declarations: [
        CourseTypePipe,
        SemesterStatusPipe,
        YunzhiGradeStatusPipe,
        YunzhiKlassStatusPipe,
        YunzhiScoreStatusPipe
    ],
    exports: [
        CourseTypePipe,
        SemesterStatusPipe,
        YunzhiGradeStatusPipe,
        YunzhiKlassStatusPipe,
        YunzhiScoreStatusPipe
    ]
})
export class PipeModule {
}

spec

测试目录,为何单拿出来这个目录,主要是为了解决Service的测试数据问题。

clipboard.png

本模块存储全部以.test.service.ts结尾的测试service

clipboard.png

而后全部的测试Service去继承原Service,并重写里面的方法,这里的@Injectable()注解中不用加providedIn,由于没有专业的测试模块,每一个测试用例中咱们使用provide进行注入。

@Injectable()
export class CollegeTestService extends CollegeService {
}

原来直接跑ng test特别快,根本看不清楚组件的建立,这两天发现了一个新套路,跑测试的时候上YouTube点开个视频看,而后电脑就特别卡,测试跑的时候就慢了。

而后就能够清楚地看到每一个测试用例的执行过程,看到每一个组件如何建立并显示。也不知道改了哪里,如今Alice跑测试的时候最后给出一个Karma的测试报告。

clipboard.png

直接把错误报出来,也好修改。

测试

测试最后怎么设计的呢?也说不明白,看代码就是了。最近才发现以前的测试用例写得都不正确。

其实一个测试,就是构建了一个测试的模块,该模块和其余模块都相同。

发现不少测试中为了能跑过,直接把公共组件或公共管道写在了declarations里,这是不合理的,虽然测试能跑过,可是理论上,这个测试就是测这个的,因此模块中的declarations只有它本身。

而后这里的imports也是通过反复的测试,导入BrowserAnimationsModuleHttpClientTestingModuleRouterTestingModuleShareModule这四个模块,这个测试的全部依赖就都有了,其余的什么都不要导入,看着混乱。

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();
    });
});

总结

最佳实践,都是从坑里爬出来后才总结出来的。

clipboard.png

clipboard.png

上次我感慨Angular架构设计难的时候是426日,当时只是对Alice进行小改,还不到一月,现在一次性对前台作了这么大的改动,坑也踩得多了,爬出坑后,最佳实践,其实就在眼前。

此次的架构设计得很整洁,打完包后也很快,我很满意。

clipboard.png

古人学问无遗力,少壮工夫老始成。
纸上得来终觉浅,绝知此事要躬行。
——陆游《冬夜读书示子聿》

之后再设计不能纸上谈兵,要努力去实践,经历得多了,最佳实践天然就出来了。

相关文章
相关标签/搜索