Skip to content

Task: Refactor Monorepo to Support Lazy-Loaded Plugins #31

@huangyiirene

Description

@huangyiirene

I have an existing pnpm workspace with packages/react (Core) and packages/components (Standard Lib).
Now I need to split heavy components into separate Plugin Packages and implement Internal Lazy Loading to optimize bundle size.

1. New Directory Structure

Please create two new packages in packages/:

  1. packages/plugin-editor:

    • Purpose: A code editor component.
    • Simulated Heavy Dependency: @monaco-editor/react.
    • Schema Type: code-editor.
  2. packages/plugin-charts:

    • Purpose: A charting component.
    • Simulated Heavy Dependency: recharts (or simply simulate a large file).
    • Schema Type: chart-bar.

2. ⚡️ The Lazy Loading Pattern (CRITICAL)

Do NOT force the Host App to use React.lazy. The plugin itself must handle the lazy loading internally.

Implementation Requirement for each plugin:

  1. HeavyImpl.tsx: The actual component that imports the heavy library (e.g., Monaco).
  2. index.tsx: The entry point. It must use React.lazy to import HeavyImpl.tsx and wrap it in <React.Suspense>.

Example Code Structure (for plugin-editor):

// packages/plugin-editor/src/MonacoImpl.tsx
import Editor from '@monaco-editor/react'; // 👈 The heavy import happens here
export default function MonacoImpl(props) { ... }

// packages/plugin-editor/src/index.tsx
import React, { Suspense } from 'react';
import { Skeleton } from '@object-ui/components'; // Reuse skeleton from standard lib

// 🚀 Lazy load the implementation file
const LazyEditor = React.lazy(() => import('./MonacoImpl'));

export const CodeEditorRenderer = (props) => (
  <Suspense fallback={<Skeleton className="h-64 w-full bg-slate-100" />}>
    <LazyEditor {...props} />
  </Suspense>
);

// Standard Export Protocol
export const editorComponents = {
  'code-editor': CodeEditorRenderer
};

3. Execution Steps
 * Create Packages: Initialize plugin-editor and plugin-charts with package.json and tsconfig.json.
 * Implement Lazy Logic: Apply the pattern described above to both plugins.
   * For plugin-charts, create a mock "Heavy Chart" component if you don't want to install recharts yet, but ensure the React.lazy structure is used.
 * Export Registry: Ensure package.json main points to src/index.ts (or dist).
 * Update Playground:
   * Go to apps/playground.
   * Add dependencies: pnpm add @object-ui/plugin-editor @object-ui/plugin-charts --workspace.
   * In App.tsx, import editorComponents and chartComponents.
   * Merge them into the SchemaRenderer components prop:
     const registry = { ...standardComponents, ...editorComponents, ...chartComponents };

4. Verification
Create a test schema in the Playground containing { "type": "code-editor" }.
Verify that the heavy chunk (Monaco/Charts) is NOT loaded on initial page load, but only loaded when the component is rendered.

Metadata

Metadata

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