Skip to content

Latest commit

 

History

History
219 lines (184 loc) · 6.47 KB

File metadata and controls

219 lines (184 loc) · 6.47 KB

Lazy-Loaded Plugins - Verification Report

Build Verification

Plugin Packages Structure

1. @object-ui/plugin-editor (Monaco Editor)

packages/plugin-editor/
├── src/
│   ├── MonacoImpl.tsx         # Heavy implementation (imports Monaco)
│   └── index.tsx              # Lazy wrapper with React.lazy()
├── dist/
│   ├── index.js         (0.19 KB)  # Entry point - LIGHT
│   ├── MonacoImpl-*.js (19.42 KB)  # Heavy chunk - LAZY LOADED
│   ├── index-*.js      (22.42 KB)  # Supporting chunk
│   └── index.umd.cjs   (30.37 KB)  # UMD bundle
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.md

Key Files:

  • MonacoImpl.tsx: Contains import Editor from '@monaco-editor/react'
  • index.tsx: Contains React.lazy(() => import('./MonacoImpl'))

2. @object-ui/plugin-charts (Recharts)

packages/plugin-charts/
├── src/
│   ├── ChartImpl.tsx          # Heavy implementation (imports Recharts)
│   └── index.tsx              # Lazy wrapper with React.lazy()
├── dist/
│   ├── index.js         (0.19 KB)   # Entry point - LIGHT
│   ├── ChartImpl-*.js (541.17 KB)   # Heavy chunk - LAZY LOADED
│   ├── index-*.js      (22.38 KB)   # Supporting chunk
│   └── index.umd.cjs  (393.20 KB)   # UMD bundle
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.md

Key Files:

  • ChartImpl.tsx: Contains import { BarChart, ... } from 'recharts'
  • index.tsx: Contains React.lazy(() => import('./ChartImpl'))

Playground Build Output

When the playground imports both plugins, they remain as separate chunks:

apps/playground/dist/assets/
├── index-CyDHUpwF.js                (2.2 MB)  # Main bundle
├── MonacoImpl-DCiwKyYW-D65z0X-D.js  ( 15 KB)  # Monaco - SEPARATE
├── ChartImpl-BJBP1UnW-DO38vX_d.js  (340 KB)  # Recharts - SEPARATE
└── index-dgFB6nSI.css               ( 99 KB)  # Styles

Lazy Loading Mechanism

Code Flow

  1. App Startup (Initial Load):

    // apps/playground/src/App.tsx
    import '@object-ui/plugin-editor';  // Loads ~200 bytes
    import '@object-ui/plugin-charts';  // Loads ~200 bytes
    • ✅ Only the entry points are loaded (~400 bytes total)
    • ❌ Monaco Editor is NOT loaded yet
    • ❌ Recharts is NOT loaded yet
  2. Component Registration:

    // Inside @object-ui/plugin-editor/src/index.tsx
    ComponentRegistry.register('code-editor', CodeEditorRenderer);
    • Components are registered with the registry
    • But the heavy implementation is NOT executed yet
  3. Schema Rendering (When Component Used):

    const schema = { type: 'code-editor', value: '...' };
    <SchemaRenderer schema={schema} />
    • SchemaRenderer looks up 'code-editor' in registry
    • Finds CodeEditorRenderer
    • CodeEditorRenderer contains <Suspense><LazyComponent /></Suspense>
    • React.lazy triggers dynamic import of MonacoImpl.tsx
    • NOW the Monaco chunk is fetched from the server
    • Shows skeleton while loading
    • Renders Monaco Editor once loaded

Network Request Timeline

Initial Page Load:

GET /index.html                          200 OK
GET /assets/index-CyDHUpwF.js           200 OK  (Main bundle)
GET /assets/index-dgFB6nSI.css          200 OK  (Styles)
# Monaco and Recharts chunks NOT requested

When Code Editor Component Renders:

GET /assets/MonacoImpl-DCiwKyYW-D65z0X-D.js  200 OK  (15 KB)
# Loaded on demand!

When Chart Component Renders:

GET /assets/ChartImpl-BJBP1UnW-DO38vX_d.js  200 OK  (340 KB)
# Loaded on demand!

Bundle Size Comparison

Without Lazy Loading (Traditional Approach)

Initial Load:
- Main bundle:     2.2 MB
- Monaco bundled:  + 0.015 MB
- Recharts bundled: + 0.340 MB
────────────────────────────
TOTAL INITIAL:     ~2.6 MB  ❌ Heavy!

With Lazy Loading (Our Implementation)

Initial Load:
- Main bundle:     2.2 MB
- Plugin entries:  + 0.0004 MB (400 bytes)
────────────────────────────
TOTAL INITIAL:     ~2.2 MB  ✅ Lighter!

On-Demand (when components render):
- Monaco chunk:    0.015 MB (if code-editor used)
- Recharts chunk:  0.340 MB (if chart-bar used)

Savings: ~355 KB (13.5%) on initial load for apps that don't use these components on every page.

Verification Tests

Test 1: Build Output Structure

$ ls -lh packages/plugin-editor/dist/
-rw-rw-r-- 1 runner runner  197 bytes  index.js          # Entry (light)
-rw-rw-r-- 1 runner runner   19K      MonacoImpl-*.js   # Heavy chunk
✅ PASS: Heavy chunk is separate from entry point

Test 2: Playground Build

$ ls -lh apps/playground/dist/assets/ | grep -E "(Monaco|Chart)"
-rw-rw-r-- 1 runner runner  15K MonacoImpl-*.js
-rw-rw-r-- 1 runner runner 340K ChartImpl-*.js
✅ PASS: Plugin chunks are separate in final build

Test 3: Component Registration

// After importing '@object-ui/plugin-editor'
ComponentRegistry.has('code-editor')  // true
 PASS: Components are registered automatically

Test 4: Lazy Loading Behavior

// Initial import - lightweight
import '@object-ui/plugin-editor';  // ~200 bytes loaded

// Use in schema - triggers lazy load
<SchemaRenderer schema={{ type: 'code-editor' }} />
// Monaco chunk (~15 KB) is NOW fetched
 PASS: Heavy chunk loads only when component renders

Usage Examples

Example 1: Code Editor

{
  "type": "code-editor",
  "value": "function hello() {\n  console.log('Hello, World!');\n}",
  "language": "javascript",
  "theme": "vs-dark",
  "height": "400px"
}

Example 2: Bar Chart

{
  "type": "chart-bar",
  "data": [
    { "name": "Jan", "value": 400 },
    { "name": "Feb", "value": 300 },
    { "name": "Mar", "value": 600 }
  ],
  "dataKey": "value",
  "xAxisKey": "name",
  "height": 400,
  "color": "#8884d8"
}

Conclusion

Successfully implemented lazy-loaded plugin architecture

  • Heavy libraries (Monaco, Recharts) are in separate chunks
  • Chunks are only loaded when components are actually rendered
  • Main bundle stays lean (~2.2 MB vs ~2.6 MB)
  • Users don't need to manage lazy loading themselves
  • Provides loading skeletons automatically

The implementation follows React best practices and Vite's code-splitting capabilities to deliver optimal performance.