Skip to content

Conversation

@dauglyon
Copy link
Collaborator

@dauglyon dauglyon commented Jan 15, 2026

Summary

Migrate the UI from Create React App (CRA) to Vite, along with related tooling updates for TypeScript 5, Vitest, and Storybook 8.

Why Vite?

  • CRA is deprecated - No longer maintained by Facebook/Meta, stuck on older webpack and babel versions with known security vulnerabilities
  • Faster development - Vite uses native ES modules during development, providing near-instant hot module replacement (HMR) instead of rebundling
  • Modern tooling - First-class TypeScript 5 support, modern browser targets, native ESM
  • Better DX - Faster cold starts, on-demand compilation, cleaner error messages
  • Active ecosystem - Vitest for testing, native Storybook support, growing plugin ecosystem

Migration Details

1. Build System Changes

Add Vite configuration files (d5a2945)

New files added:

  • vite.config.ts - Main Vite config with:
    • React plugin with Fast Refresh
    • SVGR plugin for importing SVGs as React components
    • Proxy config for /services → KBase API
    • Vitest configuration (test globals, jsdom environment)
    • Browser targets: Chrome 143+, Firefox 146+, Safari 18+, Edge 143+
  • tsconfig.node.json - TypeScript config for Vite config file itself
  • src/vite-env.d.ts - Type declarations for:
    • Vite client types and SVGR
    • ImportMetaEnv interface with all VITE_* environment variables
    • Global fetchMock for vitest-fetch-mock

Move index.html to project root (40d2379)

Vite expects the entry HTML at the project root (not in public/). Added the entry script tag:

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

Update tsconfig.json (b3a112a)

  • Target: es5ES2020 (modern browsers only)
  • Module resolution: Added bundler for Vite compatibility
  • Added types: vitest/globals, @testing-library/jest-dom
  • References tsconfig.node.json for composite builds

Update package.json (52526b4)

Scripts changed:

- "start": "react-scripts start"
+ "start": "vite"
- "build": "react-scripts build"
+ "build": "tsc && vite build"
- "test": "react-scripts test"
+ "test": "vitest"

2. Environment Variables

Vite uses VITE_ prefix instead of REACT_APP_ and import.meta.env instead of process.env.

Rename in .env files (222540a)

- REACT_APP_KBASE_DOMAIN=ci.kbase.us
+ VITE_KBASE_DOMAIN=ci.kbase.us
- REACT_APP_KBASE_ENV=ci
+ VITE_KBASE_ENV=ci

Update source files (35ce731)

Mechanical find/replace across 15 files:

- process.env.REACT_APP_KBASE_DOMAIN
+ import.meta.env.VITE_KBASE_DOMAIN
- process.env.NODE_ENV
+ import.meta.env.MODE

3. Test Migration (Jest → Vitest)

Vitest is a Vite-native test runner with Jest-compatible API but faster execution.

Rewrite setupTests.ts (93d6ddf)

Major changes:

  • jest-fetch-mockvitest-fetch-mock
  • Added custom console.error handler to suppress expected React warnings
  • Set IS_REACT_ACT_ENVIRONMENT = true for React 18
  • Import @testing-library/jest-dom/vitest for matcher types

Replace Jest APIs in test files (80a2031)

Across 34 test files:

- jest.fn()
+ vi.fn()
- jest.spyOn(module, 'method')
+ vi.spyOn(module, 'method')
- jest.mock('./module')
+ vi.mock('./module')

Also wrapped MUI components with <ThemeProvider> where needed for proper styling in tests.

Update test utilities (2ec950e)

  • mockRTKQuery.ts - Updated mock function types for Vitest
  • kbaseServiceMock.ts - Minor type adjustments
  • jsonrpc11.ts - Compatible with both Jest and Vitest

4. Storybook Migration (v6 → v8)

Storybook 8 has native Vite support and a new component story format.

Migrate config to TypeScript/Vite (1a1ad60)

- // .storybook/main.js
- module.exports = {
-   framework: '@storybook/react',
-   core: { builder: 'webpack5' },
-   addons: ['@storybook/preset-create-react-app']
- }

