While we were busy using tools like Create React App (CRA) on a day-to-day basis, Vite just popped up as an efficient tool that brought innovation and gained a lot of attention in the community.
However, migrating an existing project from Create React App (CRA) to Vite can be a journey filled with unexpected challenges. Here, I share our experience, shedding light on the intricacies of such a migration and providing insights that might ease your transition.
Our odyssey began with the addition of @vitejs/plugin-react
and vite
to our project, which necessitated the removal of react-scripts
and react-app-rewired
. Our reliance on react-app-rewired
had left us with custom configurations that didn't translate directly to Vite. This was particularly evident when addressing our JSX files, traditionally with .js
extensions, which we resolved by crafting a custom plugin to enforce .jsx
extensions for JSX-containing files.
// vite.config.js snippet
optimizeDeps: {
esbuildOptions: {
plugins: [
{
name: 'load-js-files-as-jsx',
setup(build) {
build.onLoad(
{filter: /src\/.*\.js$/},
async (args) => ({
loader: 'jsx',
contents: await fs.readFile(args.path, 'utf8'),
})
)
},
},
],
},
},
Even with configurations seemingly in place, our application was initially unresponsive, offering no clues beyond a This site can’t be reached
message. It was only after comparing our structure with a Vite skeleton project did we realised that index.html
needed relocation from the public
directory to the root. This simple move was the key to our breakthrough.
The initial application run surfaced a plethora of errors, especially with SVG imports. We swiftly adopted vite-plugin-svgr
, modifying our import statements to accommodate Vite's module resolution.
// vite.config.js snippet
plugins: [
react(),
svgr({
svgrOptions: {},
include: '**/*.svg?react',
}),
],
Migrating custom paths and environment variables was another hurdle. The Vite configuration syntax differed significantly from CRA, but we mapped our aliases and adopted the import.meta.env
pattern, prefixing our variables with VITE_
to align with Vite's conventions.
// vite.config.js snippet
resolve: {
alias: {
// Aliases
},
},
With Vite, we transitioned from Jest to Vitest, necessitating a renaming of our test files and an addition to our ESLint configuration to recognize Vitest's global variables.
// .eslintrc snippet
"globals": {
"vi": true
}
Vite's default build directory is dist
, a departure from CRA's build
. This necessitated script updates in our package.json
. Moreover, to maintain our development workflow, we customized the development server's startup to land on a specific admin page.
// package.json snippet
"dev": "vite --port 3000 --open custom-url",
The transition of an NPM module from CRA to Vite introduced unique considerations. We disabled the public directory and defined the main entry file for the library. The package's main entry point was also specified in package.json
.
// vite.config.js snippet for NPM module
publicDir: false,
build: {
lib: {
entry: path.resolve(__dirname, 'src/main.jsx'),
formats: ['es'],
fileName: 'main',
},
rollupOptions: {
external: ['react', 'react-dom', 'react/jsx-runtime'],
},
},
For CSS management, we leveraged vite-plugin-lib-inject-css
, which efficiently chunked CSS files corresponding to their JavaScript counterparts.
// vite.config.js snippet
plugins: [
// Other plugins...
libInjectCss(),
// ...
],
The migration from CRA to Vite was far from trivial; it was a testament to the complexity hidden behind the simplicity of modern tooling. Every step revealed a new aspect of the build and deployment process that we took for granted with CRA. However, the improved build times, reduced configuration overhead, and the promise of a more streamlined development experience provided by Vite were compelling reasons to undertake this journey.
Through trial and error and a fair bit of Googling, we emerged on the other side with a functional setup, a deeper understanding of our toolchain, and a newfound appreciation for the craft of web development.
1. DEV Community: A guide detailing the migration process from CRA to Vite, including GitHub Actions workflow updates and optimization tips for development processes.
2. FreeCodeCamp: Offers insights into updating environment variables and troubleshooting common issues when migrating from CRA to Vite, such as global is not defined errors.
3. Robin Wieruch's Blog: Provides a comprehensive guide on migrating to Vite, including creating a `vite.config.js` file and updating `index.html`, with additional steps for using ESLint and TypeScript with Vite.
5. Patrick Desjardins' Blog: Shares personal migration experiences to ViteJS with TypeScript and absolute path capability, including configuring the `vite.config.ts` file and handling environment variables.
6. HackerNoon: Discusses why Vite is considered better than CRA, emphasizing its faster speed and bundling efficiency with Rollup.
7. HackerNoon: Describes the obsolescence of CRA and presents Vite among other alternatives, noting its performance benefits and fast development time.
8. HackerNoon: A case study on improving speed and performance by migrating from Webpack to Vite, including practical experiences and lessons learned.