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)
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
- Passing the server data to the React client
- 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
Top comments (6)
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.
register.ts in point 1 is broken
const app = express();
^
TypeError: express is not a function
Why is it like this?????