尽可能简化 Angular+NestJS 的单体环境设置
考虑到之前我发表的关于Angular+NestJS+OpenAPI(Swagger)的帖子,我曾思考如何将微服务纳入到这个环境中。我一直觉得NestJS和Angular的协作部分不太理想,但现在我找到了解决方案,所以我尝试以简单的单仓库结构重新构建了它。
条件
-
- Node.jsインストール済み
-
- Angular CLIインストール済み
- NestJSインストール済み
各种版本 (gè ɡ
$ node -v
v12.19.0
$ ng --version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 10.2.0
Node: 12.19.0
OS: linux x64
Angular:
...
Ivy Workspace:
Package Version
------------------------------------------------------
@angular-devkit/architect 0.1002.0 (cli-only)
@angular-devkit/core 10.2.0 (cli-only)
@angular-devkit/schematics 10.2.0 (cli-only)
@schematics/angular 10.2.0 (cli-only)
@schematics/update 0.1002.0 (cli-only)
$ nest --version
7.5.1
环境建设
创建Lerna项目
Lerna是一个用于管理单一存储库的工具。
虽然没有它也没问题,但它可以对服务器和客户端项目进行批量构建和npm安装,非常方便。
# プロジェクトのディレクトリを作成して移動
mkdir mono-nestjs-angular && cd mono-nestjs-angular
# Lernaプロジェクトとして初期化
npx lerna init
使用NestJS生成模板
# 各プロジェクトはlerna initで生成されるpackagesディレクトリの下に作成する
cd packages
nest new server
Angular的模板生成
ng new client --style=scss --routing=true
设定API端的前缀
为了区分API调用和静态文件的访问,需要设置API的URL前缀以/api开头。具体步骤请参考此处。
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// APIのURLが/apiとなるようにプレフィクスを設定
app.setGlobalPrefix('api');
await app.listen(3000);
}
bootstrap();
将Angular页面配置为静态文件返回。
这次我想做的是在这里。
我会参考参考文件并添加静态文件的配置。
npx lerna add @nestjs/serve-static --scope=server
# もしくは
cd server && npm install --save @nestjs/serve-static
在模块中导入ServeStaticModule。以下是此时的重点。
-
- rootPathはAngularの出力ディレクトリと一致するようにします
Angularの出力ディレクトリはpackages/client/angular-cli.jsonのoutputPathに書いてあります
excludeにて上記で設定したプレフィクスを指定してAPIコール時は参照しないようにします
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
@Module({
imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, '../../client/', 'dist/client'),
exclude: ['/api'],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
添加构建和启动脚本
在项目的根目录下,通过lerna init生成的package.json文件中添加启动命令。
{
"name": "root",
"private": true,
"scripts": {
"start": "lerna run start --scope=server --stream",
"build": "lerna run build --stream"
},
"devDependencies": {
"lerna": "^3.16.1"
}
}
-
- lerna runコマンドはプロジェクト内のpackage.jsonにあるscriptsで定義されたコマンドを一括実行します
startに関してはサーバーのみ実行するため、–scopeオプションでパッケージを指定する
–streamオプションはログ出力するためのオプションです。これがないとサーバー起動してもログが出てきません。
确认操作
请在项目根目录下执行以下命令。
开动
npm install
npm run build
npm start
确认图像
访问 http://localhost:3000
你看,Angular页面正常显示出来了。
确认应用程序接口
我将尝试访问http://localhost:3000/api。
API可以调用,对吗?
能否在子目录中直接输入URL进行跳转的补充说明。
对于SPA而言,它只是通过JavaScript在index.html页面上进行页面转换,即使在URL中指定了子目录,实际上并不存在该子目录下的index.html文件,因此如果只是简单地发布静态文件,当直接在URL中输入或通过子目录按下F5刷新时,会导致404错误。
(一般情况下,复制index.html并创建404.html来应对这个问题是常见的做法吗?)
据这个页面上的注意事项,@nestjs/serve-static似乎可以很巧妙地处理这些问题,所以我想试一试。
顺便提一下,在之前写的Angular + NestJS + OpenAPI (Swagger)的环境中考虑到微服务,我们将app.use(regx, express.static(path))设置为始终返回index.html。
添加组件
添加Page1Component和Page2Component组件。
import { Component } from '@angular/core';
@Component({
selector: 'app-page1',
template: `
<h1>{{title}}</h1>
<a routerLink="/page2">to page2</a>
`
})
export class Page1Component {
title = 'page1';
}
※Page2Component只是把page1的部分替换成了page2的部分。
将添加的组件在module的声明中进行指定,以便能够引用。
・・・
import { Page1Component } from './pages/page1.component';
import { Page2Component } from './pages/page2.component';
@NgModule({
declarations: [
AppComponent,
Page1Component,
Page2Component,
],
・・・
进行路由设置
・・・
import { Page1Component } from './pages/page1.component';
import { Page2Component } from './pages/page2.component';
const routes: Routes = [
{ path: 'page1', component: Page1Component },
{ path: 'page2', component: Page2Component },
];
・・・
展示画面
访问 http://localhost:3000/page1
正确地显示出来了。
(Page1Component的内容已在底部输出)
页面已成功切换到Page2Component中(URL也已变成/page2了)。
总结
我可以很容易地将NestJS和Angular进行协作,比以前写的文章简单多了。毕竟NestJS受到了Angular的启发,与SPA相兼容,真是太棒了^^
我已将此次制作的内容推送到GitHub上
https://github.com/teracy55/mono-nestjs-angular