@gooddata/sdk-ui-loaders 11.49.0-alpha.0 → 11.49.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -106,13 +106,82 @@ function addScriptTag(url) {
|
|
|
106
106
|
element,
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
|
+
// React, ReactDOM and the JSX runtimes must resolve to the single host-provided instance —
|
|
110
|
+
// hooks and context break across duplicate React copies. A prebuilt (webpack) plugin bundles
|
|
111
|
+
// its own React and registers it into the share scope on container.init(). When that copy is a
|
|
112
|
+
// higher semver than the host's, the plugin's singleton consume selects the plugin's (lazily
|
|
113
|
+
// loaded) copy and reads a null React at render ("Cannot read properties of null (reading
|
|
114
|
+
// 'useEffect')"), blanking the dashboard.
|
|
115
|
+
const REACT_SINGLETON_SHARES = [
|
|
116
|
+
"react",
|
|
117
|
+
"react-dom",
|
|
118
|
+
"react-dom/client",
|
|
119
|
+
"react/jsx-runtime",
|
|
120
|
+
"react/jsx-dev-runtime",
|
|
121
|
+
];
|
|
122
|
+
function snapshotSharedVersions(shareScope) {
|
|
123
|
+
const snapshot = {};
|
|
124
|
+
for (const key of REACT_SINGLETON_SHARES) {
|
|
125
|
+
snapshot[key] = new Set(Object.keys(shareScope?.[key] ?? {}));
|
|
126
|
+
}
|
|
127
|
+
return snapshot;
|
|
128
|
+
}
|
|
129
|
+
// The host's React versions are captured once per share scope and cached. Snapshotting them
|
|
130
|
+
// per loadEntry call would race under concurrent plugin loads: a later call could snapshot the
|
|
131
|
+
// scope after an earlier plugin's container.init() already registered its own React and mistake
|
|
132
|
+
// that copy for a host version, leaving a plugin React in the scope for the singleton consume to
|
|
133
|
+
// pick. The read-then-set below is synchronous, so the first call to reach it captures the scope
|
|
134
|
+
// before any plugin container has initialized, and every other call reuses that snapshot.
|
|
135
|
+
const hostReactVersionsByScope = new WeakMap();
|
|
136
|
+
function getHostReactVersions(shareScope) {
|
|
137
|
+
if (!shareScope) {
|
|
138
|
+
return snapshotSharedVersions(shareScope);
|
|
139
|
+
}
|
|
140
|
+
let snapshot = hostReactVersionsByScope.get(shareScope);
|
|
141
|
+
if (!snapshot) {
|
|
142
|
+
snapshot = snapshotSharedVersions(shareScope);
|
|
143
|
+
hostReactVersionsByScope.set(shareScope, snapshot);
|
|
144
|
+
}
|
|
145
|
+
return snapshot;
|
|
146
|
+
}
|
|
147
|
+
// Drop the React copies the plugin just registered so it reuses the host's already-provided
|
|
148
|
+
// singleton, then resolve that copy up front so the plugin's synchronous consume reads a live
|
|
149
|
+
// module rather than an unresolved lazy factory.
|
|
150
|
+
async function pinReactSharesToHost(shareScope, hostVersions) {
|
|
151
|
+
await Promise.all(REACT_SINGLETON_SHARES.map(async (key) => {
|
|
152
|
+
const versions = shareScope?.[key];
|
|
153
|
+
if (!versions) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const hostKeys = Object.keys(versions).filter((version) => hostVersions[key]?.has(version));
|
|
157
|
+
// Only strip plugin-added copies when a host copy remains to fall back on.
|
|
158
|
+
if (hostKeys.length > 0) {
|
|
159
|
+
for (const version of Object.keys(versions)) {
|
|
160
|
+
if (!hostVersions[key]?.has(version)) {
|
|
161
|
+
delete versions[version];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const entry = versions[hostKeys[0] ?? Object.keys(versions)[0]];
|
|
166
|
+
if (entry && typeof entry.get === "function") {
|
|
167
|
+
const factory = await entry.get();
|
|
168
|
+
if (typeof factory === "function") {
|
|
169
|
+
factory();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
109
174
|
function loadEntry(moduleName, { __webpack_init_sharing__, __webpack_share_scopes__ }) {
|
|
110
175
|
return async () => {
|
|
111
176
|
// Initializes the share scope. This fills it with known provided modules from this build and all remotes
|
|
112
177
|
await __webpack_init_sharing__("default");
|
|
178
|
+
const shareScope = __webpack_share_scopes__.default;
|
|
179
|
+
// The host's React versions, captured once before any plugin container contributes its own.
|
|
180
|
+
const hostReactVersions = getHostReactVersions(shareScope);
|
|
113
181
|
const container = window[moduleName]; // or get the container somewhere else
|
|
114
182
|
// Initialize the container, it may provide shared modules
|
|
115
|
-
await container.init(
|
|
183
|
+
await container.init(shareScope);
|
|
184
|
+
await pinReactSharesToHost(shareScope, hostReactVersions);
|
|
116
185
|
// the `./${moduleName}_ENTRY` corresponds to exposes in the dashboard-plugin-template webpack config
|
|
117
186
|
const entryFactory = await window[moduleName].get(`./${moduleName}_ENTRY`);
|
|
118
187
|
const entryModule = entryFactory();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-loaders",
|
|
3
|
-
"version": "11.49.0-alpha.
|
|
3
|
+
"version": "11.49.0-alpha.1",
|
|
4
4
|
"description": "GoodData SDK Runtime Component Loaders",
|
|
5
5
|
"license": "LicenseRef-LICENSE",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"semver": "7.7.4",
|
|
33
33
|
"ts-invariant": "0.10.3",
|
|
34
34
|
"tslib": "2.8.1",
|
|
35
|
-
"@gooddata/sdk-backend-spi": "11.49.0-alpha.
|
|
36
|
-
"@gooddata/sdk-model": "11.49.0-alpha.
|
|
37
|
-
"@gooddata/sdk-ui
|
|
38
|
-
"@gooddata/sdk-ui": "11.49.0-alpha.
|
|
35
|
+
"@gooddata/sdk-backend-spi": "11.49.0-alpha.1",
|
|
36
|
+
"@gooddata/sdk-model": "11.49.0-alpha.1",
|
|
37
|
+
"@gooddata/sdk-ui": "11.49.0-alpha.1",
|
|
38
|
+
"@gooddata/sdk-ui-dashboard": "11.49.0-alpha.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"react": "19.1.1",
|
|
70
70
|
"react-dom": "19.1.1",
|
|
71
71
|
"typescript": "5.9.3",
|
|
72
|
-
"@gooddata/eslint-config": "11.49.0-alpha.
|
|
73
|
-
"@gooddata/oxlint-config": "11.49.0-alpha.
|
|
72
|
+
"@gooddata/eslint-config": "11.49.0-alpha.1",
|
|
73
|
+
"@gooddata/oxlint-config": "11.49.0-alpha.1"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"react": "^18.0.0 || ^19.0.0",
|