@xxx-ssr/nestjs-express
TypeScript icon, indicating that this package has built-in type declarations

0.12.4 • Public • Published

😎 @xxx-ssr/nestjs-express 😎

Overview

  • SSR (Server Side Rendering) as a view template engine
  • Passing the server data to the client props
  • Dynamic props without caring about SSR
    • Suitable for dynamic routes like blogging
  • Dynamic Head component
  • HMR when process.env.NODE_ENV !== 'production'

Usage

Install it:

# install NestJS dependencies
$ npm install --save @nestjs/core @nestjs/common @nestjs/platform-express

# install @xxx-ssr/nestjs-express
$ npm install --save @xxx-ssr/nestjs-express react react-dom

And add a script to your package.json like this:

{
	"scripts": {
		"start": "ts-node --project tsconfig.server.json server/main.ts"
	}
}

Populate files below inside your project:

./.babelrc

{
	"presets": ["@xxx-ssr/nestjs-express/babel"]
}

./tsconfig.json

{
	"compilerOptions": {
		"target": "esnext",
		"module": "esnext",
		"moduleResolution": "node",
		"jsx": "preserve",
		"lib": ["dom", "dom.iterable", "esnext"],
		"strict": true,
		"allowJs": true,
		"skipLibCheck": true,
		"esModuleInterop": true,
		"isolatedModules": true,
		"resolveJsonModule": true,
		"emitDecoratorMetadata": true,
		"experimentalDecorators": true
	},
	"exclude": ["node_modules", ".ssr"]
}

./tsconfig.server.json

{
	"extends": "./tsconfig.json",
	"compilerOptions": {
		"module": "commonjs"
	},
	"include": ["server"]
}

./server/main.ts

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import register from '@xxx-ssr/nestjs-express/register';
import { AppModule } from './app.module';

async function bootstrap() {
	const app = await NestFactory.create<NestExpressApplication>(AppModule);

	// register `.tsx` as a view template engine
	await register(app);

	app.listen(3000, async () => {
		console.log(`> Ready on http://localhost:3000`);
	});
}

bootstrap();

./server/app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';

@Module({
	controllers: [AppController]
})
export class AppModule {}

./server/app.controller.ts

import { Controller, Get, Render } from '@nestjs/common';

@Controller()
export class AppController {
	@Get()
	@Render('index') // this will render `views/index.tsx`
	public showHome() {
		const user = { name: 'NestJS' };
		return { user };
	}
}

./views/index.tsx

interface IndexProps {
	user: any;
}

const Index = ({ user }: IndexProps) => {
	return <p>Hello {user.name}!</p>;
};

export default Index;

Then just run npm start and go to http://localhost:3000, you'll see Hello NestJS!.

Configuration (ssr.config.js)

Here is the default ssr.config.js, which is used by xxx-ssr when there are no valid values:

module.exports = {
	id: 'default',
	distDir: '.ssr',
	viewsDir: 'views',
	dynamicViews: [],
	webpack: (
		config /* webpack.Configuration */,
		env /* 'development' | 'production' */
	) => {
		return config;
	}
};

ssr.config.js#id

The id of UI framework. (default: default)

It can be ignored only when the project does not use any UI frameworks.

Supported UI frameworks are:

For example, if we want to use emotion, ssr.config.js is like this:

module.exports = {
	id: 'emotion'
};

ssr.config.js#distDir

The place where xxx-ssr generates production results. (default: .ssr)

If we use TypeScript or any other library which must be compiled, the config below may be useful:

module.exports = {
	// dist folder should be ignored by `.gitignore`
	distDir: 'dist/.ssr'
};

ssr.config.js#viewsDir

The place where we put views. (default: views)

A function res.render('xxx') will render views/xxx.jsx or views/xxx.tsx.

A working example is here:

ssr.config.js#dynamicViews

If specified, xxx-ssr won't generate html cache when production.

This is suitable for search-engine-optimized dynamic routes like blogging:

module.exports = {
	dynamicViews: [
		// this means `views/posts.jsx` is a dynamic view
		'posts'
	]
};

A working example is here:

ssr.config.js#webpack()

module.exports = {
	webpack: (
		config /* webpack.Configuration */,
		env /* 'development' | 'production' */
	) => {
		// we can override default webpack config here
		return config;
	}
};

Custom Document

Just put _document.tsx into the views root:

./views/_document.tsx

import React from 'react';
import { Document, Head, Main } from '@xxx-ssr/nestjs-express';

export default class extends Document {
	render() {
		return (
			<html>
				<Head>
					<title>Default Title</title>
				</Head>
				<body>
					<Main />
				</body>
			</html>
		);
	}
}

Note: Please put <Main /> component directly under <body> tag AND don't wrap <Main /> component with another components because this is a hydration target for the client.

And then, use it as always:

./views/index.tsx

const Index = props => {
	return <p>Hello Layout!</p>;
};

export default Index;

Dynamic Head

We can use the Head component anyware:

./views/index.tsx

import React from 'react';
import { Head } from '@xxx-ssr/nestjs-express';

const Index = props => {
	return (
		<React.Fragment>
			<Head>
				<title>Dynamic Title</title>
				<meta name="description" content="Dynamic Description" />
			</Head>
			<p>Of course, SSR Ready!</p>
		</React.Fragment>
	);
};

export default Index;

Supported UI Framework

Non CSS-in-JS framework

Like semantic-ui, non CSS-in-JS frameworks are supported without extra configuration.

All we have to do is to load global CSS in _document or each page:

./views/_document.tsx

import React from 'react';
import { Document, Head, Main } from '@xxx-ssr/express';

export default class extends Document {
	render() {
		return (
			<html>
				<Head>
					<title>A Sample of Semantic UI React</title>
					<link
						rel="stylesheet"
						href="//cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css"
					/>
				</Head>
				<body>
					<Main />
				</body>
			</html>
		);
	}
}

With Emotion

In order to enable SSR, we must install these packages:

And then, populate .babelrc in your project root:

{
	"presets": ["@xxx-ssr/express/babel"],
	"plugins": ["emotion"]
}

With styled-components

In order to enable SSR, we must install babel-plugin-styled-components as devDependencies.

And then, populate .babelrc in your project root:

{
	"presets": ["@xxx-ssr/nestjs-express/babel"],
	"plugins": ["styled-components"]
}

With Material UI

We can use material-ui without extra configuration.

With Ant Design

In order to enable SSR, we must install babel-plugin-import as devDependencies.

And then, populate .babelrc in your project root:

{
	"presets": ["@xxx-ssr/nestjs-express/babel"],
	"plugins": [
		[
			"import",
			{
				"libraryName": "antd",
				"style": "css"
			}
		]
	]
}

Package Sidebar

Install

npm i @xxx-ssr/nestjs-express

Weekly Downloads

0

Version

0.12.4

License

MIT

Unpacked Size

11.4 kB

Total Files

8

Last publish

Collaborators

  • zan