全面分析一下前端框架Angular的来龙去脉,分析angular的技术要点和难点,以及详细的语法和使用规则,底层原理-小白进阶之路

Angular 前端框架全面分析

Angular 是一个由 Google 维护的开源前端框架。它最早在 2010 年发布,最初版本称为 AngularJS。2016 年,团队发布了一个完全重写的版本,称为 Angular 2,之后的版本(如 Angular 4、Angular 5 等)都统称为 Angular。

一、历史背景

1. AngularJS(Angular 1.x)

  • 发布年份:2010
  • 特点:基于 MVC(Model-View-Controller)架构,使用双向数据绑定和依赖注入。
  • 限制:性能瓶颈、可维护性差、学习曲线陡峭。

2. Angular 2+

  • 发布年份:2016
  • 特点:完全重写,采用基于组件的架构,使用 TypeScript 开发,提升了性能和可维护性。
  • 发展:从 Angular 2 开始,Angular 团队每半年发布一个大版本,当前最新版本为 Angular 15。

二、技术要点

1. TypeScript

Angular 使用 TypeScript 编写,提供了静态类型检查、现代 JavaScript 特性等优点,有助于提高代码质量和开发效率。

2. 组件化

采用组件式开发,将应用程序分割成独立的、可复用的组件,每个组件包含自己的模板、样式和逻辑。

3. 模块化

使用 NgModule 来组织代码,一个 NgModule 可以包含组件、指令、管道和服务等,提供了良好的模块化支持。

4. 依赖注入

Angular 提供了强大的依赖注入机制,简化了服务的创建和管理,提高了代码的可测试性和可维护性。

5. 模板语法

Angular 使用直观的模板语法来定义组件的视图,支持数据绑定、指令和事件绑定等。

6. 路由

Angular 内置强大的路由模块,可以轻松地定义应用程序的导航和页面切换。

7. 表单处理

提供了两种表单处理方式:模板驱动表单和响应式表单,满足不同需求。

8. RxJS

Angular 大量使用 RxJS(Reactive Extensions for JavaScript)来处理异步数据流,非常适合复杂的数据交互场景。

三、技术难点

1. 学习曲线

由于 Angular 涉及的概念较多(如依赖注入、RxJS、TypeScript 等),学习曲线相对较陡。

2. 性能优化

理解和应用 Angular 的变更检测机制和 Zone.js 是性能优化的关键,需要一定的深入学习。

3. 复杂项目管理

随着项目规模的扩大,如何有效地管理模块、组件、服务等也是一个挑战。

四、详细语法和使用规则

1. 组件

import { Component } from '@angular/core';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent {title = 'my-angular-app';
}

2. 模块

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';import { AppComponent } from './app.component';@NgModule({declarations: [AppComponent],imports: [BrowserModule],providers: [],bootstrap: [AppComponent]
})
export class AppModule { }

3. 数据绑定

  • 插值绑定{{ expression }}
  • 属性绑定[property]="expression"
  • 事件绑定(event)="handler"
  • 双向绑定[(ngModel)]="property"

4. 指令

  • 结构型指令*ngIf, *ngFor
  • 属性型指令[ngClass], [ngStyle]

5. 服务和依赖注入

import { Injectable } from '@angular/core';@Injectable({providedIn: 'root',
})
export class DataService {getData() {return ['data1', 'data2', 'data3'];}
}

6. 路由

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent }```typescript
import { AboutComponent } from './about/about.component';const routes: Routes = [{ path: '', component: HomeComponent },{ path: 'about', component: AboutComponent }
];@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]
})
export class AppRoutingModule { }

7. 模板驱动表单

<form #form="ngForm" (ngSubmit)="onSubmit(form)"><input type="text" name="username" ngModel required><button type="submit">Submit</button>
</form>

8. 响应式表单

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';@Component({selector: 'app-form',templateUrl: './form.component.html'
})
export class FormComponent implements OnInit {form: FormGroup;constructor(private fb: FormBuilder) { }ngOnInit() {this.form = this.fb.group({username: ['', Validators.required]});}onSubmit() {console.log(this.form.value);}
}
<form [formGroup]="form" (ngSubmit)="onSubmit()"><input formControlName="username"><button type="submit">Submit</button>
</form>

五、底层原理

1. 变更检测机制

Angular 使用 Zone.js 来捕获异步操作,然后触发变更检测机制来更新视图。变更检测机制的核心是脏值检测策略,Angular 会对比数据的当前值和之前的值,决定是否重新渲染视图。

2. 依赖注入机制

Angular 的依赖注入机制基于提供者(Provider)和注入器(Injector)。每个服务、组件等都可以声明依赖项,Angular 会根据依赖关系图自动注入所需的依赖。

3. 编译过程

Angular 的编译过程分为 AOT(Ahead-of-Time)和 JIT(Just-in-Time)两种模式:

  • AOT 编译:在构建时进行编译,生成优化后的 JavaScript 代码,减少应用运行时的开销,提高性能。
  • JIT 编译:在浏览器中运行时进行编译,适合开发阶段使用。

4. 渲染机制

Angular 使用虚拟 DOM 进行渲染优化,类似于 React。通过虚拟 DOM,Angular 可以高效地计算出需要更新的部分,减少直接操作真实 DOM 的次数,从而提高性能。

5. 模块化

Angular 的模块系统通过 NgModule 实现。每个 NgModule 都有自己的执行环境,可以包含组件、指令、管道和服务等。模块化设计有助于代码分离和按需加载,提高了应用的可维护性和性能。

六、模块化

Angular 是一个功能强大且全面的前端框架,适用于大规模、复杂的 Web 应用开发。它采用 TypeScript 进行开发,提供了丰富的工具和功能(如依赖注入、变更检测、模块化、路由等),尽管学习曲线较陡,但在大型项目中表现出色。掌握 Angular 的核心概念和原理,能够帮助开发者构建高性能、高可维护性的 Web 应用。
当然,下面是关于 Angular 的更多详细信息,包括一些高级特性、最佳实践以及常见的开发模式。

七、高级特性

1. 懒加载(Lazy Loading)

懒加载是 Angular 中提高性能的重要特性。通过懒加载,可以按需加载模块而不是在应用启动时加载所有模块。

const routes: Routes = [{ path: 'home', component: HomeComponent },{ path: 'about', loadChildren: () => import('./about/about.module').then(m => m.AboutModule) }
];

2. Angular CLI

Angular CLI 是一个强大的命令行工具,用于初始化、开发、构建和维护 Angular 应用程序。

# 安装 Angular CLI
npm install -g @angular/cli# 创建新项目
ng new my-angular-app# 启动开发服务器
ng serve# 生成组件、服务等
ng generate component my-component

3. 国际化(i18n)

Angular 提供了内置的国际化支持,可以轻松地将应用程序本地化到多种语言。

import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';registerLocaleData(localeFr, 'fr');

4. 动态组件加载

在运行时动态加载和渲染组件是 Angular 的一个高级特性,适用于需要根据用户交互动态生成内容的场景。

import { Component, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core';@Component({selector: 'app-dynamic-loader',template: `<ng-container #container></ng-container>`
})
export class DynamicLoaderComponent {@ViewChild('container', { read: ViewContainerRef, static: true }) container: ViewContainerRef;constructor(private resolver: ComponentFactoryResolver) { }loadComponent(component: any) {const factory = this.resolver.resolveComponentFactory(component);this.container.clear();this.container.createComponent(factory);}
}

5. 服务端渲染(SSR)

使用 Angular Universal 可以实现服务端渲染,从而提高应用的 SEO 和首屏加载速度。

# 安装 Angular Universal
ng add @nguniversal/express-engine# 构建和运行 SSR 应用
npm run build:ssr
npm run serve:ssr

八、最佳实践

