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 Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  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.

Oren Farhi user avatar by
Oren Farhi
·
Nov. 22, 22 · Analysis
Like (2)
Save
Tweet
Share
937 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.

Popular on DZone

  • GitLab vs Jenkins: Which Is the Best CI/CD Tool?
  • What Are the Benefits of Java Module With Example
  • Practical Example of Using CSS Layer
  • How Chat GPT-3 Changed the Life of Young DevOps Engineers

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

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

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: