本文作为自己学习Angular的记录文,意在之后的用途中回顾所学的知识。目标是打造一个通过angular-cli生成的demo应用,汇集Module,Component,Service,模板语法,生命周期,组件间的交互,指令,管道,动画,Rxjs,国际化(i18n),懒加载,ssr(服务端渲染)等知识点的一个示例应用。

angular-cli

  • 安装angular-cli

    1
    npm install -g @angular/cli
  • 认识angular-cli
    安装版本:@6.1.3
    运行代码下述命令可查看帮助:

    1
    ng --help

常用命令有如下,也可以在每个命令下加上 –help查看帮助

  1. ng new 新建
  2. ng generate 生成文件
  3. ng build 构建
  4. ng serve 运行服务
  5. ng help 帮助
  • 初始化文件:
    1
    ng new demo --routing --style=sass --skip-tests

生成了一个带有路由模块,样式为sass(也可不带或者less),跳过测试文件的demo目录,所有初始安装包均已install。详细配置可查看ng new –help

  • 开启服务
    1
    ng serve

详细配置可查看ng serve –help 例如–aot 开启aot编译(开发阶段常用jit编译,生产阶段常用aot编译)–host 监听的端口号等。

  • 生成组件
    1
    2
    ng generate component home
    ng g c home

生成了一个home的组件,generate可简写为g,component可简写为c,这样就生成了

  1. home.component.html
  2. home.component.sass
  3. home.component.ts

三个文件(如果之前没有通过配置项设置为内联引用的话)。

路由

在之前生成的app-routing.module.ts路由模块中添加如下代码:

1
2
3
4
5
6
import { HomeComponent } from './home/home.component';
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', component: HomeComponent },
];

定义了home路由的模块组件已经空路由的重定向以及未匹配到路由的组件。注意:

1
2
3
4
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})

自能有一个根路由,其他的子路由用forChild,还需要把RouterModule模块导出,由app.module模块导入才能正常使用路由系统。
在app.component.html页面中:

1
<router-outlet></router-outlet>

定义路由位置,只后匹配的路由组件会在该定义的下方展示

懒加载

一般为了首屏加载时间缩短会把其他路由定义为懒加载,angular中定义懒加载的方式也非常简单,但是也很强大,不仅能完成懒加载的任务,同时可以通过配置的方式实现守卫(在进入该路由前先检验权限),预加载等等。

1
2
ng generate module lazy
ng generate component lazy

通过命令生成lazy模块和lazy组件,另外再为lazy模块添加路由组件lazy-routing.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LazyComponent } from './lazy.component';

const routes: Routes = [
{
path: '',
component: LazyComponent,
}
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class LazyRoutingModule { }

最后在lazy的module中导入该路由模块,这样一个异步加载的模块就完成了。

服务端渲染

为什么要服务端渲染在这里就不多说了,这里主要关注的点在怎么实现服务端的渲染以及客户端渲染的切换(TODO 能通过webpack直接配置而不走angular-cli吗?)

通过下列步骤达到的效果:页面初始化时,走一遍服务器渲染,页面会很快的显示出来,但是一些点击事件是没有办法触发的,然后等待客户端的渲染,重新渲染一次根模块(会重新走根组件的构造函数),然后页面就是一个整正的客户端程序,完成切换。

  • 安装依赖
    1
    npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader @nguniversal/express-engine
  1. @angular/platform-server - Universal 的服务端元件。

  2. @nguniversal/module-map-ngfactory-loader - 用于处理服务端渲染环境下的惰性加载。

  3. @nguniversal/express-engine - Universal 应用的 Express 引擎。

  4. ts-loader - 用于对服务端应用进行转译。

  • 在app.module.ts中导入BrowserModule模块

    1
    BrowserModule.withServerTransition({ appId: 'tour-of-heroes' }),
  • 增加src/app/app.server.module.ts
    这个模块是服务端渲染的入口模块代码地址

  • 增加src/main.server.ts
    这是应用服务器入口点,需要在稍后的angular.json配置中用到

    1
    export { AppServerModule } from './app/app.server.module';
  • server.ts
    这是express框架的web服务器,理论上可以用任何的框架,只要它能调用 Universal 的 renderModuleFactory (TODO 这个用Koa测试一下)代码地址

  • 配置
  1. src/tsconfig.server.json
  2. webpack.server.config.js
  3. angular.json

最后在package.json中的scripts增加如下行:

1
2
3
4
"build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server",
"serve:ssr": "node dist/server",
"build:client-and-server-bundles": "ng build --prod && ng run angular.io-example:server",
"webpack:server": "webpack --config webpack.server.config.js --progress --colors"

  • 运行
    1
    2
    npm run build:ssr
    npm run serve:ssr

分别执行构建和启动服务器命令,完成!

总结

基本案例参考官网的步骤,也算是完成了效果,也由此引发了几点思考,在今后补充答案:

  1. 什么时候由服务端渲染切换成客户端渲染?
  2. 能不能不通过angular-cli的方式加载服务端渲染?
  3. 服务端的渲染能不能选择一些模块进行渲染,比如说只渲染首页的路由?
  4. 怎么用其他web服务器开启服务端渲染?比如说koa。。。