+ // .storybook/main.ts
+ const config: StorybookConfig = {
+   framework: '@storybook/react-vite',
+   // No CRA preset needed with Vite
+ }

Update story files (bd14b80)

16 story files updated for Storybook 8 API:

- import { ComponentStory, ComponentMeta } from '@storybook/react'
+ import type { Meta, StoryObj } from '@storybook/react'

- export const Primary: ComponentStory<typeof Button> = ...
+ export const Primary: StoryObj<typeof Button> = ...

5. Sass Deprecation Fixes

Fix Sass module syntax (470d982)

26 SCSS files updated for Dart Sass 2.0 compatibility:

- @import "../common/colors";
+ @use "../common/colors" as *;

- $color: map-get($palette, 'primary');
+ @use "sass:map";
+ $color: map.get($palette, 'primary');

- $lightness: lightness($color);
+ @use "sass:color";
+ $lightness: color.channel($color, "lightness", $space: hsl);

6. TypeScript 5 Fixes

Fix typeof syntax (b21c3ed, 21f84cb)

TypeScript 5 requires parentheses around typeof in certain type positions:

- type Foo = typeof bar['key']
+ type Foo = (typeof bar)['key']

Affects collectionsApi.ts, kbaseBaseQuery.ts, and 16 other files.

Fix circular dependency (4a607e0)

Vite's ES module handling is stricter than webpack. Fixed circular import between Routes.tsx and Legacy.tsx by extracting route constants to src/app/routes.constants.ts.


7. Cleanup

Remove unused web-vitals (44dec9a)

web-vitals was included by CRA but never configured to send metrics anywhere. Removed dead code:

  • Deleted src/reportWebVitals.ts
  • Removed import and call from src/index.tsx
  • Removed web-vitals dependency

Update .nvmrc (d3b3e94)

Node.js version: v20.11.1v22.22.0

Update redirectValidation (2a7f398)

Update env var references to use VITE_REDIRECT_WHITELIST.

Update README (df305bd)

Rewrote documentation to reflect Vite migration:

  • New Tech Stack section
  • Updated Available Scripts for Vitest
  • Added Environment Variables and API Proxy docs
  • Removed obsolete CRA troubleshooting

Dependency Changes

Package Before After Notes
Build
react-scripts 5.0.1 ❌ removed Replaced by Vite
vite - 7.3.1 New build tool
@vitejs/plugin-react - 5.1.2 React Fast Refresh
TypeScript
typescript 4.9.4 5.9.3 Major upgrade
State
@reduxjs/toolkit 1.9.5 2.11.2 RTK 2.0
react-redux 8.0.5 9.2.0 Hooks improvements
Testing
jest (via CRA) ❌ removed Replaced by Vitest
vitest - 4.0.17 Vite-native testing
@testing-library/react 14.0.0 16.3.1 React 18 support
Storybook
@storybook/react 6.5.14 8.6.14 Major upgrade
@storybook/builder-webpack5 6.5.14 ❌ removed Using Vite
@storybook/react-vite - 8.6.14 Vite framework
Sass
node-sass 9.0.0 ❌ removed Deprecated
sass - 1.97.2 Dart Sass
Other
web-vitals 1.1.2 ❌ removed Unused CRA boilerplate

Testing Checklist

  • npm install - Dependencies install correctly
  • npm start - Dev server starts, HMR works
  • npm test - All tests pass
  • npm run build - Production build succeeds
  • npm run storybook - Storybook runs
  • npm run lint - No lint errors

🤖 Generated with Claude Code

@dauglyon dauglyon force-pushed the vite-migration branch 5 times, most recently from 155302c to 49b003f Compare January 15, 2026 22:55
- vite.config.ts: Vite config with React plugin, SVGR, proxy for
  /services, Vitest config, and browser targets
- tsconfig.node.json: TypeScript config for Vite config file
- src/vite-env.d.ts: Type declarations for Vite env vars and
  vitest-fetch-mock globals
Vite expects index.html at the root instead of in public/.
Added script tag for src/index.tsx entry point.
No longer needed - Vite types are declared in src/vite-env.d.ts
- Target ES2020 instead of es5
- Add moduleResolution bundler
- Add vitest/globals and @testing-library/jest-dom types
- Reference tsconfig.node.json
- Remove CRA-specific include patterns
- .nvmrc: v20.11.1 -> v22.22.0
- .gitignore: Add storybook-static/ and debug-storybook.log
Vite uses VITE_ prefix instead of REACT_APP_ for env vars.
Also rename PUBLIC_URL to VITE_BASE_URL.
Mechanical find/replace across source files to use Vite's
environment variable syntax instead of CRA's.
Scripts:
- start/build: react-scripts -> vite
- test: react-scripts test -> vitest
- storybook: Add storybook cli commands

Dependencies:
- Remove: react-scripts, node-sass, jest-fetch-mock, canvas
- Add: vite, vitest, @vitejs/plugin-react, vite-plugin-svgr, sass
- Update: @reduxjs/toolkit 1.x->2.x, react-redux 8.x->9.x,
  @storybook/* 6.x->8.x, typescript 4.x->5.x, and others

Also updates .eslintrc.json and CI workflow for Vite.
- Replace jest-fetch-mock with vitest-fetch-mock
- Add custom console.error handler to suppress expected React errors
- Set IS_REACT_ACT_ENVIRONMENT for React 18 compatibility
- Import @testing-library/jest-dom/vitest instead of jest-dom
- Add cleanup handling for React 18 async issues
Mechanical find/replace across all test files:
- jest.fn() -> vi.fn()
- jest.spyOn() -> vi.spyOn()
- jest.mock() -> vi.mock()
- jest.clearAllMocks() -> vi.clearAllMocks()
- Add vi import from vitest where needed
- Wrap components with ThemeProvider for MUI tests
- mockRTKQuery.ts: Replace jest.fn with vi.fn
- kbaseServiceMock.ts: Update mock function types
- jsonrpc11.ts: Minor type adjustments
@dauglyon dauglyon force-pushed the vite-migration branch 2 times, most recently from bd4b1fe to 213d3b2 Compare January 16, 2026 05:14
- main.js -> main.ts: Use @storybook/react-vite framework
- manager.js -> manager.ts: Update to @storybook/manager-api
- preview.js -> preview.tsx: Convert to TypeScript with proper types
- Remove CRA preset addon, no longer needed with Vite
- Update Meta and StoryObj types for Storybook 8 API
- Replace @storybook/testing-library with @storybook/test
- Update argTypes and args syntax
- Add proper TypeScript types for story components
- Replace @import with @use module syntax
- Add @use "sass:map" and @use "sass:color" where needed
- Replace map-get() with map.get()
- Replace lightness() with color.channel($color, "lightness", $space: hsl)
- Update color variable references for new module system
web-vitals was included by Create React App but never configured
to send metrics anywhere. Removing dead code.
Extract LOGIN_ROUTE, SIGNUP_ROUTE, ROOT_REDIRECT_ROUTE, and
LEGACY_BASE_ROUTE to src/app/routes.constants.ts to break the
circular dependency between Routes.tsx and Legacy.tsx.

Vite's ES module handling is stricter than webpack, causing
"Cannot access before initialization" errors when modules have
circular imports. Re-exports maintain backwards compatibility.
- api/index.ts: process.env.NODE_ENV -> import.meta.env.MODE
- LogIn.tsx: Update VITE_REDIRECT_WHITELIST usage
- Wrap typeof expressions in parentheses: typeof foo -> (typeof foo)
- Required for TypeScript 5's stricter type parsing
- Affects collectionsApi.ts and kbaseBaseQuery.ts type definitions
Additional typeof -> (typeof) fixes for TypeScript 5 compatibility
in hooks, slices, and component files.
- REACT_APP_REDIRECT_WHITELIST -> VITE_REDIRECT_WHITELIST
- Add explicit type annotation for map callback
- Replace CRA references with Vite
- Add Tech Stack section with current tooling
- Update Available Scripts for Vitest
- Add Environment Variables documentation
- Add API Proxy and Network Access sections
- Add Project Structure overview
- Remove outdated troubleshooting (node-canvas, CRA issues)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants