Skip to content

Commit

Permalink
Add SSR support #10
Browse files Browse the repository at this point in the history
  • Loading branch information
Erdoğan Bulut committed Sep 4, 2022
1 parent a0ea8bf commit 9d90d33
Show file tree
Hide file tree
Showing 6 changed files with 474 additions and 15 deletions.
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<div id="root"><!--ssr-outlet--></div>
<script type="module" src="/src/entry-client.tsx"></script>
</body>
</html>
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
"name": "viterts",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"dev": "node server",
"build": "tsc && vite build",
"build:client": "tsc && vite build --outDir dist/client",
"build:server": "tsc && vite build --outDir dist/server --ssr src/entry-server.tsx",
"preview": "vite preview",
"lint": "yarn run lint:ts",
"lint:ts": "tsc && yarn lint:eslint",
Expand All @@ -19,6 +22,7 @@
"@reduxjs/toolkit": "^1.8.5",
"antd": "^4.23.0",
"bootstrap": "^5.2.0",
"express": "^4.18.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.2",
Expand All @@ -31,6 +35,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
"@types/express": "^4.17.13",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"@typescript-eslint/eslint-plugin": "^5.36.1",
Expand Down
64 changes: 64 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import express from 'express';
import { createServer as createViteServer } from 'vite';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

async function createServer() {
const app = express();

// Create Vite server in middleware mode and configure the app type as
// 'custom', disabling Vite's own HTML serving logic so parent server
// can take control
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'custom',
});

// use vite's connect instance as middleware
// if you use your own express router (express.Router()), you should use router.use
app.use(vite.middlewares);

app.use('*', async (req, res, next) => {
const url = req.originalUrl;

try {
// 1. Read index.html
let template = fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf-8');

// 2. Apply Vite HTML transforms. This injects the Vite HMR client, and
// also applies HTML transforms from Vite plugins, e.g. global preambles
// from @vitejs/plugin-react
template = await vite.transformIndexHtml(url, template);

// 3. Load the server entry. vite.ssrLoadModule automatically transforms
// your ESM source code to be usable in Node.js! There is no bundling
// required, and provides efficient invalidation similar to HMR.
const { render } = await vite.ssrLoadModule('/src/entry-server.tsx');

// 4. render the app HTML. This assumes entry-server.js's exported `render`
// function calls appropriate framework SSR APIs,
// e.g. ReactDOMServer.renderToString()
const appHtml = await render(url);

// 5. Inject the app-rendered HTML into the template.
const html = template.replace(`<!--ssr-outlet-->`, appHtml);

// 6. Send the rendered HTML back.
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
} catch (e) {
// If an error is caught, let Vite fix the stack trace so it maps back to
// your actual source code.
vite.ssrFixStacktrace(e);
next(e);
}
});

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

createServer();
3 changes: 2 additions & 1 deletion src/main.tsx → src/entry-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { BrowserRouter } from 'react-router-dom';
import App from './App';
import { store } from './store';

ReactDOM.createRoot(document.getElementById('root')!).render(
ReactDOM.hydrateRoot(
document.getElementById('root')!,
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
Expand Down
17 changes: 17 additions & 0 deletions src/entry-server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { Provider } from 'react-redux';
import { StaticRouter } from 'react-router-dom/server';
import App from './App';
import { store } from './store';

export const render = (url: any, context: any) =>
ReactDOMServer.renderToString(
<Provider store={store}>
<StaticRouter location={url} context={context}>
<App />
</StaticRouter>
</Provider>,
);

export default render;
Loading

0 comments on commit 9d90d33

Please sign in to comment.