Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am making Angular + NestJS app, and I want to send index.html file for all routes.

main.ts

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 {};
  }
}

It works fine while I open localhost:3000/, but if I open localhost:3000/some_route the server falls with 500 internal error and says Can not find html module. I was searching why I am getting this error and everyone says set default view engine like ejs or pug, but I don't want to use some engines, I just want to send plain html built by angular without hacking like res.sendFile('path_to_file'). Please help

like image 992
epsilon Avatar asked Feb 23 '19 04:02

epsilon


People also ask

How do I redirect in NestJS?

To set a static redirection for a GET request in Nestjs, we can use the @Redirect() decorator function from the @nestjs/common module and call it just above the Controller class's method that handles that GET request.

Is NestJS good for backend?

It is lightweight, simple, and open source. NestJS is a relatively new option in backend development, with many features for building and deploying enterprise services quickly and following the principles of SOLID and 12-factor applications.

Can I use NestJS with JavaScript?

Language. We're in love with TypeScript, but above all - we love Node.js. That's why Nest is compatible with both TypeScript and pure JavaScript. Nest takes advantage of the latest language features, so to use it with vanilla JavaScript we need a Babel compiler.

Does NestJS support TypeScript?

Nest. js uses TypeScript for type checking and provides an out-of-the-box software architecture for building and deploying testable, scalable, loosely coupled, and easily maintainable applications. In this article, we'll explore Nest. js and what you can build with it.


2 Answers

You can only use setBaseViewsDir and @Render() with a view engine like handlebars (hbs); for serving static files (Angular), however, you can only use useStaticAssets and response.sendFile.

To serve index.html from all other routes you have a couple of possibilities:

A) Middleware

You can create a middleware that does the redirect, see this article:

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

and then register the middleware for all routes:

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

B) Global Error Filter

You can redirect all NotFoundExceptions to your 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')));
  }
}

and then register it as a global filter in your main.ts:

app.useGlobalFilters(new NotFoundExceptionFilter());
like image 187
Kim Kern Avatar answered Nov 15 '22 00:11

Kim Kern


Updated Answer for December 10, 2019

You need to create middleware for sending the react index.html

Create middleware file

frontend.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'));
  }
}

Include middleware in

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

App Structure for Reference:

enter image description here

like image 33
Alan Avatar answered Nov 15 '22 00:11

Alan