1. 代码组织

  • 模块化设计:将应用分为多个功能模块,每个模块负责特定功能。
  • 组件化设计:尽量将界面划分为独立的组件,提升可复用性。
  • 服务层:将业务逻辑和数据访问层抽象为服务,组件只负责视图逻辑。

2. 性能优化

  • 使用懒加载:按需加载模块,减少首屏加载时间。
  • 避免不必要的变更检测:使用 OnPush 变更检测策略,减少不必要的视图更新。
  • 异步操作:尽量使用异步操作,如 async 管道、PromiseObservable

3. 代码规范

  • 使用 TypeScript:充分利用 TypeScript 的静态类型检查,提升代码质量。
  • 遵循 Angular 风格指南:遵循官方提供的风格指南,保持代码一致性和可维护性。
  • 单元测试和端到端测试:编写单元测试和端到端测试,确保代码的正确性和稳定性。

九、常见开发模式

1. 智能组件和哑组件

  • 智能组件:负责处理业务逻辑和与服务的交互。
  • 哑组件:只负责展示数据和处理简单的用户交互。
// 智能组件
@Component({selector: 'app-smart',template: `<app-dumb [data]="data" (event)="handleEvent($event)"></app-dumb>`
})
export class SmartComponent {data = this.dataService.getData();constructor(private dataService: DataService) { }handleEvent(event: any) { /* 处理事件 */ }
}// 哑组件
@Component({selector: 'app-dumb',template: `<div *ngFor="let item of data">{{ item }}</div>`
})
export class DumbComponent {@Input() data: any[];@Output() event = new EventEmitter<any>();
}

2. 状态管理

对于复杂的应用,可以采用状态管理库(如 NgRx)来管理应用状态当然,接下来我会详细介绍 Angular 的状态管理、单元测试、与其他技术的集成,以及一些高级调试技巧。

十、状态管理

1. NgRx

NgRx 是 Angular 中常用的状态管理库,基于 Redux 架构,提供了单一状态树、不可变状态、纯函数 reducer 等特点。

安装 NgRx
ng add @ngrx/store
ng add @ngrx/effects
状态定义

定义状态接口和初始状态:

// state.ts
export interface AppState {count: number;
}export const initialState: AppState = {count: 0,
};
Actions

定义 actions:

// actions.ts
import { createAction, props } from '@ngrx/store';export const increment = createAction('[Counter] Increment');
export const decrement = createAction('[Counter] Decrement');
export const reset = createAction('[Counter] Reset', props<{ count: number }>());
Reducer

定义 reducer:

// reducer.ts
import { createReducer, on } from '@ngrx/store';
import { increment, decrement, reset } from './actions';
import { AppState, initialState } from './state';const _counterReducer = createReducer(initialState,on(increment, state => ({ ...state, count: state.count + 1 })),on(decrement, state => ({ ...state, count: state.count - 1 })),on(reset, (state, { count }) => ({ ...state, count }))
);export function counterReducer(state: AppState | undefined, action: Action) {return _counterReducer(state, action);
}
Store Module

在应用模块中引入 Store 模块:

import { StoreModule } from '@ngrx/store';
import { counterReducer } from './reducer';@NgModule({imports: [StoreModule.forRoot({ count: counterReducer }),],
})
export class AppModule { }
使用 Store

在组件中使用 Store:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from './state';
import { increment, decrement, reset } from './actions';@Component({selector: 'app-counter',template: `<div>Count: {{ count$ | async }}</div><button (click)="increment()">Increment</button><button (click)="decrement()">Decrement</button><button (click)="reset(0)">Reset</button>`
})
export class CounterComponent {count$ = this.store.select(state => state.count);constructor(private store: Store<AppState>) {}increment() {this.store.dispatch(increment());}decrement() {this.store.dispatch(decrement());}reset(value: number) {this.store.dispatch(reset({ count: value }));}
}

2. Akita

Akita 是另一种用于 Angular 的状态管理库,提供了灵活的状态管理方式,适合大型应用。

