Skip to content

Commit 10cd1e5

Browse files
committed
fix(app-page-builder): create plugin loader components
1 parent a782ed0 commit 10cd1e5

File tree

6 files changed

+139
-212
lines changed

6 files changed

+139
-212
lines changed

packages/app-page-builder/src/admin/components/EditorPluginsLoader.tsx

Lines changed: 0 additions & 138 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createPluginsLoader } from "~/admin/components/PluginLoaders/createPluginsLoader";
2+
3+
export const EditorPluginsLoader = createPluginsLoader({
4+
type: "pb-editor-page-element",
5+
factory: plugin => {
6+
return plugin.loadEditorPlugins ? plugin.loadEditorPlugins() : undefined;
7+
}
8+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createPluginsLoader } from "~/admin/components/PluginLoaders/createPluginsLoader";
2+
3+
export const RenderPluginsLoader = createPluginsLoader({
4+
type: "pb-render-page-element",
5+
factory: plugin => {
6+
return plugin.loadRenderPlugins ? plugin.loadRenderPlugins() : undefined;
7+
}
8+
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { useEffect, useState } from "react";
2+
import type { Plugin } from "@webiny/plugins/types";
3+
import { GenericRecord } from "@webiny/app/types";
4+
import { plugins } from "@webiny/plugins";
5+
import { CircularProgress } from "@webiny/ui/Progress";
6+
import type { PbEditorPageElementPlugin, PbPluginsLoader, PbRenderElementPlugin } from "~/types";
7+
8+
export interface CreatePluginsLoaderParams {
9+
// Plugin type
10+
type: PbRenderElementPlugin["type"] | PbEditorPageElementPlugin["type"];
11+
// Plugin factory
12+
factory: (plugin: PbPluginsLoader) => Promise<Plugin[]> | undefined;
13+
}
14+
15+
const globalCache: GenericRecord<string, boolean> = {};
16+
17+
export interface PluginsLoaderProps {
18+
children: React.ReactNode;
19+
}
20+
21+
export const createPluginsLoader = ({ type, factory }: CreatePluginsLoaderParams) => {
22+
const PluginsLoader = ({ children }: PluginsLoaderProps) => {
23+
const [loaded, setLoaded] = useState(false);
24+
25+
const loadPlugins = async () => {
26+
const pluginsLoaders = plugins.byType<PbPluginsLoader>("pb-plugins-loader");
27+
28+
const lazyLoadedPlugins = await Promise.all(
29+
pluginsLoaders.map(plugin => factory(plugin)).filter(Boolean)
30+
);
31+
32+
// Here comes an awkward hack: there's a chance that a user registered some custom plugins through React,
33+
// and they're already in the registry. But we want to make sure that user plugins are applied _after_ the lazy-loaded
34+
// plugins, loaded via the `pb-plugins-loader`. To achieve that, we unregister existing plugins, and register them
35+
// _after_ the lazy-loaded ones.
36+
37+
const existingPlugins = plugins.byType(type);
38+
39+
existingPlugins.forEach(plugin => {
40+
plugins.unregister(plugin.name);
41+
});
42+
43+
// Register lazy-loaded plugins first.
44+
plugins.register(lazyLoadedPlugins);
45+
plugins.register(existingPlugins);
46+
};
47+
48+
useEffect(() => {
49+
if (!globalCache[type]) {
50+
loadPlugins().then(() => {
51+
globalCache[type] = true;
52+
setLoaded(true);
53+
});
54+
} else {
55+
setLoaded(true);
56+
}
57+
}, []);
58+
59+
return loaded ? <>{children}</> : <CircularProgress />;
60+
};
61+
62+
PluginsLoader.displayName = `PluginsLoader<${type}>`;
63+
64+
return PluginsLoader;
65+
};

0 commit comments

Comments
 (0)