Introducing an Alternative to NEXT.js
Tags: react, javascript, nextjs, showdev
Published: 2019-12-16 21:43:13

---
title: Introducing an Alternative to NEXT.js
published: true
description: `react-ssr` is a React framework that enables us to make server side rendering Express apps easily. It may be the alternative to NEXT.js, The React SSR framework, you know.
tags: react,javascript,nextjs,showdev
cover_image: https://i.imgur.com/RtuijYA.png
---

## Introduction

When we develop React apps, it is one of the best choices to separate a server and a client.

But in those cases, we must implement so many APIs for the client in the server side.

On the other hand, a good old way to server render views like handlebars or ejs is not suitable for React single page apps or server side rendering apps.

Though it is not possible to use NEXT.js as a view template engine like from an Express server, but it is necessary a little tricky techniques like this:

```tsx
// pages/index.tsx

const IndexPage = ({ articles }) => {
  return (
    <ul>
      {articles.map((article, index) => (
        <li key={index}>{article.title}</li>
      ))}
    </ul>
  );
};

// we must use `getInitialProps()` to enable SSR correctly
IndexPage.getInitialProps = async ({ req, query }) => {
  const isServer = !!req;

  // and we have to check a process is a server or not
  let articles;
  if (isServer) {
    // if the server side, we can receive data from the server directly
    articles = query.articles;
  } else {
    // if the client side, we must fetch data from the API server
    articles = await http.get('api/articles');
  }

  // finally, we can use data in the `IndexPage` component like above
  return {
    articles,
  };
};
```

Have you ever thought of the implementation like this?

```js
// server.js

const express = require('express');

const app = express();

app.get('/', (req, res) => {
  const message = 'Hello World!';
  res.render('index', { message });
});

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

```jsx
// views/index.jsx

export default function IndexPage{ message }) {
  return <p>{message}</p>;
}
```

And if we could see 'Hello World' by SSR?

## Let's Imagine!

```js
// server.js

const posts = [
  { id: 1, body: 'This is a first post.' },
  { id: 2, body: 'This is a second post.' },
  { id: 3, body: 'This is a last post.' },
];

app.get('/', (req, res) => {
  res.render('index', { posts });
});

app.get('/posts/:postId', (req, res) => {
  const { postId } = req.params;
  const post = findById(postId);
  res.render('post', { post });
});
```

```jsx
// views/index.jsx

import React from 'react';

const IndexPage = ({ posts }) => {
  return (
    <React.Fragment>
      {posts.map((post, index) => {
        return (
          <p key={index}>
            <a href={'/posts/' + post.id}>{post.body}</a>
          </p>
        );
      })}
    </React.Fragment>
  );
};

export default IndexPage;
```

```jsx
// views/post.jsx

import React from 'react';

const PostPage = ({ post }) => {
  return (
    <React.Fragment>
      <p>{post.body}</p>
    </React.Fragment>
  );
};

export default PostPage;
```

Is it so easy enough, right?

And we can use React as if it was a view template engine!

## About `react-ssr`

{% github:https://github.com/saltyshiomix/react-ssr %}

### Overview

- Pass the server data to the React client `props`
  - So it reacts as if it is a view template engine
  - Off course, it is optimized for search engines by using server side rendering
- Developer Experience
  - It is so easy to use and there is almost nothing to learn the way to use
  - HMR (Hot Module Replacement) when `process.env !== 'production'`

## How to Use `react-ssr`

There are three npm packages for Express applications:

- [@react-ssr/core](https://npm.im/@react-ssr/core)
  - A core package for `@react-ssr/express` and `@react-ssr/nestjs-express`
- [@react-ssr/express](https://npm.im/@react-ssr/express)
  - A package for pure Express applications
- [@react-ssr/nestjs-express](https://npm.im/@react-ssr/nestjs-express)
  - A package for NestJS Express applications

### Usage of `@react-ssr/express` in JavaScript

Installation:

```zsh
$ npm install --save @react-ssr/core @react-ssr/express express react react-dom
```

In the `package.json`:

```json
{
  "scripts": {
    "start": "node server.js"
  }
}
```

And populate files below inside your project:

**`.babelrc`**:

```json
{
  "presets": [
    "@react-ssr/express/babel"
  ]
}
```

**`server.js`**:

```js
const express = require('express');
const register = require('@react-ssr/express/register');

const app = express();

