Programming, error messages and sample code
How to publish a ReactJS Vite SSR to your hosting account
Programming, error messages and sample code > Node.js
1. Create a React project using Vite
npm create vite@latestEnter your project name (this sample uses vite-project) and press Enter. Use the arrow keys (↑ or ↓) to choose the React framework and press Enter. Select the TypeScript variant and press Enter. Navigate to the project folder, install the dependencies, and run the development server:
cd vite-project npm install npm run devThe project will run at http://localhost:5173/ by default. Update your pages, apply changes, and verify that everything works. Press Ctrl+C to stop the server.
2. Add Server-Side Rendering (SSR) support to your React project
Install the Express, compression and sirv packages:cd vite-project npm install express compression sirvOpen index.html in the project root. Add <!--app-head--> immediately after the <title> tag, and replace the contents of the <body> tag with the following:
<div id="app"><!--app-html--></div> <script type="module" src="/src/entry-client.tsx"></script>index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<!--app-head-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/entry-client.tsx"></script>
</body>
</html>
Create a server.js file in the project root and add the following code:
import fs from 'node:fs/promises'
import express from 'express'
// Constants
const isProduction = process.env.NODE_ENV === 'production'
const port = process.env.PORT || 5173
const base = process.env.BASE || '/'
// Cached production assets
const templateHtml = isProduction
? await fs.readFile('./dist/client/index.html', 'utf-8')
: ''
// Create http server
const app = express()
// Add Vite or respective production middlewares
/** @type {import('vite').ViteDevServer | undefined} */
let vite
if (!isProduction) {
const { createServer } = await import('vite')
vite = await createServer({
server: { middlewareMode: true },
appType: 'custom',
base,
})
app.use(vite.middlewares)
} else {
const compression = (await import('compression')).default
const sirv = (await import('sirv')).default
app.use(compression())
app.use(base, sirv('./dist/client', { extensions: [] }))
}
// Serve HTML
app.use('*all', async (req, res) => {
try {
const url = req.originalUrl.replace(base, '')
/** @type {string} */
let template
/** @type {import('./src/entry-server.js').render} */
let render
if (!isProduction) {
// Always read fresh template in development
template = await fs.readFile('./index.html', 'utf-8')
template = await vite.transformIndexHtml(url, template)
render = (await vite.ssrLoadModule('/src/entry-server.tsx')).render
} else {
template = templateHtml
render = (await import('./dist/server/entry-server.js')).render
}
const rendered = await render(url)
const html = template
.replace(`<!--app-head-->`, rendered.head ?? '')
.replace(`<!--app-html-->`, rendered.html ?? '')
res.status(200).set({ 'Content-Type': 'text/html' }).send(html)
} catch (e) {
vite?.ssrFixStacktrace(e)
console.log(e.stack)
res.status(500).end(e.stack)
}
})
// Start http server
app.listen(port, () => {
console.log(`Server started at http://localhost:${port}`)
})
In the src folder, create entry-client.tsx and entry-server.tsx.
entry-client.tsx
import './index.css'
import { StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'
import App from './App'
hydrateRoot(
document.getElementById('app') as HTMLElement,
<StrictMode>
<App />
</StrictMode>,
)
entry-server.tsx
import { StrictMode } from 'react'
import { renderToString } from 'react-dom/server'
import App from './App'
/**
* @param {string} _url
*/
export function render(_url) {
const html = renderToString(
<StrictMode>
<App />
</StrictMode>,
)
return { html }
}
Update the scripts section in your package.json file as follows:
"scripts": {
"dev": "node server",
"build:client": "vite build --outDir dist/client",
"build:server": "vite build --outDir dist/server --ssr src/entry-server.tsx",
"build": "npm run build:client && npm run build:server",
"start": "node server.js",
},
Build the project:
npm run buildRun the following command to start the site locally and confirm it works:
npm run startVisit http://localhost:5173/ to verify your web pages.
3. Deploy the project
Compress the entire vite-project folder into a .zip file. Upload the .zip file via FTP. Extract the .zip file using your hosting control panel. Enable Node.js for your site within the hosting control panel. Visit your website to verify the deployment.Reference:
The final folder structure:
site-root-folder/
|-- dist/
|-- client/
|-- index.html
|-- server/
|-- entry-server.js
|-- node_modules/
|-- public/
|-- src/
|-- assets/
|-- App.css
|-- App.tsx
|-- entry-client.tsx
|-- entry-server.tsx
|-- index.css
|-- index.html
|-- package.json
|-- server.js