This project is mainly borrowed from https://github.com/kyle-mccarthy/nest-next, But there are other optimizations
Next-Adapter provides a nestjs module to integrate next.js into a nest.js application, it allows the rendering of next.js pages via nestjs controllers and providing initial props to the page as well
Import the RenderModule into your application's root module and call the forRootAsync method.
import { Module } from '@nestjs/common';
import { NextAdapterModule } from '@towerlight/nest-next-adapter';
@Module({
imports: [
NextAdapterModule.forRoot({
nextServerOption: {
customServer: true,
conf: {},
dev: true,
dir: resolve(__dirname, '../forum'),
},
rendererOptions: {
viewsDir: '',
dev: true,
},
}),
],
...
})
export class AppModule {
}
Also, you can use useFactory to set up dynamic configuration
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { NextAdapterModule } from '@towerlight/nest-next-adapter';
@Module({
imports: [
ConfigModule.forRoot({
// ...
}),
NextAdapterModule.forRoot({
nextServerOption: {
customServer: true,
conf: {},
dev: !configService.get<boolean>('production'),
dir: resolve(
__dirname,
configService.get<boolean>('production')
? '../forum'
: '../../../apps/forum'
),
},
rendererOptions: {
viewsDir: '',
dev: !configService.get<boolean>('production'),
},
}),
],
...
})
export class AppModule {
}
The RenderModule accepts configuration
export interface NextAdapterModuleOptions {
nextServerOption: ServerConstructor;
rendererOptions: Partial<RendererConfig>;
}
export declare type ServerConstructor = {
/**
* Where the Next project is located - @default '.'
*/
dir?: string;
/**
* Hide error messages containing server information - @default false
*/
quiet?: boolean;
/**
* Object what you would use in next.config.js - @default {}
*/
conf?: NextConfig;
dev?: boolean;
customServer?: boolean;
};
export interface RendererConfig {
/**
* The viewsDir option determines the folder inside of pages to render from. By default the value is /views
* but this can be changed or set to null or '' to render from the root of pages.
*/
viewsDir: null | string;
/**
* By default the dev mode will be set to true unless the option is overwritten.
* Currently the dev mode determines how the errors should be serialized before being sent to next.
*/
dev: boolean;
}
The NextAdapterModule
overrides the Express/Fastify render. To render a page
in your controller import the Render decorator from @nestjs/common
and add
it to the method that will render the page. The path for the page is relative
to the /pages
directory.
import {
Controller,
Get,
Render,
} from '@nestjs/common';
@Controller()
export class AppController {
@Get()
@Render('Index')
public index() {
// initial props
return {
title: 'Next with Nest',
};
}
}
Additionally, the render function is made available on the res object.
@Controller()
export class AppController {
@Get()
public index(@Res() res: RenderableResponse) {
res.render('Index', {
title: 'Next with Nest',
});
}
}
The render function takes in the view, as well as the initial props passed to the page.
render = (view: string, initialProps?: any) => any
The initial props sent to the next.js view page can be accessed from the context's query method inside the getInitialProps method.
import { NextPage, NextPageContext } from 'next'
// The component's props type
type PageProps = {
title: string
}
// extending the default next context type
type PageContext = NextPageContext & {
query: PageProps
}
// react component
const Page: NextPage<PageProps> = ({ title }) => {
return (
<div>
<h1>{ title } < /h1>
< /div>
)
}
// assigning the initial props to the component's props
export async function getServerSideProps(context) {
if (context.req) {
return {
props: {
...context.query
}
}
}
return {
props: { title: 'from client' }, // will be passed to the page component as props
}
}
export default Page
Because the back-end project will be restarted after it is code changed, and at the same time next.js It will also compile again, which will waste a lot of time.
Here, we use hot reload , and ensure that the next.js is a singleton which always exists.