This is just a quick introduction to migrating an existing web-app from a CRA => Vite. It doesn't solve all the problems you may have, but it gives a breif introduction to how to migrate. Also added a few points on stuff that went sideways for us whilst performing an migration π€ͺ.
This assumes the following:
- You're using CRA
- You're on latest CRA and React
- You're using
typescript
Two things.
- Remove the
%PUBLIC_URL%
found in yourindex.html
-file. Example:
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
// to
<link rel="icon" href="/favicon.ico"/>
- Include a vite-specific module script after your
root
-element:
<script type="module" src="/src/index.tsx"></script>
- Move the file
index.html
=> root of the project :-).
You, of course, need to adjust your dependencies and package.json
a tad bit. This shows how to!
-
Remove the
package-lock.json
-file -
Install some dependencies
npm install vite-plugin-env-compatible
npm install -D @babel/preset-typescript @types/react-router-dom @vitejs/plugin-react esbuild-jest jest vite vite-plugin-svgr jest-junit
- Adjust
scripts
"scripts": {
"start": "vite --host",
"build": "vite build",
"test": "jest",
"test-coverage": "jest --coverage --no-cache",
"test-ci": "CI=true jest --coverage --no-cache --reporters=default --reporters=jest-junit"
},
- Include configuration for
jest
andbabel
"jest": {
"roots": [
"<rootDir>/src"
],
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!src/**/*.d.ts"
],
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.ts"
],
"testMatch": [
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
],
"testEnvironment": "jsdom",
"transform": {
"^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": [
"esbuild-jest",
{
"sourcemap": true
}
]
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$"
],
"moduleNameMapper": {
"../../assets/size/.*": "<rootDir>/mock/staticFileMock.js"
},
"resetMocks": true
},
"babel": {
"presets": [
"@babel/preset-typescript"
]
}
- Create new file
{project.dir}/mock/staticFileMock.js
with content (will be used during test):
module.exports = 'test-file-stub';
- Remove dependencies
react-scripts
andts-jest
dependency inpackage.json
(if present)!
import react from '@vitejs/plugin-react'
import {defineConfig} from 'vite'
import envCompatible from 'vite-plugin-env-compatible';
import svgrPlugin from 'vite-plugin-svgr'
export default defineConfig({
build: {
outDir: 'build',
},
server: {
open: "/my-app-path",
},
plugins: [
react(),
svgrPlugin(),
envCompatible(),
],
})
{
"compilerOptions": {
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"types": ["vite/client", "vite-plugin-svgr/client"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"noImplicitAny": false,
"jsx": "react-jsx"
},
"include": [
"src"
],
"exclude": [
"src/**/*.test.tsx"
]
}
Rename the setupTests.js
to setupTests.ts
(+ adjusting if required).
Or, hopefully. Something didn't work as intended, check below π€ͺ.
We discovered some oddities with import React from 'react'
in tests. Moving to import * as React from 'react'
solves this issue.
Yeah, no idea why. However, just slap that import
of React in the affected component, and you're done.
import React from 'react';
No worries! Vite will function with non-ts and/or some-ts projects. Just include typescript as a dependency:
npm install -D typescript
And rename, if you have some files with jsx within them, from *.js
=> *.jsx
, and you're mostly done.
Do I have to?
Yes, otherwise you may see this error:
The JSX syntax extension is not currently enabled
Whilst using CRA, you get a nice option of just specifying a setupProxy.js-file in your src
-folder, add a few lines of configuration for som get/post/whatever paths, and you're already off by allowing for mocked responses or proxied responses. Quite amazing!
In Vite, this does not work by just including Vite, as its a CRA thing. However, its ΓΌber-easy to fix. Here is how to just that.
npm install -D express
- Locate your
setupProxy.js
-file and addconst express = require('express')
to the file. Then, create a new instance of express using:const app = express()
. Export this constant directly:
module.exports = app
You should end up with something like:
const express = require('express')
const {createProxyMiddleware} = require('http-proxy-middleware');
const bodyParser = require('body-parser')
const useRealEnvironment = false
const app = express()
if (useRealEnvironment) {
app.use(createProxyMiddleware('/some/path', {target: 'https://some-host.com/', changeOrigin: true}));
} else {
app.get('/some/path/api/user', (req, res) => res.json("{user: 'its you!'}"))
}
app.use(bodyParser.json())
console.log('β
express server ready')
module.exports = app
- In the
vite.config.ts
file add the following plugin:
const expressServerPlugin = (path, expressApp) => ({
name: 'configure-server',
configureServer(server) {
server.middlewares.use(path, expressApp);
}
});
- And use the plugin as follows (add it within the
plugins: [..]
-section) as follows:
plugins: [
...,
expressServerPlugin("/", app),
...
]
- Where does the
app
come from?! This you just imported from your updatedsetupProxy.js
. E.g:
import app from './mock/setupProxy'
Enjoy!