(async () => {
  // register `.jsx` as a view template engine
  await register(app);

  app.get('/', (req, res) => {
    const message = 'Hello World!';
    res.render('index', { message });
  });

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

**views/index.jsx**:

```jsx
export default function IndexPage({ message }) {
  return <p>{message}</p>;
}
```

That's it!

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

### Usage of `@react-ssr/express` in TypeScript

To enable TypeScript engine (`.tsx`), just put `tsconfig.json` in your project root directory.

The codes of TypeScript will be like this:

**`package.json`**:

```json
{
  "scripts": {
    "start": "ts-node server.ts"
  }
}
```

**`server.ts`**:

```ts
import express, { Request, Response } from 'express';
import register from '@react-ssr/express/register';

const app = express();

(async () => {
  // register `.tsx` as a view template engine
  await register(app);

  app.get('/', (req: Request, res: Response) => {
    const message = 'Hello World!';
    res.render('index', { message });
  });

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

**`views/index.tsx`**:

```tsx
interface IndexPageProps {
  message: string;
}

export default function IndexPage({ message }: IndexPageProps) {
  return <p>{message}</p>;
}
```

### Usage of `@react-ssr/nestjs-express`

Installation:

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

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

In the `package.json`:

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

And then, populate files below inside your project:

**`.babelrc`**:

```json
{
  "presets": [
    "@react-ssr/nestjs-express/babel"
  ]
}
```

**`tsconfig.json`**:

```json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "preserve",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "strict": true,
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true
  },
  "exclude": [
    "node_modules",
    "ssr.config.js",
    ".ssr"
  ]
}
```

**`tsconfig.server.json`**:

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

**`server/main.ts`**:

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

(async () => {
  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`);
  });
})();
```

**`server/app.module.ts`**:

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

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

**`server/app.controller.ts`**:

```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 };
  }
}
```

Finally, **views/index.tsx**:

```tsx
interface IndexPageProps {
  user: any;
}

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

export default IndexPage;
```

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

## There Are Many Examples

- **@react-ssr/express**
  - `.jsx`
    - [examples/basic-jsx](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-jsx)
    - [examples/basic-custom-views](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-custom-views)
    - [examples/basic-custom-document](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-custom-document)
    - [examples/basic-dynamic-head](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-dynamic-head)
    - [examples/basic-hmr-css](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-hmr-css)
    - [examples/basic-hmr-scss](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-hmr-scss)
    - [examples/basic-blogging](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-blogging)
    - [examples/with-jsx-antd](https://github.com/saltyshiomix/react-ssr/tree/master/examples/with-jsx-antd)
    - [examples/with-jsx-bulma](https://github.com/saltyshiomix/react-ssr/tree/master/examples/with-jsx-bulma)
    - [examples/with-jsx-emotion](https://github.com/saltyshiomix/react-ssr/tree/master/examples/with-jsx-emotion)
    - [examples/with-jsx-material-ui](https://github.com/saltyshiomix/react-ssr/tree/master/examples/with-jsx-material-ui)
    - [examples/with-jsx-semantic-ui](https://github.com/saltyshiomix/react-ssr/tree/master/examples/with-jsx-semantic-ui)
    - [examples/with-jsx-styled-components](https://github.com/saltyshiomix/react-ssr/tree/master/examples/with-jsx-styled-components)
  - `.tsx`
    - [examples/basic-tsx](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-tsx)
- **@react-ssr/nestjs-express**
  - [examples/basic-nestjs](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-nestjs)
  - [examples/basic-nestjs-nodemon](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-nestjs-nodemon)
- **@react-ssr/static**
  - `.jsx`
    - [examples/basic-jsx-static](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-jsx-static)
    - [examples/with-jsx-static-bulma](https://github.com/saltyshiomix/react-ssr/tree/master/examples/with-jsx-static-bulma)
  - `.tsx`
    - [examples/basic-tsx-static](https://github.com/saltyshiomix/react-ssr/tree/master/examples/basic-tsx-static)

### `examples/with-jsx-antd`

![examples/with-jsx-antd](https://i.imgur.com/yWGxseM.png)

### `examples/with-jsx-emotion`

![examples/with-jsx-emotion](https://i.imgur.com/XN8evEM.png)

### `examples/with-jsx-material-ui`

![examples/with-jsx-material-ui](https://i.imgur.com/o1AWdyd.png)

### `examples/with-jsx-semantic-ui`

![examples/with-jsx-semantic-ui](https://i.imgur.com/0PwlfVk.png)

### `examples/with-jsx-styled-components`

![examples/with-jsx-styled-components](https://i.imgur.com/RtuijYA.png)

## Conclusion

Please try [react-ssr](https://github.com/saltyshiomix/react-ssr) and send us feedbacks!

Best,