DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • How We Reduced LCP by 75% in a Production React App
  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • Mastering React App Configuration With Webpack
  • Overcoming React Development Hurdles: A Guide for Developers

Trending

  • Chaos Engineering Has a Blind Spot. Agentic AI Lives in It.
  • Securing the AI Host: Spring AI MCP Server Communication With API Keys
  • Why DDoS Protection Is an Architectural Decision for Developers
  • Skills, Java 17, and Theme Accents
  1. DZone
  2. Coding
  3. JavaScript
  4. Reducing React Dev Server to 213ms — From Create React App to Vite v3 Migration

Reducing React Dev Server to 213ms — From Create React App to Vite v3 Migration

In this article, I share the steps to migrating CRA (create react app) to use Vite v3 while highlighting the benefits.

By 
Oren Farhi user avatar
Oren Farhi
·
Updated Nov. 22, 22 · Analysis
Likes (2)
Comment
Save
Tweet
Share
1.5K Views

Join the DZone community and get the full member experience.

Join For Free

Developer experience is important. Having a fast and reliable development and build solution is important as the code that is written and how it performs. Recently, I saw a significant slow-down in a react app that its development and build system was based on the latest CRA package (create react app/react-script).

I improved the developer experience in both development and build for production from a
few seconds to a mere 213ms from 3277ms (dev server) —  That's an improvement of 95% in server uptime. In this article, I share my steps for migrating CRA (create react app) to use Vite while highlighting the benefits.

With Vite (After):

With Vite

With CRA (Before):

With CRA

Why Vite.js?

The JS ecosystem is a wild ride —  every once in a while, there is a new library/package/some other solution that comes with a promise to improve developer life in the JS client, server, and even both. The last JS evolution that popularized SSR and SSG introduced Next.js, Remix, fresh, and more as a full-stack JavaScript framework for web applications and static websites. However, not everyone is joining that ride —  I assume some don't get the full benefits while others might be stuck in a complex migration, and some don't even need the server-side benefits —  in which case these are client-side apps (CSA). 

In my case, I was looking for a CRA alternative that would not require me to introduce a JS server and any significant opinionated architecture and code change. I was interested in migrating to Next.js or Remix.

However, I dismissed both because they required me to make a huge change to my application while also requiring a learning curve that I could not afford due to time constraints.

Issues With CRA

CRA has become for my projects very sluggish and had a few issues. For starters, the first dev server start took around 45 seconds. While at the same time, cold starts took about eight to nine seconds.

I had to migrate storybook v6.5 to use Vite.js builder —  since it didn't work with the latest CRA v5 because it's based on webpack version 5. Due to that, the build process for the storybook failed because webpack still exists in the system (at the time of writing this article, it is still an issue).

The hot module reload/refresh was problematic and not satisfying —  with few changes, the entire app was reloaded, and sometimes I had to manually reload.

Lastly, maintenance and the new version release have gone silent for quite some time now.

Migrating to Vite.js

Version 3 was just published, and I wanted to try it after reading and seeing some examples that looked good. The ability to easily configure or have a "zero configuration" appealed to me.

My CRA app uses React 18, Typescript, Chakra-UI, and some SVG files.

Vite configuration lives in a vite.config.ts file at the root of the project (I chose to go with the Typescript version, although JS also works).

The Base Configuration for Compiling React, Typescript, and SVG

To support all the above and match the build of CRA, this configuration worked:

These npm packages are required:

Shell
 
npm i vite vite-plugin-svgr vite-tsconfig-paths @vitejs/plugin-react


TypeScript
 
import { defineConfig } from 'vite'
import svgrPlugin from 'vite-plugin-svgr'
import tsconfigPaths from 'vite-tsconfig-paths'
import react from '@vitejs/plugin-react'
import path from 'path';

export default defineConfig({
  server: {
    port: 3210,
  },

  build: {
    outDir: 'build',
  },

  plugins: [
    react(),
    tsconfigPaths(),
    svgrPlugin({
      svgrOptions: {
        icon: true,
        // ...svgr options (https://react-svgr.com/docs/options/)
      },
    }),
  ],
})


I believe the code is pretty much self-explanatory. One of the most dominant components is the plugin entry —  which allows composing pluggable features to vite's build system. 

Some of these plugin functions usually get a configuration object as a parameter, which lets you further customize what and how a plugin should do with the compiled code.

To complement typings and following some documentation on Vite, tsconfig.ts was updated with these:

JSON
 
{
  "target": "ESNext",
  "esModuleInterop": false,
  "jsx": "react-jsx",
  "types": [
    "vite/client", 
    "vite-plugin-svgr/client", 
  ],
  "paths": {
    "~/*": ["./*"]
  }
}


On top of this basic configuration, I added the following plugins to support more features:

Shell
 
npm i @vitejs/plugin-basic-ssl vite-plugin-mkcert vite-plugin-pwa
// adding workbox to support pwa features
npm i workbox-core workbox-precaching workbox-routing workbox-window


TypeScript
 
export default defineConfig({

plugins: [
    enableSsl && basicSsl(),
    mkcert(),
    // ...
    // ... plugins from above
    // ...

    VitePWA({
      manifest, // imported from ./manifest.json
      includeAssets: ['favicon.ico', 'robots.txt', 'images/*.png'],
      devOptions: {
        enabled: false,
      },
      workbox: {
        globPatterns: ['**/*.{js,css,html}', '**/*.{svg,png,jpg,gif}'],
        maximumFileSizeToCacheInBytes: 3000000,
      },
    }),
  ],
})


My readm app is a PWA app, which at this point, installs a cached version to speed up loading time on the next time a user opens the app. The app is also installable as a desktop app on any platform, desktop, and mobile. 

There's more to PWA configuration —  i.e., showing an update is available - for that, I had to use a dedicated solution, which is out of the scope of this article. I followed examples from the excellent VitePWA documentation and examples. I add vite-plugin-pwa/client to the tsconfig/types section.

PWA apps require an SSL connection and so —  basicSsl() and mkcert() simply set up a local HTTPS server with a locally signed certificate —  This step required a few steps when I was using CRA.

Updating Index.html and Environment Variables

The main entry point to the app, index.html, has to be in the root. I removed any %PUBLIC_URL% instances as these were not needed. Vite requires a plugin to embed environment variables values from .env —  I chose to remove those completely from the index and embed the codes statically (Google Analytics). 

A few image references in the HTML were updated with a full path starting from the root, i.e. src/assets/images/readm.png. 

Vite requires indicating the starting file for the app with a simple script tag before the closing body tag:

HTML
 
 <script type="module" src="/src/index.tsx"></script>


As for environment variables defined in .env, I had to replace any REACT_APP_ with VITE_. To use these variables across the app, you would use them like that:

TypeScript
 
import.met.env.VITE_THE_VARIABLE


src/react-app-env.d.ts has been renamed src/env.d.ts

Configure the Test With Vitest

create-react-app was using jest and react-testing-library. With Vite, I had to install the vitest plugin and add its configuration to vite.config.ts. To run a test with a virtual dom, I had to install two additional packages as well:

Shell
 
npm i vitest c8 jsdom
TypeScript
 

// added this typing reference
/// <reference types="vitest" />

export default defineConfig({
  test: {
    include: ['src/**/__tests__/*'],
    globals: true,
    environment: 'jsdom',
    setupFiles: 'src/setupTests.ts',
    clearMocks: true,
    coverage: {
      enabled: true,
      '100': true,
      reporter: ['text', 'lcov'],
      reportsDirectory: 'coverage/jest'
    }
  },
  // ... rest of the config
}


The difference in vitest vs. jest was replacing stub functions:

TypeScript
 
// BEFORE
const speak = jest.fn()

// AFTER

import { vi } from 'vitest'
const speak = vi.fn()


Updating Package.json Scripts

Finally, to make it all work, we must update the scripts that are building the production app and starting the server.

This is easily done with the following:

JSON
 
{
  "start": "vite",
  "build": "vite build",
  "test": "vitest",
  "test:ci": "vitest run"
}


With everything in place, I removed react scripts as well.

Conclusion

Moving from CRA to Vite improved my developer experience by far. As the screenshot at the beginning of the article shows, the dev server is up in ~213ms (the first run takes 1-2 seconds) compared to CRA - which took around 3277ms or more (the first run adds 4-5 seconds) —  that's a reduction of about 95% in for the dev server startup.

The additional benefit in the developer experience is the hot module reload during development —  changes are injected live into the working server —  updating specific files for the update and reloading the entire app. That's a huge improvement from the previous CRA development.

The build process has also been improved — around 10 seconds with a live indicator and hints on how to improve it. That same build took around 40 seconds in CRA
with no live indicator.

Feels like readm is now steroids — I recommend anyone who's still using create-react-app to make this effort and consider migrating to Vite.

JavaScript Picasa Web Albums app dev React (JavaScript library)

Published at DZone with permission of Oren Farhi. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How We Reduced LCP by 75% in a Production React App
  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • Mastering React App Configuration With Webpack
  • Overcoming React Development Hurdles: A Guide for Developers

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook