簡體   English   中英

如何將所有路由重定向到 nest.js 中的 index.html (Angular)?

[英]How to redirect all routes to index.html (Angular) in nest.js?

我正在制作 Angular + NestJS 應用程序,我想為所有路由發送index.html文件。

主文件

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useStaticAssets(join(__dirname, '..', 'frontend', 'dist', 'my-app'));
  app.setBaseViewsDir(join(__dirname, '..', 'frontend', 'dist', 'my-app'));
  await app.listen(port);
}

app.controller.ts

@Controller('*')
export class AppController {

  @Get()
  @Render('index.html')
  root() {
    return {};
  }
}

當我打開localhost:3000/時它工作正常,但是如果我打開localhost:3000/some_route服務器會出現500 internal error並說Can not find html module 我在搜索為什么我會收到這個錯誤,每個人都說set default view engine like ejs or pug ,但我不想使用某些引擎,我只想發送由 angular 構建的純 html,而不像res.sendFile('path_to_file') 請幫忙

您只能將setBaseViewsDir@Render()與像把手 (hbs) 這樣的視圖引擎一起使用; 但是,對於提供靜態文件(Angular),您只能使用useStaticAssetsresponse.sendFile

要從所有其他路由提供index.html ,您有幾種可能性:

A) 中間件

您可以創建一個執行重定向的中間件,請參閱這篇文章

@Middleware()
export class FrontendMiddleware implements NestMiddleware {
  resolve(...args: any[]): ExpressMiddleware {
    return (req, res, next) => {
      res.sendFile(path.resolve('../frontend/dist/my-app/index.html')));
    };
  }
}

然后為所有路由注冊中間件:

export class ApplicationModule implements NestModule {
  configure(consumer: MiddlewaresConsumer): void {
    consumer.apply(FrontendMiddleware).forRoutes(
      {
        path: '/**', // For all routes
        method: RequestMethod.ALL, // For all methods
      },
    );
  }
}

B) 全局錯誤過濾器

您可以將所有NotFoundExceptions重定向到您的index.html

@Catch(NotFoundException)
export class NotFoundExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    response.sendFile(path.resolve('../frontend/dist/my-app/index.html')));
  }
}

然后將其注冊為main.ts的全局過濾器:

app.useGlobalFilters(new NotFoundExceptionFilter());

2019 年 12 月 10 日的更新答案

您需要創建中間件來發送 react index.html

創建中間件文件

前端.middleware.ts

import { NestMiddleware, Injectable } from '@nestjs/common';
import {Request, Response} from "express"
import { resolve } from 'path';

@Injectable()
export class FrontendMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: Function) {
    res.sendFile(resolve('../../react/build/index.html'));
  }
}

包括中間件

app.module.ts

import { FrontendMiddleware } from './frontend.middleware';
import {
  Module,
  MiddlewareConsumer,
  RequestMethod,
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {
  configure(frontEnd: MiddlewareConsumer) {
    frontEnd.apply(FrontendMiddleware).forRoutes({
      path: '/**', // For all routes
      method: RequestMethod.ALL, // For all methods
    });
  }
}

供參考的應用程序結構:

在此處輸入圖片說明

您還可以將 Cloud Functions for Firebase 與 Firebase 托管一起使用。 您在main.ts擁有的內容非常好,使用這種方法您甚至不需要控制器。 你應該按照以下步驟進行:

  1. index.html重命名為index2.html 這對於渲染您的路線路徑很重要,否則您將在所有路線上都能正常渲染,不包括根/
  2. 更新angular.json以具有以下"index": "apps/myapp/src/index2.html", (只需將index.html更改為index2.html )。 注意:你的 index.html 路徑可能不同,我使用的是Nx workspace
  3. 添加templatePath: join(BROWSER_DIR, 'index2.html'),到 NestJS 的ApplicationModule ,很可能你在服務器目錄中將該文件命名為app.module.ts

像這樣:

@Module({
  imports: [
    AngularUniversalModule.forRoot({
      bundle: require('./path/to/server/main'), // Bundle is created dynamically during build process.
      liveReload: true,
      templatePath: join(BROWSER_DIR, 'index2.html'),
      viewsPath: BROWSER_DIR
    })
  ]
})
  1. 初始化 Firebase Cloud Functions 和 Firebase Hosting,有關如何設置,您可以查看https://hackernoon.com/deploying-angular-universal-v6-with-firebase-c86381ddd445https://blog.angularindepth.com/angular -5-universal-firebase-4c85a7d00862

  2. 編輯您的firebase.json

它應該看起來像那樣,或者至少是hosting部分。

{
  "hosting": {
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "public": "functions/dist/apps/path/to/browser",
    "rewrites": [
      {
        "function": "angularUniversalFunction",
        "source": "**"
      }
    ]
  }
} 
  1. main.ts 中,您需要在服務器上設置 Cloud Functions。

在簡約的情況下,它會像這樣:

import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';

admin.initializeApp(); // Initialize Firebase SDK.
const expressApp: Express = express(); // Create Express instance.

// Create and init NestJS application based on Express instance.
(async () => {
  const nestApp = await NestFactory.create<NestExpressApplication>(
    ApplicationModule,
    new ExpressAdapter(expressApp)
  );
  nestApp.init();
})().catch(err => console.error(err));

// Firebase Cloud Function for Server Side Rendering (SSR).
exports.angularUniversalFunction = functions.https.onRequest(expressApp);

使用這種方法,您不必關心 NestJS 端的路由。 您可以在 Angular 端設置所有內容,僅此而已。 Angular 負責路由。 您可能已經注意到這是服務器端渲染 (SSR),但是可以結合使用 NestJS + Cloud Functions for Firebase 將所有路由重定向到index.html (或更准確地說index2.html )。 另外你有一個“免費”的 SSR :)

展示項目:

1) Angular + Angular Universal (SSR) + Cloud Functions for Firebase: https : //github.com/Ismaestro/angular8-example-app (缺少 NestJS)。

2) Angular + NestJS: https : //github.com/kamilmysliwiec/universal-nest (缺少 Firebase 的雲函數)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM