Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation on how to serve static files #402

Closed
osolliec opened this issue Feb 7, 2018 · 23 comments
Closed

Add documentation on how to serve static files #402

osolliec opened this issue Feb 7, 2018 · 23 comments

Comments

@osolliec
Copy link

osolliec commented Feb 7, 2018

I'm submitting a...


[ ] Regression 
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

The documentation is very well written and very useful; however I think an example of serving a static file would be a huge plus.

I'm trying to serve an Angular App bundled with a NestJS backend, and see no clear way to do that. An example serving a static html file would help a lot.

@kamilmysliwiec
Copy link
Member

kamilmysliwiec commented Feb 11, 2018

Hi @testos944,
Actually, it's in the docs already, take a look here: https://docs.nestjs.com/techniques/mvc. Let me know if you would have any questions 🙂

@osolliec
Copy link
Author

Well, not if you don't want to use a view engine but serve only a plain html file :)

But I guess I can juste use res.sendfile('public/index.html'), I will try this out.

@kamilmysliwiec
Copy link
Member

Yes, that's true. I'll provide a small example without any engine soon 🙂

@osolliec
Copy link
Author

osolliec commented Feb 18, 2018

For anyone wondering :

import * as express from 'express';
app.use(express.static(path.join(__dirname, 'public')));

If you put your index.html file in the public folder, it should be good to go

@osolliec
Copy link
Author

osolliec commented Feb 18, 2018

@kamilmysliwiec, is there any way to have a global catch all route ? I want to catch all routes (except those defined in my modules/controllers), something like that in expressjs:

app.get('*', function(req, res){
  res.redirect('/');
});

@ovidiup13
Copy link

ovidiup13 commented May 13, 2018

If you're interested in serving static files, here's a nice way to do it with fastify and fastify-static. This solution assumes that your static files are in the root of the project, in the folder dist/public. Then, add the following lines to:

main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule, new FastifyAdapter());

  app.useStaticAssets({
    root: path.resolve(__dirname + "../dist/public")
  });
...
}

app.controller.ts

  @Get()
  root(@Res() res) {
    res.sendFile("index.html");
  }

This will serve your main index.html as well as any other assets on the root path "/".

@Cspeisman
Copy link

@kamilmysliwiec if you're still working on examples I would love to see an example where nestjs serves both static files and json responses depending on the route. I would love to serve both my react app and the json needed from the server!

@natqe
Copy link

natqe commented Jun 19, 2018

@Cspeisman here is an example (in src/main.ts)

import { join } from 'path'
import { renderFile } from 'ejs'
import { NestFactory } from '@nestjs/core'
import { AppModule } from './app.module'

(async () => {

  const app = await NestFactory.create(AppModule)

  app.
    engine('html', renderFile).
    setBaseViewsDir(join(__dirname, '../views')).
    useStaticAssets(join(__dirname, '../views/public'), {
      index: false,
      redirect: false
    })

  await app.listen(process.env.PORT || 3000)

})()

and in app.controller you render the file like so:

import { Get, Controller, Render } from '@nestjs/common'
import { AppService } from './app.service'

@Controller()
export class AppController {

  constructor(private readonly appService: AppService) { }

  @Get()
  @Render('public/index.html')
  root(): Promise<object> {
    return this.appService.root()
  }

}

@calebeaires
Copy link

@ovidiup13 Your solution is great, works on dev mode, (localhost:8080), but does not when I need to run it on a aws server.

I have checked everthing: port, firewall and others, but nestjs does not load an index.html file

@ovidiup13
Copy link

@calebeaires hmm... That's weird. It depends on how you configured to access the service on aws. Have you tried with other routes to return, for example, JSON?

@hernanS
Copy link

hernanS commented Aug 1, 2018

@Cspeisman
it is my first time leaving a question so, let me explain:
I recently started to work with Nest framewor, Until now I have couldn't do a good render. I have this:

main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);

app.
engine('html', renderFile).
setBaseViewsDir(join(__dirname, '../views')).
useStaticAssets(join(__dirname, '../views/public'), {
index: false,
redirect: false,
});
await app.listen(3000);
}

app.controller
@controller()
export class AppController {
constructor(private readonly appService: AppService) {}

@get()
@Render('public/clients1.html')
root() {
return this.appService.root();
}
}

export class AppService {
root() {
}
}

What should go in appService?

@natqe
Copy link

natqe commented Aug 4, 2018

@Cspeisman object with all the data you want to put into the view using ejs template rendering.
if u not want to render any data u not need to return anything in the controller, i think.

@jsdevtom
Copy link

jsdevtom commented Jan 1, 2019

