6

I have a NestJS api that I want to use to also serve a frontend, from Angular. This is deployed onto heroku. By backend routes use the prefix '/api' and I want all other requests to respond with the index.html from my build Angular app.

My folder structure for the deployed app is:

-dist
  -client
    -index.html
    -.js files
  -server
    -main.js
    -other dirs/modules

I have tried all kinds of things so far and they have all worked locally. The problem is deploying to heroku. The closest I've gotten (with help from this article: https://medium.com/@bo.vandersteene/use-nest-as-your-server-side-application-with-an-angular-frontend-540b0365bfa3) is creating a frontend middleware in the NestJS app that looks at the request path and file extensions, then uses res.sendFile and path.resolve to create the filepath to respond with.

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

const allowedExtentions = [
  '.js',
  '.ico',
  '.css',
  '.png',
  '.jpg',
  '.woff2',
  '.woff',
  '.ttf',
  '.svg',
];

const prefix = apiPrefix;

@Injectable()
export class FrontendMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: () => void) {
    const { baseUrl } = req;
    if (baseUrl.indexOf(prefix) === 0) {
      next();
    } else if (
      allowedExtentions.filter(extention => baseUrl.indexOf(extention) > 0)
        .length > 0
    ) {
      res.sendFile(resolve(`./dist/client/${baseUrl}`));
    } else {
      res.sendFile(resolve('./dist/client/index.html'));
    }
  }
}

This works LOCALLY. When deploying to heroku, I get an error: [ExceptionsHandler] ENOENT: no such file or directory, stat '/app/dist/client/index.html' This doesn't make sense, though, because when logging into the Heroku bash for my project, I can see the exact file path and file. The file exists but for some reason, NestJS does not recognize it.

Any help would be appreciated.

1

1 Answer 1

4

What I've done with great success is in your main.ts file, add app.useStaticAssets('your/path/to/dist/client') and then at your GET / route you serve the index.html file. e.g.


@Injectable()
export class AppController {
  @Get()
  sendApplication(@Res() res) {
    res.sendFile('index.html');
  }
}

I should mention that this requires your angular app to be built using ng build --prod in the Heroku build stage or before the code makes it to Heroku.

Sign up to request clarification or add additional context in comments.

2 Comments

How can I use this during development? When using ng serve?
for development you should just do a res.redirect('http://localhost:4200/');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.