-
-
Couldn't load subscription status.
- Fork 0
Technical Guides ‐ Migrating to Vite
As explained in ADR-0002, we are migrating our Create React App (CRA)-based client applications over to Vite (and Vitest to replace CRA-managed Jest).
⚠️ If you have any problems migrating your app to Vite while following this guide, report them in #cyf-tech-products.
Since Vite 5:
Vite no longer supports Node.js 14 / 16 / 17 / 19, which reached its EOL. Node.js 18 / 20+ is now required.
Given ADR-0001 we should be moving all Tech Products repos to Node ^20.9; ensure this is done before starting the Vite migration.
Remove the old tooling with:
# npm
npm uninstall react-scripts
# yarn
yarn remove react-scriptsReview the dependency list - if you have anything referring to jest (except @testing-library/jest-dom, which is still compatible) it will need to be removed and/or updated.
# npm
npm install --save-dev vite @vitejs/plugin-react-swc
# yarn
yarn add --dev vite @vitejs/plugin-react-swcNote that Vite goes in devDependencies, unlike react-scripts which encouraged putting everything in dependencies. Take this opportunity to review what's in each dependency group, and move (i.e. npm uninstall/yarn remove then re-npm install/yarn add) anything that's in the wrong place (e.g. linting- or testing-related dependencies should be --save-dev'd).
-
Vite uses ESM by default, so set
"type": "module"in yourpackage.json. -
Create a new file
vite.config.jsand add the following:import react from '@vitejs/plugin-react-swc' import { defineConfig } from 'vite' export default defineConfig({ build: { outDir: 'build' }, plugins: [react()] })
-
Move
index.htmlout ofpublic/to the root of the package (i.e. as a sibling ofpackage.jsonandsrc/) and add a new line<script type="module" src="/src/main.jsx"></script>in the body (just after<div id="root"></div>). -
Delete
src/serviceWorker.jsand remove any reference to it insrc/index.js -
Rename
src/index.jstosrc/main.jsx(note this file extension is now required, see JSX)
The Vite CLI supports many of the same commands as react-scripts, but with a few minor changes:
-
Build (compile to static JS/HTML/CSS/etc.):
- "build": "react-scripts build", + "build": "vite build",
Some of our apps have various steps to remove source maps; Vite defaults to not generating source maps at all, this can be configured using the
build.sourcemapproperty invite.config.js. -
Eject (stop using CRA and emit Webpack/Babel/etc. code) has no equivalent, just remove it:
- "eject": "react-scripts eject", -
Preview/serve (statically serve the build outputs):
- "serve": "serve --single build", + "serve": "vite preview",
This defaults to port 4173, but we can set
preview.portinvite.config.jsas needed. -
Start (dev mode):
- "start": "react-scripts start", + "start": "vite",
This defaults to port 5173 rather than 3000, but we can set
server.portinvite.config.jsto e.g.parseInt(process.env.PORT ?? "3000", 10)to restore the behaviour we're used to. -
Test (run low-level tests):
- "test": "react-scripts test", + "test": "vitest",
Unlike CRA, which would transpile JSX in any file with the extension .js or .jsx, Vite requires any file containing JSX to be explicitly .jsx.
Unlike CRA's convention of process.env.REACT_APP_{whatever}*, Vite injects relevant environment variables based on the VITE_ prefix into import.meta.env.
Different configuration for different environments can be handled with .env.[mode] files - note that anything secret should be placed in a .env.local/.env.[mode].local file.
Vitest is API compatible with Jest, which means it's largely a drop-in replacement. Install the following test-specific dependencies:
# npm
npm install --save-dev vitest jsdom
# yarn
yarn add --dev vitest jsdomAdd the following section to the vite.config.js configuration file:
- import { defineConfig } from 'vite'
+ import { defineConfig } from 'vitest/config' test: {
environment: "jsdom",
globals: true,
},If the src/setupTests.js file is in use, add that too:
test: {
environment: "jsdom",
globals: true,
+ setupFiles: [
+ "./src/setupTests.js",
+ ],
},Most of the globals (e.g. describe, expect, it) have the same names, but any references to properties of the Jest object, e.g. jest.fn(), need to be replaced with the equivalent from the vi helper, e.g. vi.fn().
Any additional configuration under the "jest" property in package.json will also have to be reviewed and possibly migrated.
Vite does support CSS pre-processors, however several of our repos are using the now-deprecated node-sass.
Instead, to continue using .sass/.scss styles, we need to switch to sass:
# npm
npm uninstall node-sass
npm install --save-dev sass
# yarn
yarn remove node-sass
yarn add --dev sassNo further configuration is needed, Vite picks this up automatically if you import any relevant style files (as CRA did).
CRA bundled an ESLint configuration, which was likely in use.
You may also have had other configs or plugins installed, and/or rules enabled - make note of these.
ESLint configuration will definitely be in the eslintConfig field in package.json, but you may also have .eslintrc files.
Instead of the CRA config we can use the configuration provided by the Vite React template by removing eslintConfig from package.json and creating a .eslintrc.cjs in the root of the package containing:
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['build', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}This requires the following dependencies:
# npm
npm install --save-dev eslint@8 eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-refresh
# yarn
yarn add --dev eslint@^8.57.0 eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-react-refreshUpdate your linting script in package.json to explicitly include both .js and .jsx files, for example:
- "lint": "eslint src",
+ "lint": "eslint --ext js,jsx src",Once all of the linting has been set up (including the optional steps below, if relevant), run npm run lint/yarn lint and fix any issues so we don't break the pipeline (you can apply some fixes automatically with npm run lint -- --fix/yarn lint --fix, others may require a bit more work).
To restore the best of what CRA included, you can then also add:
# npm
npm install --save-dev eslint-plugin-import eslint-plugin-jsx-a11y
# yarn
yarn add --dev eslint-plugin-import eslint-plugin-jsx-a11yand add the following presets and rules:
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
+ 'plugin:jsx-a11y/recommended',
],- plugins: ['react-refresh'],
+ plugins: ['import', 'react-refresh'],
rules: {
+ 'import/first': 'error',
+ 'import/no-amd': 'error',
+ 'import/no-anonymous-default-export': 'warn',
+ 'import/no-webpack-loader-syntax': 'error',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},CYF also has its own ESLint configuration you could adopt at this point, by installing:
# npm
npm install --save-dev @codeyourfuture/eslint-config-standard
# yarn
yarn add --dev @codeyourfuture/eslint-config-standardand switching out the first preset:
extends: [
- 'eslint:recommended',
+ '@codeyourfuture/standard',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
],Migrate from CRA's proxy setup (src/setupProxy.js/proxy in package.json) to Vite's proxy setup.
Uninstall http-proxy-middleware if present:
# npm
npm uninstall http-proxy-middleware
# yarn
yarn remove http-proxy-middleware- Remove
browserslistfrompackage.json(Vite manages its own supported browsers). - Update any documentation (README, wiki, etc.) referring to CRA or Jest
-
#33 Migrate client tooling to Vite/Vitest in
CodeYourFuture/tech-products-demo - JS TTD Vite shows how to set up a simple Vite React app for testing
-
ac5356e"Migrate from CRA to Vite" intextbook/abv(note: also includes TypeScript) -
c036603"Migrate client build and dev server to Vite" (in a full-stack app, from Babel and Webpack)
* this is achieved by literal text replacement, as process.env doesn't exist in the browser - see e.g. https://stackoverflow.com/a/76440819/3001761 for details