This answer explains how by using an exception filter, a wild card can be achieved: https://stackoverflow.com/questions/49879274/nestjs-default-wildcard-route/49917487#49917487

@rilexus
Copy link

rilexus commented Jan 6, 2019

If you're interested in serving static files, here's a nice way to do it with fastify and fastify-static. This solution assumes that your static files are in the root of the project, in the folder dist/public. Then, add the following lines to:

main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule, new FastifyAdapter());

  app.useStaticAssets({
    root: path.resolve(__dirname + "../dist/public")
  });
...
}

app.controller.ts

  @Get()
  root(@Res() res) {
    res.sendFile("index.html");
  }

This will serve your main index.html as well as any other assets on the root path "/".

And if you create an ExeptionFilter and add it to the app.module.ts all paths will return index.html. You just need to take care of the routing on the client(React, Angular, etc)

`import {ArgumentsHost, Catch, ExceptionFilter, NotFoundException} from "@nestjs/common";
@catch(NotFoundException)
export class NotFoundExceptionFilter implements ExceptionFilter {

catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    response.sendFile("index.html");
}

}`

@CanKattwinkel
Copy link

CanKattwinkel commented Mar 6, 2019

Edit: As you can find in the comment below for Nest 6 and newer HTTP_SERVER_REF is no longer exported. Solution: #402 (comment)

I recently came to the same situation where I needed to serve an SPA (React) from within a NestJS application that also served an express legacy application.

But I did not wanted to loose the 404 on false API requests, luckily all my API requests were prefixed with api. Therefore I extended rilexus solution:

redirect-client.filter.ts

import {ArgumentsHost, Catch, HttpServer, Inject, NotFoundException} from '@nestjs/common';
import {BaseExceptionFilter, HTTP_SERVER_REF} from '@nestjs/core';
import {resolve} from 'path';

@Catch(NotFoundException)
export class AllExceptionsFilter extends BaseExceptionFilter {
    constructor(@Inject(HTTP_SERVER_REF) applicationRef: HttpServer) {
        super(applicationRef);
    }

    catch(exception: any, host: ArgumentsHost) {
        const ctx = host.switchToHttp();
        const response = ctx.getResponse();
        const req = ctx.getRequest();
        
        if (req.path && req.path.startsWith('/api')) {
            // API 404, serve default nest 404:
            super.catch(exception, host);
        } else {
            // client access, let the SPA handle:
            response.sendFile(resolve(__dirname, '../../client/build/index.html'));
        }
    }
}

main.ts

async function bootstrap() {

    const app = await NestFactory.create(AppModule);

    app.useStaticAssets(join(__dirname, '../../client/build/'));

    const httpRef = app.get(HTTP_SERVER_REF);
    app.useGlobalFilters(new AllExceptionsFilter(httpRef));
    ...
}

@jesben
Copy link

jesben commented Apr 22, 2019

@CanKattwinkel I really want to use your example but nestjs/core "has no exported member 'HTTP_SERVER_REF'.

Do you have a solution for this?

Nest.js version: 6.1.1

@BrunnerLivio
Copy link
Member

BrunnerLivio commented Apr 22, 2019

@jesben I think that got changed from v5 to v6. I guess we should mention that in the docs

const app = await NestFactory.create(AppModule);
const refHost = app.get(HttpAdapterHost);
const httpServer = refHost.httpAdapter.getHttpServer();

Related
- docs
- @nestjs/terminus production code

@Luxcium
Copy link

Luxcium commented Jul 21, 2019

what is the Typescript Type of res (where to import Response from) in :

  @Get('*')
  public reactApp(@Res() res: Response): any {
    res.sendFile('index.html');
  }

@webberwang
Copy link
Contributor

what is the Typescript Type of res (where to import Response from) in :

  @Get('*')
  public reactApp(@Res() res: Response): any {
    res.sendFile('index.html');
  }

import { Response } from 'express';

@jdottori
Copy link

Hello, I am new to Nest, but I think that you are looking to serve a SPA application (Angular or similar). I am setting up something similar with this example:
https://docs.nestjs.com/recipes/serve-static

@ncbtart
Copy link

ncbtart commented Sep 5, 2019

Hello, i want to share images but the router redirect me everytime on an index file :'(

@Module({
imports: [
    PrismaModule,
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '..', 'public'),
      serveStaticOptions: {
        index: false,
      },
    }),
]

If you have any suggestions :)

@DzmitryU
Copy link

@ncbtart You could use app.useStaticAssets and NestFastifyApplication if it's possible. That helped me to serve my static assets, stylings, images and js files

@lock
Copy link

lock bot commented Dec 14, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Dec 14, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests