-
Notifications
You must be signed in to change notification settings - Fork 0
Move plugin imports from global to per-page lazy loading #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f25f61f
3c6962e
5066104
5f8c39f
476e140
71bd4c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| 'use client'; | ||
|
|
||
| import { useEffect, useState } from 'react'; | ||
|
|
||
| type PluginName = | ||
| | 'aggrid' | ||
| | 'editor' | ||
| | 'charts' | ||
| | 'dashboard' | ||
| | 'kanban' | ||
| | 'markdown' | ||
| | 'timeline' | ||
| | 'calendar' | ||
| | 'gantt' | ||
| | 'map' | ||
| | 'chatbot' | ||
| | 'form' | ||
| | 'grid' | ||
| | 'view'; | ||
|
|
||
| interface PluginLoaderProps { | ||
| plugins: PluginName[]; | ||
| children: React.ReactNode; | ||
| } | ||
|
|
||
| /** | ||
| * PluginLoader component - Loads specific plugins on-demand | ||
| * | ||
| * Usage in MDX files: | ||
| * ```mdx | ||
| * import { PluginLoader } from '@/app/components/PluginLoader'; | ||
| * | ||
| * <PluginLoader plugins={['aggrid']}> | ||
| * <InteractiveDemo schema={{...}} /> | ||
| * </PluginLoader> | ||
| * ``` | ||
| */ | ||
| export function PluginLoader({ plugins, children }: PluginLoaderProps) { | ||
| const [loaded, setLoaded] = useState(false); | ||
|
|
||
| useEffect(() => { | ||
| let cancelled = false; | ||
|
|
||
| const loadPlugins = async () => { | ||
| // On server side, skip actual imports but mark as loaded to avoid hydration mismatch | ||
| if (typeof window === 'undefined') { | ||
| if (!cancelled) { | ||
| setLoaded(true); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| // Dynamically import plugins based on the list | ||
| const imports = plugins.map(async (plugin) => { | ||
| switch (plugin) { | ||
| case 'aggrid': | ||
| return import('@object-ui/plugin-aggrid'); | ||
| case 'editor': | ||
| return import('@object-ui/plugin-editor'); | ||
| case 'charts': | ||
| return import('@object-ui/plugin-charts'); | ||
| case 'dashboard': | ||
| return import('@object-ui/plugin-dashboard'); | ||
| case 'kanban': | ||
| return import('@object-ui/plugin-kanban'); | ||
| case 'markdown': | ||
| return import('@object-ui/plugin-markdown'); | ||
| case 'timeline': | ||
| return import('@object-ui/plugin-timeline'); | ||
| case 'calendar': | ||
| return import('@object-ui/plugin-calendar'); | ||
| case 'gantt': | ||
| return import('@object-ui/plugin-gantt'); | ||
| case 'map': | ||
| return import('@object-ui/plugin-map'); | ||
| case 'chatbot': | ||
| return import('@object-ui/plugin-chatbot'); | ||
| case 'form': | ||
| return import('@object-ui/plugin-form'); | ||
| case 'grid': | ||
| return import('@object-ui/plugin-grid'); | ||
| case 'view': | ||
| return import('@object-ui/plugin-view'); | ||
| default: | ||
| console.warn(`Unknown plugin: ${plugin}`); | ||
| return Promise.resolve(); | ||
| } | ||
| }); | ||
|
|
||
| await Promise.all(imports); | ||
| if (!cancelled) { | ||
| setLoaded(true); | ||
| } | ||
| } catch (error) { | ||
| console.error('Failed to load plugins:', error); | ||
| if (!cancelled) { | ||
| setLoaded(true); // Still render children even if plugin loading fails | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| loadPlugins(); | ||
|
|
||
| return () => { | ||
| cancelled = true; | ||
| }; | ||
| }, [plugins]); | ||
|
||
|
|
||
| if (!loaded) { | ||
| return <div className="p-6 text-center text-muted-foreground">Loading plugins...</div>; | ||
| } | ||
|
|
||
| return <>{children}</>; | ||
| } | ||
|
Comment on lines
+1
to
+115
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for typeof window === 'undefined' inside useEffect is unnecessary because useEffect never runs during server-side rendering in React. This code path (lines 46-50) will never execute on the server.
If the goal is to avoid showing a loading state on the server, you should initialize the state differently:
const [loaded, setLoaded] = useState(typeof window === 'undefined');
Then remove the server-side check from the useEffect. This ensures the server renders the children immediately while the client shows loading until plugins are loaded.