loading...

The React View Template Engine for Express

saltyshiomix profile image Shiono Yoshihide ・2 min read

TLDR

  • Pass the server data to the React client props
  • Because this is a view template engine, so results can be searchable by searching engines like Google (yes, we use server side rendering)

GitHub logo saltyshiomix / react-ssr

React SSR as a view template engine

Overview

  • SSR (Server Side Rendering) as a view template engine
  • Dynamic props
    • Passing the server data to the React client props
    • Suitable for
      • Admin Panels
      • Blogging
  • Developer Experience
    • Zero config of webpack and babel
    • HMR (Hot Module Replacement) both scripts and even if styles when process.env.NODE_ENV !== 'production'
    • Built-in Sass (SCSS) support

Pros and Cons

Pros

Because it is just a view template engine:

  • It doesn't need to have any APIs, all we have to do is to pass the server data to the client
  • It supports multiple engines like .hbs, .ejs and React .(ts|js)x
  • We can use passport authentication as it always is

Cons

  • It is not so performant, because it assembles the whole HTML on each request
  • It does not support client side routing

Usage

With @react-ssr/express

Install it:

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

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

Quick Start

Installation

$ npm install --save @react-ssr/express express react react-dom

Populate package.json

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

Write server.js

const express = require('@react-ssr/express');
const app = express();

app.get('/', (req, res) => {
  const user = { name: 'World' };
  res.render('index', { user });
});

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

Implement views/index.jsx

import React from 'react';

export default function Index(props) {
  return `Hello ${props.user.name}!`;
}

Run Server

$ npm start

You'll see Hello World!

Deep into Dive

1. Register jsx and tsx

source: register.ts

const ENGINE: 'jsx' | 'tsx' = getEngine();
app.engine(ENGINE, renderFile);
app.set('views', resolve(process.cwd(), viewsDir));
app.set('view engine', ENGINE);
app.use(express.static(distDir));

2. Render a File (Server Side Rendering)

source: render.tsx

import { renderToString } from 'react-dom/server';

let html: string = '<!DOCTYPE html>';

let Page = require(file); // `file` is a React function component
Page = Page.default || Page;

html += renderToString(
  <Html script={`${hash}.js`}>
    <Page {...props} />
  </Html>
);

return html;

3. Bundle Scripts and Write Output

source: render.tsx

import fs from 'fs';
import template from 'art-template';
import webpack from 'webpack';

const { ufs } = require('unionfs');
const MemoryFileSystem = require('memory-fs');
const template = require('art-template');

const cwd: string = process.cwd();

template.defaults.minimize = false;

const mfs = new MemoryFileSystem;
ufs.use(mfs).use(fs); // union memory-fs and fs!

// write file in the server memory
mfs.mkdirpSync(resolve(cwd, 'react-ssr-src'));
mfs.writeFileSync(resolve(cwd, `react-ssr-src/entry.jsx`), template(resolve(__dirname, '../page.jsx'), { props }));
mfs.writeFileSync(resolve(cwd, `react-ssr-src/page.jsx`), template(file, props));

// compile in the server memory!
const compiler: webpack.Compiler = webpack(configure(hash, ext, distDir));
compiler.inputFileSystem = ufs;
compiler.outputFileSystem = mfs;
compiler.run((err: any) => {
  if (err) {
    console.error(err.stack || err);
    if (err.details) {
      console.error(err.details);
    }
    return;
  }
});

// read the results from memory file system
// write the results to the real file system
await outputFileSync('result.js', mfs.readFileSync(cache).toString());

That's it!

Final output html is like this:

<!DOCTYPE html>
<html>
  <body>
    <div id="app">
      <p>Hello World!</p>
    </div>
    <script src="/c834ab9b47260a08d695f59ba1a5b24d.js"></script>
  </body>
</html>

Ending

But I love to use NEXT.js! lol

Posted on by:

Discussion

markdown guide
 

I am getting error at "Run Server" part.

" Cannot find module '@react-ssr/core/dist/document' "

Can't see any result in google either :(

 

Have you installed @react-ssr/core?

If you want to see full information, please check out GitHub README, not this post :)

 

Aaaah :(((( Sorry. I only installed @react-ssr/express. I thought it was a dependency and will install by itself. Now it is OK. Thank you for fast reply

No problem, the latest information is at GitHub readme :)

Formally it's true that @react-ssr/express includes @react-ssr/core, but now it is separated for many reasons.