React Server Side Rendering (SSR)
Typescript
In our time it's easy to make react SSR using only Typescript.
Create directory
mkdir react-ssr-ts
cd react-ssr-ts
Init project
yarn init -y
echo "nodeLinker: node-modules" > .yarnrc.yml
touch yarn.lock
Dependencies
yarn add react react-dom typescript @types/react @types/react-dom
tsconfig.json
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true
},
"include": ["index.tsx"]
}
index.tsx
import * as React from 'react';
import { renderToString } from 'react-dom/server';
const App = () => <div>App</div>;
console.log(renderToString(<App />));
Run
tsc && node index
Result
<div>App</div>
Vyriy
Pure TypeScript is enough for a small SSR example, but for production SSR a bundler is usually safer.
The TypeScript compiler transpiles files, but it does not bundle or validate the full runtime dependency graph.
With a bundler you run the server from the same resolved module graph that was checked during build: ESM/CommonJS interop, JSX transform, package exports, aliases, side-effect imports and external dependencies are handled in one place.
It also gives you a predictable server artifact in dist, which is easier to test, deploy and compare in consumer tests.
The same we can make with Vyriy.
Create directory
mkdir react-ssr-vyriy
cd react-ssr-vyriy
Init project
yarn init -y
echo "nodeLinker: node-modules" > .yarnrc.yml
touch yarn.lock
Dependencies
yarn add react react-dom typescript @types/react @types/react-dom
yarn add @vyriy/webpack-config @vyriy/typescript-config webpack
tsconfig.json
{
"extends": "@vyriy/typescript-config/index.json",
"include": ["index.tsx"]
}
index.tsx
import { renderToString } from 'react-dom/server';
const App = () => <div>App</div>;
console.log(renderToString(<App />));
webpack.config.mjs
import 'webpack';
import { ssr } from '@vyriy/webpack-config';
export default ssr('./index.tsx', {
filename: 'index.js',
library: { type: 'commonjs2' },
clean: true,
});
Run
webpack && node dist
Result
<div>App</div>
So yes, the bundler version has more code and one more config file. But this extra code is not accidental ceremony: it moves important runtime decisions into the build step. For SSR this is worth it because server rendering fails late and often in places that TypeScript alone does not model: package resolution, module format interop, side effects, missing files and dependencies that behave differently after publish.
The result is a stronger contract.
If webpack builds the SSR entry, you know the server artifact can be executed from dist with the same dependency graph that your consumer or deployment will use.
That makes the example a little longer, but the production story simpler: build once, test the built file, deploy the built file.
This is where Vyriy helps: the library takes the complicated webpack and TypeScript choices into shared configuration.
The application keeps a small webpack.config.mjs, a normal TypeScript entry file and a plain webpack && node dist command.
So the coding and build process stays simple, calm and reliable, while the hard parts are still handled deliberately.