安装 Akita
ng add @datorama/akita
定义 Store
import { Store, StoreConfig } from '@datorama/akita';export interface AppState {count: number;
}export function createInitialState(): AppState {return {count: 0,};
}@StoreConfig({ name: 'app' })
export class AppStore extends Store<AppState> {constructor() {super(createInitialState());}
}
使用 Store
import { Component } from '@angular/core';
import { AppStore } from './app.store';@Component({selector: 'app-counter',template: `<div>Count: {{ count$ | async }}</div><button (click)="increment()">Increment</button><button (click)="decrement()">Decrement</button><button (click)="reset()">Reset</button>`
})
export class CounterComponent {count$ = this.appStore.select(state => state.count);constructor(private appStore: AppStore) {}increment() {this.appStore.update(state => ({ count: state.count + 1 }));}decrement() {this.appStore.update(state => ({ count: state.count - 1 }));}reset() {this.appStore.reset();}
}

十一、单元测试

Angular 提供了强大的单元测试支持,使用 Karma 和 Jasmine 进行测试。

1. 设置测试环境

Angular CLI 自动生成的项目已经配置好了 Karma 和 Jasmine,无需额外配置。

2. 编写测试当然,我将继续深入探讨 Angular 的单元测试、与其他技术的集成、以及一些高级调试技巧。

十一、单元测试(继续)

2. 编写测试

组件测试

使用 TestBed 创建组件并进行测试:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CounterComponent } from './counter.component';describe('CounterComponent', () => {let component: CounterComponent;let fixture: ComponentFixture<CounterComponent>;beforeEach(async () => {await TestBed.configureTestingModule({declarations: [ CounterComponent ]}).compileComponents();});beforeEach(() => {fixture = TestBed.createComponent(CounterComponent);component = fixture.componentInstance;fixture.detectChanges();});it('should create', () => {expect(component).toBeTruthy();});it('should increment count', () => {component.increment();expect(component.count).toBe(1);});it('should decrement count', () => {component.decrement();expect(component.count).toBe(-1);});it('should reset count', () => {component.reset(0);expect(component.count).toBe(0);});
});
服务测试

测试服务时,使用 TestBed 配置提供者:

import { TestBed } from '@angular/core/testing';
import { DataService } from './data.service';describe('DataService', () => {let service: DataService;beforeEach(() => {TestBed.configureTestingModule({});service = TestBed.inject(DataService);});it('should be created', () => {expect(service).toBeTruthy();});it('should get data', () => {const data = service.getData();expect(data).toEqual(['item1', 'item2']);});
});

3. 运行测试

使用 Angular CLI 运行测试:

ng test

十二、与其他技术的集成

1. 与后端 API 的集成

使用 Angular 的 HttpClient 模块来与后端 API 进行通信。

安装 HttpClient 模块
import { HttpClientModule } from '@angular/common/http';@NgModule({imports: [ HttpClientModule ],
})
export class AppModule { }
创建服务
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';@Injectable({providedIn: 'root',
})
export class ApiService {constructor(private http: HttpClient) {}getData(): Observable<any> {return this.http.get('https://api.example.com/data');}postData(data: any): Observable<any> {return this.http.post('https://api.example.com/data', data);}
}
使用服务
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';@Component({selector: 'app-data',template: `<div *ngFor="let item of data">{{ item }}</div>`,
})
export class DataComponent implements OnInit {data: any;constructor(private apiService: ApiService) {}ngOnInit() {this.apiService.getData().subscribe(data => this.data = data);}
}

2. 与第三方库的集成

Angular 可以轻松集成第三方库,如 RxJS、Lodash 等。

使用 RxJS
import { of } from 'rxjs';
import { map } from 'rxjs/operators';const observable = of(1, 2, 3).pipe(map(x => x * 2)
);observable.subscribe(value => console.log(value)); // 输出 2, 4, 6
使用 Lodash
import * as _ from 'lodash';const array = [1, 2, 3, 4];
const doubled = _.map(array, x => x * 2);
console.log(doubled); // 输出 [2, 4, 6, 8]

当然,我将继续介绍更多关于 Angular 的内容,包括高级调试技巧、动画、表单处理、以及一些常见的开发工具和资源。

十三、高级调试技巧(继续)

2. 使用 Debug 模式

启用 Debug 模式

在开发过程中,可以启用 Angular 的 Debug 模式,以便在控制台中查看详细的调试信息。

import { enableProdMode } from '@angular/core';if (environment.production) {enableProdMode();
} else {// 开发模式下启用调试信息import('zone.js/plugins/zone-error');  // Included with Angular CLI.
}

3. Angular 调试工具

使用 ng.probe

在浏览器控制台中,可以使用 ng.probe 方法来访问组件实例和调试信息。

// 获取组件实例
const component = ng.probe(document.querySelector('app-root')).componentInstance;
console.log(component);
使用 Augury

Augury 是一个用于调试 Angular 应用的 Chrome 扩展,提供组件树、依赖注入、路由等信息的可视化展示。

安装 Augury
  • 在 Chrome 浏览器中,访问 Augury 页面并安装扩展。
使用 Augury
  • 打开 Chrome 开发者工具,切换到 Augury 标签,可以查看组件树、依赖关系等信息。

十四、动画

Angular 提供了强大的动画支持,通过 Angular Animations 模块可以实现复杂的动画效果。

1. 安装 Angular Animations

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';@NgModule({imports: [BrowserAnimationsModule],
})
export class AppModule {}

2. 定义动画

使用 triggerstatestyletransitionanimate 来定义动画。

import { trigger, state, style, transition, animate } from '@angular/animations';@Component({selector: 'app-animated',template: `<div [@fadeInOut]="'in'">Fade In Out Animation</div><button (click)="toggleState()">Toggle State</button>`,animations: [trigger('fadeInOut', [state('in', style({ opacity: 1 })),transition(':enter', [style({ opacity: 0 }),animate(600)]),transition(':leave', [animate(600, style({ opacity: 0 }))])])]
})
export class AnimatedComponent {state = 'in';toggleState() {this.state = this.state === 'in' ? 'out' : 'in';}
}

十五、表单处理

Angular 提供了两种表单处理方式:模板驱动表单和响应式表单。

1. 模板驱动表单

模板驱动表单使用 Angular 的指令和模板语法来处理表单。

import { FormsModule } from '@angular/forms';@NgModule({imports: [FormsModule],
})
export class AppModule {}
<!-- template-driven-form.component.html -->
<form #form="ngForm" (ngSubmit)="onSubmit(form)"><label for="name">Name:</label><input type="text" id="name" name="name" ngModel><button type="submit">Submit</button>
</form>
// template-driven-form.component.ts
import { Component } from '@angular/core';@Component({selector: 'app-template-driven-form',templateUrl: './template-driven-form.component.html'
})
export class TemplateDrivenFormComponent {onSubmit(form: any) {console.log('Form Data:', form.value);}
}

2. 响应式表单

响应式表单使用 FormBuilderFormGroup 来处理表单。

import { ReactiveFormsModule, FormBuilder, FormGroup } from '@angular/forms';@NgModule({imports: [ReactiveFormsModule],
})
export class AppModule {}
<!-- reactive-form.component.html -->
<form [formGroup]="form" (ngSubmit)="onSubmit()"><label for="name">Name:</label><input type="text" id="name" formControlName="name"><button type="submit">Submit</button>
</form>
// reactive-form.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';@Component({selector: 'app-reactive-form',templateUrl: './react### 2. **响应式表单**响应式表单使用 `FormBuilder``FormGroup` 来处理表单。#### 创建表单```typescript
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';@Component({selector: 'app-reactive-form',templateUrl: './reactive-form.component.html'
})
export class ReactiveFormComponent implements OnInit {form: FormGroup;constructor(private fb: FormBuilder) {}ngOnInit() {this.form = this.fb.group({name: ['', Validators.required],email: ['', [Validators.required, Validators.email]],password: ['', [Validators.required, Validators.minLength(6)]]});}onSubmit() {if (this.form.valid) {console.log('Form Data:', this.form.value);} else {console.log('Form is invalid');}}
}
表单模板
<form [formGroup]="form" (ngSubmit)="onSubmit()"><div><label for="name">Name:</label><input type="text" id="name" formControlName="name"><div *ngIf="form.get('name').invalid && form.get('name').touched">Name is required</div></div><div><label for="email">Email:</label><input type="email" id="email" formControlName="email"><div *ngIf="form.get('email').invalid && form.get('email').touched">Enter a valid email</div></div><div><label for="password">Password:</label><input type="password" id="password" formControlName="password"><div *ngIf="form.get('password').invalid && form.get('password').touched">Password must be at least 6 characters long</div></div><button type="submit">Submit</button>
</form>

十六、路由

Angular 的路由模块允许你在应用中定义导航路径。

1. 设置路由

配置路由
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';const routes: Routes = [{ path: '', component: HomeComponent },{ path: 'about', component: AboutComponent }
];@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]
})
export class AppRoutingModule { }
导航链接
<nav><a routerLink="/">Home</a><a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>

2. 路由守卫

路由守卫用于保护路由,确保用户具有访问权限。

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';@Injectable({providedIn: 'root'
})
export class AuthGuard implements CanActivate {constructor(private authService: AuthService, private router: Router) {}canActivate(next: ActivatedRouteSnapshot,state: RouterStateSnapshot): boolean {if (this.authService.isLoggedIn()) {return true;} else {this.router.navigate(['/login']);return false;}}
}
使用路由守卫
const routes: Routes = [{ path: '', component: HomeComponent },{ path: 'about', component: AboutComponent, canActivate: [AuthGuard] }
];

十七、国际化

Angular 提供了内置的国际化支持,用于多语言应用程序。

1. 准备翻译文件

创建翻译文件 messages.xlf

<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2"><file source-language="en" datatype="plaintext" original="ng2.template"><body><trans-unit id="homeTitle" datatype="html"><source>Home</source><target>Accueil</target></当然,我将继续介绍更多关于 Angular 的内容,包括国际化的详细步骤、服务端渲染、以及一些常用的开发工具和资源。## 十七、国际化(继续)### 1. **准备翻译文件**创建翻译文件 `messages.xlf`:```xml
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2"><file source-language="en" datatype="plaintext" original="ng2.template"><body><trans-unit id="homeTitle" datatype="html"><source>Home</source><target>Accueil</target></trans-unit><trans-unit id="aboutTitle" datatype="html"><source>About</source><target>À propos</target></trans-unit></body></file>
</xliff>

2. 配置 Angular

angular.json 中添加国际化配置:

{"$schema": "./node_modules/@angular/cli/lib/config/schema.json","projects": {"your-project-name": {"i18n": {"sourceLocale": "en","locales": {"fr": "src/locale/messages.fr.xlf"}},...}}
}

3. 标记可翻译文本

使用 Angular 内置的 i18n 属性标记可翻译的文本:

<h1 i18n="homeTitle">Home</h1>
<p i18n="aboutTitle">About</p>

4. 构建多语言版本

使用 Angular CLI 构建多语言版本:

ng build --localize

十八、服务端渲染(SSR)

Angular Universal 是一个用于实现 Angular 应用服务端渲染的库。

1. 安装 Angular Universal

ng add @nguniversal/express-engine

2. 更新应用模块

更新 app.server.module.ts 以适配服务端渲染:

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';@NgModule({imports: [AppModule,ServerModule],bootstrap: [AppComponent]
})
export class AppServerModule {}

3. 更新服务器文件

配置 server.ts 文件以启动 Express 服务器:

import 'zone.js/node';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { APP_BASE_HREF } from '@angular/common';
import { existsSync } from 'fs';import { AppServerModule } from './src/main.server';// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {const server = express();const distFolder = join(process.cwd(), 'dist/your-project-name/browser');const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';server.engine('html', ngExpressEngine({bootstrap: AppServerModule,}));server.set('view engine', 'html');server.set('views', distFolder);// Serve static files from /browserserver.get('*.*', express.static(distFolder, {maxAge: '1y'}));// All regular routes use the Universal engineserver.get('*', (req, res) => {res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });});return server;
}function run(): void {const port = process.env.PORT || 4000;// Start up the Node serverconst server = app();server.listen(port, () => {console.log(`Node Express server listening on http://localhost:${port}`);});
}// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
declare const __non_webpack_require__: NodeRequire;const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {run();
}export * from './src/main.server';

4. 运行 SSR

使用 Angular CLI 构建和运行 SSR 应用:

npm run build:ssr
npm run serve:ssr

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/858362.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是CSS原子化?

CSS原子化&#xff0c;也被称为功能性CSS或工具类CSS&#xff0c;是一种构建样式表的方法&#xff0c;它将传统CSS中的“多属性-多值”类转变为“单属性-单值”的类。这种方法最主要的特点是提高了样式的可复用性和模块化程度。 CSS原子化的详细说明&#xff1a; 结构和命名 …

【LocalAI】(13):LocalAI最新版本支持Stable diffusion 3,20亿参数图像更加细腻了,可以继续研究下

最新版本v2.17.1 https://github.com/mudler/LocalAI/releases Stable diffusion 3 You can use Stable diffusion 3 by installing the model in the gallery (stable-diffusion-3-medium) or by placing this YAML file in the model folder: Stable Diffusion 3 Medium 正…

PriorityQueue详解(含动画演示)

目录 PriorityQueue详解1、PriorityQueue简介2、PriorityQueue继承体系3、PriorityQueue数据结构PriorityQueue类属性注释完全二叉树、大顶堆、小顶堆的概念☆PriorityQueue是如何利用数组存储小顶堆的&#xff1f;☆利用数组存储完全二叉树的好处&#xff1f; 4、PriorityQueu…

python json反序列化为对象

在Python中&#xff0c;将JSON数据反序列化为对象通常意味着将JSON格式的字符串转换为一个Python的数据结构&#xff08;如列表、字典&#xff09;或者一个自定义的类实例。虽然Python的标准库json模块不提供直接将JSON数据映射到类的实例的功能&#xff0c;但我们可以通过一些…

React AntDesign Layout组件布局刷新页面错乱闪动

大家最近在使用React AntDesign Layout组件布局后刷新页面时&#xff0c;页面布局错乱闪动 经过组件属性的研究才发现&#xff0c;设置 hasSider 为 true 就能解决上面的问题&#xff0c;耽搁了半天的时间&#xff0c;接着踩坑接着加油&#xff01;&#xff01;&#xff01; …

pytorch实现的面部表情识别

一、绪论 1.1 研究背景 面部表情识别 (Facial Expression Recognition ) 在日常工作和生活中&#xff0c;人们情感的表达方式主要有&#xff1a;语言、声音、肢体行为&#xff08;如手势&#xff09;、以及面部表情等。在这些行为方式中&#xff0c;面部表情所携带的表达人类…

QT/QMessageBox/QTimerEvent/使用定时器制作一个闹钟

1.使用定时器制作一个闹钟 代码&#xff1a; widget.cpp: #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), speecher(new QTextToSpeech(this))//给语音对象申请空间 {ui->setup…

SQL找出所有员工当前薪水salary情况

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 有一个薪水表…

Debian Linux安装minikubekubectl

minikube&kubectl minkube用于在本地开发环境中快速搭建一个单节点的Kubernetes集群,还有k3s&#xff0c;k3d&#xff0c;kind都是轻量级的k8skubectl是使用K8s API 与K8s集群的控制面进行通信的命令行工具 这里使用Debian Linux演示&#xff0c;其他系统安装见官网,首先…

红队内网攻防渗透:内网渗透之内网对抗:横向移动篇Kerberos委派安全RBCD资源Operators组成员HTLMRelay结合

基于资源的约束委派(RBCD)是在Windows Server 2012中新加入的功能,与传统的约束委派相比,它不再需要域管理员权限去设置相关属性。RBCD把设置委派的权限赋予了机器自身,既机器自己可以决定谁可以被委派来控制我。也就是说机器自身可以直接在自己账户上配置msDS-AllowedToAct…

使用SpringCache实现Redis缓存

目录 一 什么是Spring Cache 二 Spring Cache 各注解作用 ①EnableCaching ②Cacheable ③CachePut ④CacheEvict 三实现步骤 ①导入spring cache依赖和Redis依赖 ②配置Redis连接信息 ③在启动类上加上开启spring cache的注解 ④ 在对应的方法上加上需要的注解 一 什么…

green bamboo snake

green bamboo snake 【竹叶青蛇】 为什么写这个呢&#xff0c;因为回县城听说邻居有人被蛇咬伤&#xff0c;虽然不足以危及生命&#xff0c;严重的送去市里了。 1&#xff09;这种经常都是一动不动&#xff0c;会躲在草地、菜地的菜叶里面、果树上、有时候会到民房大厅休息&a…

什么是网络安全

标题&#xff1a;《网络安全&#xff1a;守护我们的数字世界》 在这个数字时代&#xff0c;网络已经成为了我们生活中不可或缺的一部分。我们用网络进行社交、购物、学习、工作等各种活动。然而&#xff0c;网络世界并非完全安全&#xff0c;网络安全威胁日益增加&#xff0c;…

Qt——系统

目录 概述 事件 鼠标事件 进入、离开事件 按下事件 释放事件 双击事件 移动事件 滚轮事件 按键事件 单个按键 组合按键 定时器 QTimerEvent QTimer 窗口事件 文件 输入输出设备 文件读写类 文件和目录信息类 多线程 常用API 线程安全 互斥锁 条件变量…

python列表常见去重方法

列表去重在python实际运用中&#xff0c;十分常见&#xff0c;也是最基础的重点知识。 1. 使用for循环实现列表去重 此方法去重后&#xff0c;原顺序保持不变。 # for循环实现列表去重 list1 [a, 4, 6, 4, b, hello, hello, world, 9, 9, 4, a] list2 [] for l1 in list1:…

光纤传感器十大品牌

十大光纤传感器品牌-光纤光栅传感器厂家哪家好-Maigoo品牌榜

Blazor js和c#互操作

c# 操作js 定义js变量 <img id"blazor_logo" />await js.InvokeVoidAsync("eval", "myimage document.getElementById(blazor_logo)"); js 操作c#

【chatgpt】train_split_test的random_state

在使用train_test_split函数划分数据集时&#xff0c;random_state参数用于控制随机数生成器的种子&#xff0c;以确保划分结果的可重复性。这样&#xff0c;无论你运行多少次代码&#xff0c;只要使用相同的random_state值&#xff0c;得到的训练集和测试集划分就会是一样的。…

导入别人的net文件报红问题sdk

1. 使用cmd命令 dotnet --info 查看自己使用的SDK版本 2.直接找到项目中的 global.json 文件&#xff0c;右键打开&#xff0c;直接修改版本为本机的SDK版本&#xff0c;就可以用了

使用Flink CDC实时监控MySQL数据库变更

在现代数据架构中&#xff0c;实时数据处理变得越来越重要。Flink CDC&#xff08;Change Data Capture&#xff09;是一种强大的工具&#xff0c;可以帮助我们实时捕获数据库的变更&#xff0c;并进行处理。本文将介绍如何使用Flink CDC从MySQL数据库中读取变更数据&#xff0…