Skip to content

React version fragmentation - Mixed React 17 and 18 causing bundle bloat and runtime issues #1271

@Harshit2405-2004

Description

@Harshit2405-2004

Problem

The EmbeddedChat monorepo has inconsistent React versions across packages, causing peer dependency conflicts, potential runtime errors, and significant bundle size increase.

Current State

Packages using React 17.0.2 (as peerDependencies)

  • @embeddedchat/react
  • @embeddedchat/ui-kit
  • @embeddedchat/ui-elements
  • @embeddedchat/markups

Packages using React 18.2.0 (as dependencies or peerDependencies)

  • @embeddedchat/htmlembed
  • @embeddedchat/layout_editor
  • @embeddedchat/e2e-react
  • @embeddedchat/react-native

Impact

Build & Runtime Issues

  • ⚠️ Peer dependency warnings during installation
  • ⚠️ Multiple React instances bundled together
  • ⚠️ Duplicate React in bundle (~200KB overhead, 97% increase)
  • ⚠️ React Context doesn't work across package boundaries
  • ⚠️ React Hooks behave unexpectedly with multiple instances
  • ⚠️ Different feature sets (React 18 has Suspense, Concurrent Mode, etc.)

Example Error Scenarios

Warning: Invalid hook call. Hooks can only be called inside the body of a function component.
This could happen for one of the following reasons:
1. You might have mismatching versions of React and React DOM
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app

Evidence

Run this in the monorepo root:

# Check all React versions
yarn why react

# Example output shows multiple versions:
# react@17.0.2 - ui-kit, react, ui-elements, markups
# react@18.2.0 - htmlembed, layout_editor, react-native

Proposed Solution

Option 1: Migrate All to React 18 (Recommended)

React 18 is backward compatible with React 17 code. Migrate all packages to use React 18 with broad peer dependencies.

Benefits:

  • ✅ Access to React 18 features (Suspense, Concurrent Mode, Automatic Batching)
  • ✅ Single React instance
  • ✅ Future-proof (React 19 compatibility path)
  • ✅ Smaller bundle size

Changes needed:

// For library packages (@embeddedchat/react, ui-kit, ui-elements, markups)
{
  "peerDependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}

// For application packages (htmlembed, layout_editor, e2e-react)
{
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

Migration steps:

  1. Update all package.json files

    • Libraries: Use "react": "^18.0.0" in peerDependencies
    • Apps: Use "react": "^18.2.0" in dependencies
  2. Update React imports if needed

    // If using React 17 style
    - import React from 'react';
    - import ReactDOM from 'react-dom';
    + import { createRoot } from 'react-dom/client';
  3. Test for breaking changes

    • Most React 17 code works in React 18
    • Main change: ReactDOM.rendercreateRoot
    • Check for UNSAFE_* lifecycle methods
  4. Update root rendering (if applicable)

    // React 17
    ReactDOM.render(<App />, document.getElementById('root'));
    
    // React 18
    const root = createRoot(document.getElementById('root'));
    root.render(<App />);

Option 2: Keep React 17, Align All Packages

If React 18 migration is not desired:

{
  "peerDependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  }
}

Downside: Miss out on React 18 features and future compatibility.

Implementation Plan

Phase 1: Audit & Plan

  • List all packages with React dependencies
  • Identify React 18-specific code (if any)
  • Check for UNSAFE_* lifecycle methods
  • Review third-party dependencies' React requirements

Phase 2: Update Dependencies

  • Update all package.json files to React 18
  • Update peerDependencies to use ^18.0.0
  • Remove react from dependencies in library packages (keep as peer only)
  • Run yarn install to resolve dependencies

Phase 3: Update Code

  • Update root rendering to use createRoot (if applicable)
  • Replace any React 17-specific patterns
  • Update tests to use React 18 testing library

Phase 4: Test

  • Run all unit tests
  • Run E2E tests
  • Test bundle size (should decrease)
  • Manual testing of all features
  • Check for console warnings about multiple React instances

Verification

After fix, verify single React instance:

# Should show only React 18.x
yarn why react

# Check bundle size (should be smaller)
yarn build
ls -lh dist/  # Compare before/after

Benefits

Single React instance - No duplicate React in bundle
Smaller bundle size - ~200KB reduction
No peer dependency warnings
Consistent behavior - Same React version everywhere
React 18 features - Suspense, Concurrent Mode, etc.
Better DX - No version-related debugging
Future-proof - Easier to upgrade to React 19

Estimated Effort

Time: 1-2 days
Complexity: Medium
Risk: Low (React 18 is backward compatible)
Files affected: 8-12 package.json files, possibly 1-2 rendering files

References

Acceptance Criteria

  • All packages use same React version (18.x)
  • No peer dependency warnings during install
  • Single React instance in bundle (verify with yarn why react)
  • All tests passing
  • Bundle size reduced
  • No console warnings about multiple React instances
  • Documentation updated with React 18 requirement

Discovered during: Comprehensive codebase analysis
Priority: HIGH - Causes build warnings and bundle bloat
Category: Dependencies / Build Configuration

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions