What to Avoid When Implementing SSR in Vite.js

What to Avoid When Implementing SSR in Vite.js

·

2 min read

⚠️ 1. Use noExternal for SSR Dependencies

By default, Vite externalizes dependencies, meaning they are not bundled. However, some packages (like React) must be bundled for SSR to work.

Solution:
In vite.config.ts, ensure that react and react-dom are included in noExternal:

ssr: {
  noExternal: ['react', 'react-dom'],
}

⚠️ 2. Avoid Using window or document in Server Code

React SSR runs on the server, where window and document do not exist. If you use them, it will cause an error.

Solution:
Wrap client-only logic inside a check:

if (typeof window !== 'undefined') {
  console.log('This runs only on the client');
}

⚠️ 3. Avoid Using useEffect for Server-Side Data Fetching

useEffect only runs on the client, so it won’t work for SSR pre-fetching.

Solution:
Use data fetching inside entry-server.tsx and pass it as props to components:

export async function render(url: string) {
  const data = await fetchData(); // Fetch data before rendering
  return renderToString(<App initialData={data} />);
}

⚠️ 4. Avoid CSS-in-JS That Requires window

Libraries like styled-components work differently in SSR. If you use them, make sure to collect styles on the server.

Solution:
Use ServerStyleSheet from styled-components:

import { ServerStyleSheet } from 'styled-components';

export function render(url: string) {
  const sheet = new ServerStyleSheet();
  const appHtml = renderToString(sheet.collectStyles(<App />));
  const styleTags = sheet.getStyleTags();
  return `${styleTags}${appHtml}`;
}

⚠️ 5. Proxy API Calls to Avoid CORS Issues

When SSR fetches data from an API, CORS restrictions may block requests.

Solution:
Use Vite’s server proxy to bypass CORS:

server: {
  proxy: {
    '/api': 'http://localhost:5000',
  },
}

⚠️ 6. Ensure Your Backend Supports SSR Routes

SSR apps need proper backend routing. If your backend only serves index.html, SSR won’t work for dynamic routes.

Solution:
Use Express/Fastify to serve all routes properly:

app.use('*', async (req, res) => {
  const url = req.originalUrl;
  const html = await renderSSR(url);
  res.send(html);
});

⚠️ 7. Enable Hydration to Avoid UI Mismatches

If the SSR-rendered HTML does not match what React renders on the client, you’ll get a hydration error.

Solution:
Ensure the same data is used on both client and server:

const [data, setData] = useState(props.initialData ?? null);