Jertype

Member of Information Superhighway

Migrating from create-react-app to vite

Reason for migration

create-react-app production builds were slow, integration with tailwind was limited, and the future of create-react-app is unclear.

The following steps were built via trial and error. Good luck!

Required Packages

NodeJS polyfills

Environment variables

Change all environment variable prefixes from REACT_APP to VITE. For example, REACT_APP_KEY would be VITE_KEY. Here’s a way to rename them with Sublime Text.

process.env references must also be replaced with import.meta.env. Repeat the above steps to find and replace those.

There are better ways to do this. Send a script and I might add it here :)

All files with JSX in them must have .jsx file extension

Why Vite requires .jsx file extensions is described here.

You can use this gist (MacOS / Linux only) to rename your files. It searches through ./src and renames all .js files with JSX markup in them to use the .jsx extension instead.

There are two because one finds files with </ in them and the other with /> in them.

File locations

<!DOCTYPE html>
<html lang='en'>
<!-- ... head code here -->
<body>
  <div id='root'></div>
  <script type="module" src="/src/index.jsx"></script>
</body>
</html>

Render initial component into the root div and remove the serviceWorker code added by create-react-app.

src/index.jsx example

import App from './App';
import { createRoot } from 'react-dom/client';
import './css/index.css';

const container = document.getElementById('root');
const root = createRoot(container); 
root.render(<App tab="home" />);

Node scripts

HTTP proxy

Here’s our old setupProxy.js for reference:

const createProxyMiddleware = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'https://localhost:1111',
      changeOrigin: true,
      secure: false
    })
  );
  app.use(
    '/sso',
    createProxyMiddleware({
      target: 'https://localhost:1112',
      changeOrigin: true,
      secure: false
    })
  );
};

This will be replaced by the proxy section in vite.config.js.

HTTP proxy error

If you receive the following error while using the http proxy:

[vite] http proxy error:
Error: read ECONNRESET
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20)

Set the http agent manually. This may be a bug in the node-http-proxy library.

This was an odd issue because it only showed up on newer versions of node.

Production builds

build: {
  minify: false,
}

CSS loading order

After switching to vite we had issues with imported CSS.

There’s some discussion about loading CSS in vite here:

If you have issues here’s how to check the order:

Development

Production

We moved some of our CSS import statements out of our components and up to the initial App component. We’re not sure why that fixed things unfortunately!

Example vite.config.js

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import basicSsl from '@vitejs/plugin-basic-ssl'
import stdLibBrowser from 'node-stdlib-browser'
import inject from '@rollup/plugin-inject'
import https from 'https'

const agent = new https.Agent({keepAlive: true})

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    port: 3000,
    https: true,
    proxy: {
      '/api': {
        target: 'https://localhost:1111',
        changeOrigin: true,
        secure: false,
        agent
      },
      '/sso': {
        target: 'https://localhost:1112',
        changeOrigin: true,
        secure: false,
        agent
      }
    }
  },
  preview: {
    port: 3000,
    https: true,
    proxy: {
      '/api': {
        target: 'https://localhost:1111',
        changeOrigin: true,
        secure: false,
        agent
      },
      '/sso': {
        target: 'https://localhost:1112',
        changeOrigin: true,
        secure: false,
        agent
      }
    }
  },
  build: {
    minify: false,
    outDir: 'build'
  },
  optimizeDeps: {
    include: ['buffer', 'process']
  },
  plugins: [
    react({ fastRefresh: false }), 
    basicSsl(),
    {
      ...inject({
          global: [
            require.resolve(
              'node-stdlib-browser/helpers/esbuild/shim'
            ),
            'global'
          ],
          process: [
            require.resolve(
              'node-stdlib-browser/helpers/esbuild/shim'
            ),
            'process'
          ],
          Buffer: [
            require.resolve(
              'node-stdlib-browser/helpers/esbuild/shim'
            ),
            'Buffer'
          ]
        }),
        enforce: 'post'
    }
  ]
})

Hope this helped!