Nest: how to run with next.js?

Created on 26 Sep 2018  路  9Comments  路  Source: nestjs/nest

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.

Minimal reproduction of the problem with instructions

import * as next from 'next';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const client = next({ dev });

async function bootstrap() {
  await client.prepare();
  const handle = client.getRequestHandler();

  const server = await NestFactory.create(AppModule);
  server.use(handle);
  server.listen(port);
}
// app.controller.ts
@Controller('/test')
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  root(): string {
    return this.appService.root();
  }
}
// app module
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService]
})
export class AppModule {}

// app.service
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  root() {
    return 'Hello world!';
  }
}

What is the motivation / use case for changing the behavior?

image

All requests are handled by next.js (SSR Framewrok) . I get a 404 error throw by next.js. when i go to localhost:3000/test. But this url is watched by my AppController, it should return the string hello world.

Environment


Nest version: X.Y.Z


For Tooling issues:
- Node version: XX  
- Platform:  

Others:

type

Most helpful comment

I ended up releasing a package called nest-next to make the integration easier to setup.

All 9 comments

Hey @xiaoyu-tamu ,

I'am not an expert but what i have seen is that you have to catch the request before handle it like the following code:

server.get('*', (req, res) => {
  handle(req, res)
})

@adrien2p Thanks for the help. I also tried this solution but it's not working as expected.

You also get a 404 ?

I use nextjs and nestjs too, my workaround is to run both server separately and proxy the request from nextjs server to nestjs controller

//server.js(nextjs render server)

const port = parseInt(process.env.PORT, 10) || 3000
const env = process.env.NODE_ENV
const dev = env !== 'production'
const app = next({
  dir: '.',
  dev
})

const handle = app.getRequestHandler()

app
  .prepare()
  .then(() => {
    const server = express()
    server.use(cookieParser());

    // ONLY DEV PURPOSE
    const devProxy = {
      '/your entry': {
        target: 'YOUR AWESOME API',
        changeOrigin: true
      }
    }

    if (devProxy) {
      const proxyMiddleware = require('http-proxy-middleware')
      Object.keys(devProxy).forEach(function (context) {
        server.use(proxyMiddleware(context, devProxy[context]))
      })
    }
    server.all('*', (req, res) => handle(req, res))

    server.listen(port, err => {
      if (err) {
        throw err
      }
      console.log(`> Ready on port ${port} [${env}]`)
    })
  })
  .catch(err => {
    console.log('An error occurred, unable to start the server')
    console.log(err)
  })

I've made a pretty basic example showing the two working together, I haven't written very much documentation around it, but the majority of the code is in the main.ts file and then the render module. https://github.com/kyle-mccarthy/nest-next-starter

Right now it works with the latest next and nest versions. I will try to update the documentation in the next could days to explain more about what is going on. In short, I bind a global middleware and filter provided by the render module. The middleware gets the req and res for nextjs and the filter handles any routes not resolved by a controller. This lets it pass through requests to the _next folder. The render module overrides the default express render implementation and passes it off to the render service, this allows for the @Render decorator to work.

I've made a pretty basic example showing the two working together, I haven't written very much documentation around it, but the majority of the code is in the main.ts file and then the render module. https://github.com/kyle-mccarthy/nest-next-starter

Right now it works with the latest next and nest versions. I will try to update the documentation in the next could days to explain more about what is going on. In short, I bind a global middleware and filter provided by the render module. The middleware gets the req and res for nextjs and the filter handles any routes not resolved by a controller. This lets it pass through requests to the _next folder. The render module overrides the default express render implementation and passes it off to the render service, this allows for the @Render decorator to work.

This works for successful responses. But if any nestjs controller throws an error, next always shows a 404. Do you know of a way to fix this?

I ended up releasing a package called nest-next to make the integration easier to setup.

I create a nestjs modlue named nest-next-module, welcome to using it. ;D

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tronginc picture tronginc  路  3Comments

JulianBiermann picture JulianBiermann  路  3Comments

yanshuf0 picture yanshuf0  路  3Comments

anyx picture anyx  路  3Comments

marshall007 picture marshall007  路  3Comments