@memberjunction/react-runtime 2.89.0 → 2.91.0
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.
- package/.turbo/turbo-build.log +29 -1
- package/CHANGELOG.md +30 -0
- package/dist/compiler/babel-config.js +1 -0
- package/dist/compiler/babel-config.js.map +1 -0
- package/dist/compiler/component-compiler.d.ts +3 -0
- package/dist/compiler/component-compiler.d.ts.map +1 -1
- package/dist/compiler/component-compiler.js +159 -8
- package/dist/compiler/component-compiler.js.map +1 -0
- package/dist/compiler/index.js +1 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -0
- package/dist/registry/component-registry.d.ts +1 -0
- package/dist/registry/component-registry.d.ts.map +1 -1
- package/dist/registry/component-registry.js +10 -0
- package/dist/registry/component-registry.js.map +1 -0
- package/dist/registry/component-resolver.js +1 -0
- package/dist/registry/component-resolver.js.map +1 -0
- package/dist/registry/index.js +1 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/runtime/component-hierarchy.d.ts +7 -4
- package/dist/runtime/component-hierarchy.d.ts.map +1 -1
- package/dist/runtime/component-hierarchy.js +20 -6
- package/dist/runtime/component-hierarchy.js.map +1 -0
- package/dist/runtime/error-boundary.js +1 -0
- package/dist/runtime/error-boundary.js.map +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/prop-builder.d.ts +2 -1
- package/dist/runtime/prop-builder.d.ts.map +1 -1
- package/dist/runtime/prop-builder.js +1 -0
- package/dist/runtime/prop-builder.js.map +1 -0
- package/dist/runtime/react-root-manager.js +1 -0
- package/dist/runtime/react-root-manager.js.map +1 -0
- package/dist/runtime.umd.js +2 -0
- package/dist/runtime.umd.js.LICENSE.txt +10 -0
- package/dist/types/index.d.ts +4 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/library-config.js +1 -0
- package/dist/types/library-config.js.map +1 -0
- package/dist/utilities/cache-manager.js +1 -0
- package/dist/utilities/cache-manager.js.map +1 -0
- package/dist/utilities/component-error-analyzer.js +1 -0
- package/dist/utilities/component-error-analyzer.js.map +1 -0
- package/dist/utilities/component-styles.js +1 -0
- package/dist/utilities/component-styles.js.map +1 -0
- package/dist/utilities/core-libraries.js +1 -0
- package/dist/utilities/core-libraries.js.map +1 -0
- package/dist/utilities/index.d.ts +1 -1
- package/dist/utilities/index.d.ts.map +1 -1
- package/dist/utilities/index.js +2 -1
- package/dist/utilities/index.js.map +1 -0
- package/dist/utilities/library-loader.d.ts.map +1 -1
- package/dist/utilities/library-loader.js +15 -0
- package/dist/utilities/library-loader.js.map +1 -0
- package/dist/utilities/library-registry.d.ts +24 -0
- package/dist/utilities/library-registry.d.ts.map +1 -0
- package/dist/utilities/library-registry.js +74 -0
- package/dist/utilities/library-registry.js.map +1 -0
- package/dist/utilities/resource-manager.js +1 -0
- package/dist/utilities/resource-manager.js.map +1 -0
- package/dist/utilities/standard-libraries.js +1 -0
- package/dist/utilities/standard-libraries.js.map +1 -0
- package/package.json +16 -6
- package/src/compiler/component-compiler.ts +238 -9
- package/src/index.ts +5 -4
- package/src/registry/component-registry.ts +18 -0
- package/src/runtime/component-hierarchy.ts +29 -8
- package/src/runtime/prop-builder.ts +3 -2
- package/src/types/index.ts +12 -11
- package/src/utilities/index.ts +1 -1
- package/src/utilities/library-loader.ts +18 -0
- package/src/utilities/library-registry.ts +149 -0
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/webpack.umd.config.js +76 -0
- package/dist/utilities/runtime-utilities.d.ts +0 -10
- package/dist/utilities/runtime-utilities.d.ts.map +0 -1
- package/dist/utilities/runtime-utilities.js +0 -92
- package/src/utilities/runtime-utilities.ts +0 -122
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* @module @memberjunction/react-runtime/compiler
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { UserInfo } from '@memberjunction/core';
|
|
7
8
|
import {
|
|
8
9
|
CompileOptions,
|
|
9
10
|
CompiledComponent,
|
|
@@ -12,6 +13,8 @@ import {
|
|
|
12
13
|
ComponentError,
|
|
13
14
|
RuntimeContext
|
|
14
15
|
} from '../types';
|
|
16
|
+
import { LibraryRegistry } from '../utilities/library-registry';
|
|
17
|
+
import { ComponentLibraryEntity } from '@memberjunction/core-entities';
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Default compiler configuration
|
|
@@ -78,6 +81,9 @@ export class ComponentCompiler {
|
|
|
78
81
|
// Validate inputs
|
|
79
82
|
this.validateCompileOptions(options);
|
|
80
83
|
|
|
84
|
+
// Load required libraries if specified
|
|
85
|
+
const loadedLibraries = await this.loadRequiredLibraries(options.libraries!, options.allLibraries);
|
|
86
|
+
|
|
81
87
|
// Transpile the component code
|
|
82
88
|
const transpiledCode = this.transpileComponent(
|
|
83
89
|
options.componentCode,
|
|
@@ -85,10 +91,11 @@ export class ComponentCompiler {
|
|
|
85
91
|
options
|
|
86
92
|
);
|
|
87
93
|
|
|
88
|
-
// Create the component factory
|
|
94
|
+
// Create the component factory with loaded libraries
|
|
89
95
|
const componentFactory = this.createComponentFactory(
|
|
90
96
|
transpiledCode,
|
|
91
|
-
options.componentName
|
|
97
|
+
options.componentName,
|
|
98
|
+
loadedLibraries
|
|
92
99
|
);
|
|
93
100
|
|
|
94
101
|
// Build the compiled component
|
|
@@ -137,7 +144,7 @@ export class ComponentCompiler {
|
|
|
137
144
|
throw new Error('Babel instance not set. Call setBabelInstance() first.');
|
|
138
145
|
}
|
|
139
146
|
|
|
140
|
-
const wrappedCode = this.wrapComponentCode(code, componentName);
|
|
147
|
+
const wrappedCode = this.wrapComponentCode(code, componentName, options.libraries);
|
|
141
148
|
|
|
142
149
|
try {
|
|
143
150
|
const result = this.babelInstance.transform(wrappedCode, {
|
|
@@ -158,16 +165,25 @@ export class ComponentCompiler {
|
|
|
158
165
|
* Wraps component code in a factory function for execution
|
|
159
166
|
* @param componentCode - Raw component code
|
|
160
167
|
* @param componentName - Name of the component
|
|
168
|
+
* @param libraries - Optional library dependencies
|
|
161
169
|
* @returns Wrapped component code
|
|
162
170
|
*/
|
|
163
|
-
private wrapComponentCode(componentCode: string, componentName: string): string {
|
|
171
|
+
private wrapComponentCode(componentCode: string, componentName: string, libraries?: any[]): string {
|
|
172
|
+
// Generate library declarations if libraries are provided
|
|
173
|
+
const libraryDeclarations = libraries && libraries.length > 0
|
|
174
|
+
? libraries
|
|
175
|
+
.filter(lib => lib.globalVariable) // Only include libraries with globalVariable
|
|
176
|
+
.map(lib => `const ${lib.globalVariable} = libraries['${lib.globalVariable}'];`)
|
|
177
|
+
.join('\n ')
|
|
178
|
+
: '';
|
|
179
|
+
|
|
164
180
|
return `
|
|
165
181
|
function createComponent(
|
|
166
182
|
React, ReactDOM,
|
|
167
183
|
useState, useEffect, useCallback, useMemo, useRef, useContext, useReducer, useLayoutEffect,
|
|
168
184
|
libraries, styles, console
|
|
169
185
|
) {
|
|
170
|
-
${componentCode}
|
|
186
|
+
${libraryDeclarations ? libraryDeclarations + '\n ' : ''}${componentCode}
|
|
171
187
|
|
|
172
188
|
// Ensure the component exists
|
|
173
189
|
if (typeof ${componentName} === 'undefined') {
|
|
@@ -190,13 +206,219 @@ export class ComponentCompiler {
|
|
|
190
206
|
`;
|
|
191
207
|
}
|
|
192
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Load required libraries from the registry
|
|
211
|
+
* @param libraries - Array of library dependencies
|
|
212
|
+
* @param contextUser - Context user for accessing library registry
|
|
213
|
+
* @returns Map of loaded libraries
|
|
214
|
+
*/
|
|
215
|
+
private async loadRequiredLibraries(libraries: any[], componentLibraries: ComponentLibraryEntity[]): Promise<Map<string, any>> {
|
|
216
|
+
const loadedLibraries = new Map<string, any>();
|
|
217
|
+
|
|
218
|
+
console.log('🔍 loadRequiredLibraries called with:', {
|
|
219
|
+
librariesCount: libraries?.length || 0,
|
|
220
|
+
libraries: libraries?.map(l => ({ name: l.name, version: l.version, globalVariable: l.globalVariable }))
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (!libraries || libraries.length === 0) {
|
|
224
|
+
console.log('📚 No libraries to load, returning empty map');
|
|
225
|
+
return loadedLibraries;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Only works in browser environment
|
|
229
|
+
if (typeof window === 'undefined') {
|
|
230
|
+
console.warn('Library loading is only supported in browser environments');
|
|
231
|
+
return loadedLibraries;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Initialize LibraryRegistry with componentLibraries if provided
|
|
235
|
+
if (componentLibraries) {
|
|
236
|
+
await LibraryRegistry.Config(false, componentLibraries);
|
|
237
|
+
} else {
|
|
238
|
+
console.warn('⚠️ No componentLibraries provided for LibraryRegistry initialization');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const loadPromises = libraries.map(async (lib) => {
|
|
242
|
+
console.log(`📦 Processing library: ${lib.name}`);
|
|
243
|
+
|
|
244
|
+
// Check if library is approved
|
|
245
|
+
const isApproved = LibraryRegistry.isApproved(lib.name);
|
|
246
|
+
console.log(` ✓ Approved check for ${lib.name}: ${isApproved}`);
|
|
247
|
+
|
|
248
|
+
if (!isApproved) {
|
|
249
|
+
console.error(` ❌ Library '${lib.name}' is not approved`);
|
|
250
|
+
throw new Error(`Library '${lib.name}' is not approved. Only approved libraries can be used.`);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Get library definition for complete info
|
|
254
|
+
const libraryDef = LibraryRegistry.getLibrary(lib.name);
|
|
255
|
+
console.log(` ✓ Library definition found for ${lib.name}: ${!!libraryDef}`);
|
|
256
|
+
|
|
257
|
+
if (!libraryDef) {
|
|
258
|
+
console.error(` ❌ Library '${lib.name}' not found in registry`);
|
|
259
|
+
throw new Error(`Library '${lib.name}' not found in registry`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Get CDN URL for the library
|
|
263
|
+
const resolvedVersion = LibraryRegistry.resolveVersion(lib.name, lib.version);
|
|
264
|
+
console.log(` ✓ Resolved version for ${lib.name}: ${resolvedVersion}`);
|
|
265
|
+
|
|
266
|
+
const cdnUrl = LibraryRegistry.getCdnUrl(lib.name, resolvedVersion);
|
|
267
|
+
console.log(` ✓ CDN URL for ${lib.name}: ${cdnUrl}`);
|
|
268
|
+
|
|
269
|
+
if (!cdnUrl) {
|
|
270
|
+
console.error(` ❌ No CDN URL found for library '${lib.name}' version '${lib.version || 'default'}'`);
|
|
271
|
+
throw new Error(`No CDN URL found for library '${lib.name}' version '${lib.version || 'default'}'`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Check if already loaded
|
|
275
|
+
if ((window as any)[lib.globalVariable]) {
|
|
276
|
+
console.log(` ℹ️ Library ${lib.name} already loaded globally as ${lib.globalVariable}`);
|
|
277
|
+
loadedLibraries.set(lib.globalVariable, (window as any)[lib.globalVariable]);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Load CSS files if the library requires them
|
|
282
|
+
const versionInfo = libraryDef.versions[resolvedVersion || libraryDef.defaultVersion];
|
|
283
|
+
if (versionInfo?.cssUrls) {
|
|
284
|
+
await this.loadStyles(versionInfo.cssUrls);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Load the library dynamically (cdnUrl is guaranteed to be non-null here due to check above)
|
|
288
|
+
console.log(` 📥 Loading script from CDN for ${lib.name}...`);
|
|
289
|
+
await this.loadScript(cdnUrl!, lib.globalVariable);
|
|
290
|
+
|
|
291
|
+
// Capture the library value from global scope
|
|
292
|
+
// Note: Libraries loaded from CDN typically attach to window automatically
|
|
293
|
+
// We capture them here to pass through the component's closure
|
|
294
|
+
const libraryValue = (window as any)[lib.globalVariable];
|
|
295
|
+
console.log(` ✓ Library ${lib.name} loaded successfully, global variable ${lib.globalVariable} is:`, typeof libraryValue);
|
|
296
|
+
|
|
297
|
+
if (libraryValue) {
|
|
298
|
+
loadedLibraries.set(lib.globalVariable, libraryValue);
|
|
299
|
+
console.log(` ✅ Added ${lib.name} to loaded libraries map`);
|
|
300
|
+
} else {
|
|
301
|
+
console.error(` ❌ Library '${lib.name}' failed to expose global variable '${lib.globalVariable}'`);
|
|
302
|
+
throw new Error(`Library '${lib.name}' failed to load or did not expose '${lib.globalVariable}'`);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
await Promise.all(loadPromises);
|
|
307
|
+
|
|
308
|
+
console.log(`✅ All libraries loaded successfully. Total: ${loadedLibraries.size}`);
|
|
309
|
+
console.log('📚 Loaded libraries map:', Array.from(loadedLibraries.keys()));
|
|
310
|
+
|
|
311
|
+
return loadedLibraries;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Load CSS stylesheets dynamically
|
|
316
|
+
* @param urls - Array of CSS URLs to load
|
|
317
|
+
* @returns Promise that resolves when all stylesheets are loaded
|
|
318
|
+
*/
|
|
319
|
+
private async loadStyles(urls: string[]): Promise<void> {
|
|
320
|
+
const loadPromises = urls.map(url => {
|
|
321
|
+
return new Promise<void>((resolve) => {
|
|
322
|
+
// Check if stylesheet already exists
|
|
323
|
+
const existingLink = document.querySelector(`link[href="${url}"]`);
|
|
324
|
+
if (existingLink) {
|
|
325
|
+
resolve();
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Create new link element
|
|
330
|
+
const link = document.createElement('link');
|
|
331
|
+
link.rel = 'stylesheet';
|
|
332
|
+
link.href = url;
|
|
333
|
+
|
|
334
|
+
// CSS load events are not reliable cross-browser, so resolve immediately
|
|
335
|
+
// The CSS will load asynchronously but won't block component rendering
|
|
336
|
+
document.head.appendChild(link);
|
|
337
|
+
resolve();
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
await Promise.all(loadPromises);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Load a script dynamically
|
|
346
|
+
* @param url - Script URL
|
|
347
|
+
* @param globalName - Expected global variable name
|
|
348
|
+
* @returns Promise that resolves when script is loaded
|
|
349
|
+
*/
|
|
350
|
+
private loadScript(url: string, globalName: string): Promise<void> {
|
|
351
|
+
return new Promise((resolve, reject) => {
|
|
352
|
+
// Check if script already exists
|
|
353
|
+
const existingScript = document.querySelector(`script[src="${url}"]`);
|
|
354
|
+
if (existingScript) {
|
|
355
|
+
// Wait for it to finish loading with exponential backoff
|
|
356
|
+
let attempts = 0;
|
|
357
|
+
const maxAttempts = 50; // 5 seconds total with 100ms intervals
|
|
358
|
+
const checkLoaded = () => {
|
|
359
|
+
if ((window as any)[globalName]) {
|
|
360
|
+
resolve();
|
|
361
|
+
} else if (attempts >= maxAttempts) {
|
|
362
|
+
reject(new Error(`${globalName} not found after ${maxAttempts * 100}ms waiting for existing script`));
|
|
363
|
+
} else {
|
|
364
|
+
attempts++;
|
|
365
|
+
setTimeout(checkLoaded, 100);
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
checkLoaded();
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Create new script element
|
|
373
|
+
const script = document.createElement('script');
|
|
374
|
+
script.src = url;
|
|
375
|
+
script.async = true;
|
|
376
|
+
|
|
377
|
+
script.onload = () => {
|
|
378
|
+
// More robust checking with multiple attempts
|
|
379
|
+
let attempts = 0;
|
|
380
|
+
const maxAttempts = 20; // 2 seconds total
|
|
381
|
+
const checkInterval = 100; // Check every 100ms
|
|
382
|
+
|
|
383
|
+
const checkGlobal = () => {
|
|
384
|
+
if ((window as any)[globalName]) {
|
|
385
|
+
console.log(` ✓ Global variable ${globalName} found after ${attempts * checkInterval}ms`);
|
|
386
|
+
resolve();
|
|
387
|
+
} else if (attempts >= maxAttempts) {
|
|
388
|
+
// Final check - some libraries might use a different global name pattern
|
|
389
|
+
console.error(` ❌ ${globalName} not found after ${attempts * checkInterval}ms`);
|
|
390
|
+
console.log(` ℹ️ Window properties:`, Object.keys(window).filter(k => k.toLowerCase().includes(globalName.toLowerCase())));
|
|
391
|
+
reject(new Error(`${globalName} not found after loading script from ${url}`));
|
|
392
|
+
} else {
|
|
393
|
+
attempts++;
|
|
394
|
+
setTimeout(checkGlobal, checkInterval);
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// Start checking immediately (don't wait 100ms first)
|
|
399
|
+
checkGlobal();
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
script.onerror = () => {
|
|
403
|
+
reject(new Error(`Failed to load script: ${url}`));
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
document.head.appendChild(script);
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
193
410
|
/**
|
|
194
411
|
* Creates a component factory function from transpiled code
|
|
195
412
|
* @param transpiledCode - Transpiled JavaScript code
|
|
196
413
|
* @param componentName - Name of the component
|
|
414
|
+
* @param loadedLibraries - Map of loaded libraries
|
|
197
415
|
* @returns Component factory function
|
|
198
416
|
*/
|
|
199
|
-
private createComponentFactory(
|
|
417
|
+
private createComponentFactory(
|
|
418
|
+
transpiledCode: string,
|
|
419
|
+
componentName: string,
|
|
420
|
+
loadedLibraries: Map<string, any>
|
|
421
|
+
): Function {
|
|
200
422
|
try {
|
|
201
423
|
// Create the factory function with all React hooks
|
|
202
424
|
const factoryCreator = new Function(
|
|
@@ -209,6 +431,12 @@ export class ComponentCompiler {
|
|
|
209
431
|
// Return a function that executes the factory with runtime context
|
|
210
432
|
return (context: RuntimeContext, styles: any = {}) => {
|
|
211
433
|
const { React, ReactDOM, libraries = {} } = context;
|
|
434
|
+
|
|
435
|
+
// Merge loaded libraries with context libraries
|
|
436
|
+
const mergedLibraries = { ...libraries };
|
|
437
|
+
loadedLibraries.forEach((value, key) => {
|
|
438
|
+
mergedLibraries[key] = value;
|
|
439
|
+
});
|
|
212
440
|
|
|
213
441
|
// Execute the factory creator to get the createComponent function
|
|
214
442
|
const createComponentFn = factoryCreator(
|
|
@@ -222,7 +450,7 @@ export class ComponentCompiler {
|
|
|
222
450
|
React.useContext,
|
|
223
451
|
React.useReducer,
|
|
224
452
|
React.useLayoutEffect,
|
|
225
|
-
|
|
453
|
+
mergedLibraries,
|
|
226
454
|
styles,
|
|
227
455
|
console
|
|
228
456
|
);
|
|
@@ -239,7 +467,7 @@ export class ComponentCompiler {
|
|
|
239
467
|
React.useContext,
|
|
240
468
|
React.useReducer,
|
|
241
469
|
React.useLayoutEffect,
|
|
242
|
-
|
|
470
|
+
mergedLibraries,
|
|
243
471
|
styles,
|
|
244
472
|
console
|
|
245
473
|
);
|
|
@@ -366,7 +594,8 @@ export class ComponentCompiler {
|
|
|
366
594
|
if (this.compilationCache.size >= this.config.maxCacheSize) {
|
|
367
595
|
// Remove oldest entry (first in map)
|
|
368
596
|
const firstKey = this.compilationCache.keys().next().value;
|
|
369
|
-
|
|
597
|
+
if (firstKey)
|
|
598
|
+
this.compilationCache.delete(firstKey);
|
|
370
599
|
}
|
|
371
600
|
|
|
372
601
|
const cacheKey = this.createCacheKey(component.name, code);
|
package/src/index.ts
CHANGED
|
@@ -71,10 +71,6 @@ export {
|
|
|
71
71
|
} from './runtime';
|
|
72
72
|
|
|
73
73
|
// Export utilities
|
|
74
|
-
export {
|
|
75
|
-
RuntimeUtilities,
|
|
76
|
-
createRuntimeUtilities
|
|
77
|
-
} from './utilities/runtime-utilities';
|
|
78
74
|
|
|
79
75
|
export {
|
|
80
76
|
SetupStyles,
|
|
@@ -93,6 +89,11 @@ export {
|
|
|
93
89
|
LibraryLoadResult
|
|
94
90
|
} from './utilities/library-loader';
|
|
95
91
|
|
|
92
|
+
export {
|
|
93
|
+
LibraryRegistry,
|
|
94
|
+
LibraryDefinition
|
|
95
|
+
} from './utilities/library-registry';
|
|
96
|
+
|
|
96
97
|
export {
|
|
97
98
|
ComponentErrorAnalyzer,
|
|
98
99
|
FailedComponentInfo
|
|
@@ -167,6 +167,24 @@ export class ComponentRegistry {
|
|
|
167
167
|
return components;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Gets all components in a namespace and version as a map
|
|
172
|
+
* @param namespace - Namespace to query (default: 'Global')
|
|
173
|
+
* @param version - Version to query (default: 'v1')
|
|
174
|
+
* @returns Object mapping component names to components
|
|
175
|
+
*/
|
|
176
|
+
getAll(namespace: string = 'Global', version: string = 'v1'): Record<string, any> {
|
|
177
|
+
const components: Record<string, any> = {};
|
|
178
|
+
|
|
179
|
+
for (const entry of this.registry.values()) {
|
|
180
|
+
if (entry.metadata.namespace === namespace && entry.metadata.version === version) {
|
|
181
|
+
components[entry.metadata.name] = entry.component;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return components;
|
|
186
|
+
}
|
|
187
|
+
|
|
170
188
|
/**
|
|
171
189
|
* Gets all registered namespaces
|
|
172
190
|
* @returns Array of unique namespace names
|
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
import {
|
|
8
8
|
CompilationResult,
|
|
9
9
|
CompileOptions,
|
|
10
|
-
ComponentStyles,
|
|
11
10
|
RuntimeContext
|
|
12
11
|
} from '../types';
|
|
13
12
|
import { ComponentCompiler } from '../compiler';
|
|
14
13
|
import { ComponentRegistry } from '../registry';
|
|
15
14
|
|
|
16
|
-
import { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
15
|
+
import { ComponentSpec, ComponentStyles } from '@memberjunction/interactive-component-types';
|
|
16
|
+
import { UserInfo } from '@memberjunction/core';
|
|
17
|
+
import { ComponentLibraryEntity } from '@memberjunction/core-entities';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Result of a hierarchy registration operation
|
|
@@ -48,6 +49,10 @@ export interface HierarchyRegistrationOptions {
|
|
|
48
49
|
continueOnError?: boolean;
|
|
49
50
|
/** Whether to override existing components */
|
|
50
51
|
allowOverride?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Required, metadata for all possible libraries allowed by the system
|
|
54
|
+
*/
|
|
55
|
+
allLibraries: ComponentLibraryEntity[];
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
/**
|
|
@@ -68,7 +73,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
68
73
|
*/
|
|
69
74
|
async registerHierarchy(
|
|
70
75
|
rootSpec: ComponentSpec,
|
|
71
|
-
options: HierarchyRegistrationOptions
|
|
76
|
+
options: HierarchyRegistrationOptions
|
|
72
77
|
): Promise<HierarchyRegistrationResult> {
|
|
73
78
|
const {
|
|
74
79
|
styles,
|
|
@@ -78,6 +83,13 @@ export class ComponentHierarchyRegistrar {
|
|
|
78
83
|
allowOverride = true
|
|
79
84
|
} = options;
|
|
80
85
|
|
|
86
|
+
console.log('🌳 ComponentHierarchyRegistrar.registerHierarchy:', {
|
|
87
|
+
rootComponent: rootSpec.name,
|
|
88
|
+
hasLibraries: !!(rootSpec.libraries && rootSpec.libraries.length > 0),
|
|
89
|
+
libraryCount: rootSpec.libraries?.length || 0,
|
|
90
|
+
libraries: rootSpec.libraries?.map(l => l.name)
|
|
91
|
+
});
|
|
92
|
+
|
|
81
93
|
const registeredComponents: string[] = [];
|
|
82
94
|
const errors: ComponentRegistrationError[] = [];
|
|
83
95
|
const warnings: string[] = [];
|
|
@@ -85,7 +97,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
85
97
|
// Register the root component
|
|
86
98
|
const rootResult = await this.registerSingleComponent(
|
|
87
99
|
rootSpec,
|
|
88
|
-
{ styles, namespace, version, allowOverride }
|
|
100
|
+
{ styles, namespace, version, allowOverride, allLibraries: options.allLibraries }
|
|
89
101
|
);
|
|
90
102
|
|
|
91
103
|
if (rootResult.success) {
|
|
@@ -102,7 +114,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
102
114
|
if (childComponents.length > 0) {
|
|
103
115
|
const childResult = await this.registerChildComponents(
|
|
104
116
|
childComponents,
|
|
105
|
-
{ styles, namespace, version, continueOnError, allowOverride },
|
|
117
|
+
{ styles, namespace, version, continueOnError, allowOverride, allLibraries: options.allLibraries },
|
|
106
118
|
registeredComponents,
|
|
107
119
|
errors,
|
|
108
120
|
warnings
|
|
@@ -130,6 +142,7 @@ export class ComponentHierarchyRegistrar {
|
|
|
130
142
|
namespace?: string;
|
|
131
143
|
version?: string;
|
|
132
144
|
allowOverride?: boolean;
|
|
145
|
+
allLibraries: ComponentLibraryEntity[];
|
|
133
146
|
}
|
|
134
147
|
): Promise<{ success: boolean; error?: ComponentRegistrationError }> {
|
|
135
148
|
const { styles, namespace = 'Global', version = 'v1', allowOverride = true } = options;
|
|
@@ -160,9 +173,16 @@ export class ComponentHierarchyRegistrar {
|
|
|
160
173
|
const compileOptions: CompileOptions = {
|
|
161
174
|
componentName: spec.name,
|
|
162
175
|
componentCode: spec.code,
|
|
163
|
-
styles
|
|
176
|
+
styles,
|
|
177
|
+
libraries: spec.libraries, // Pass along library dependencies from the spec
|
|
178
|
+
allLibraries: options.allLibraries
|
|
164
179
|
};
|
|
165
180
|
|
|
181
|
+
console.log(`🔧 Compiling component ${spec.name} with libraries:`, {
|
|
182
|
+
libraryCount: spec.libraries?.length || 0,
|
|
183
|
+
libraries: spec.libraries?.map(l => ({ name: l.name, globalVariable: l.globalVariable }))
|
|
184
|
+
});
|
|
185
|
+
|
|
166
186
|
const compilationResult = await this.compiler.compile(compileOptions);
|
|
167
187
|
|
|
168
188
|
if (!compilationResult.success) {
|
|
@@ -222,7 +242,8 @@ export class ComponentHierarchyRegistrar {
|
|
|
222
242
|
styles: options.styles,
|
|
223
243
|
namespace: options.namespace,
|
|
224
244
|
version: options.version,
|
|
225
|
-
allowOverride: options.allowOverride
|
|
245
|
+
allowOverride: options.allowOverride,
|
|
246
|
+
allLibraries: options.allLibraries
|
|
226
247
|
});
|
|
227
248
|
|
|
228
249
|
if (childResult.success) {
|
|
@@ -265,7 +286,7 @@ export async function registerComponentHierarchy(
|
|
|
265
286
|
compiler: ComponentCompiler,
|
|
266
287
|
registry: ComponentRegistry,
|
|
267
288
|
runtimeContext: RuntimeContext,
|
|
268
|
-
options: HierarchyRegistrationOptions
|
|
289
|
+
options: HierarchyRegistrationOptions
|
|
269
290
|
): Promise<HierarchyRegistrationResult> {
|
|
270
291
|
const registrar = new ComponentHierarchyRegistrar(compiler, registry, runtimeContext);
|
|
271
292
|
return registrar.registerHierarchy(rootSpec, options);
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* @module @memberjunction/react-runtime/runtime
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { ComponentStyles } from '@memberjunction/interactive-component-types';
|
|
8
|
+
import { ComponentProps, ComponentCallbacks } from '../types';
|
|
8
9
|
import { Subject, debounceTime, Subscription } from 'rxjs';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -187,7 +188,7 @@ export function mergeProps(...propsList: Partial<ComponentProps>[]): ComponentPr
|
|
|
187
188
|
utilities: {},
|
|
188
189
|
callbacks: {},
|
|
189
190
|
components: {},
|
|
190
|
-
styles: {}
|
|
191
|
+
styles: {} as ComponentStyles
|
|
191
192
|
};
|
|
192
193
|
|
|
193
194
|
for (const props of propsList) {
|
package/src/types/index.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* @module @memberjunction/react-runtime/types
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { UserInfo } from '@memberjunction/core';
|
|
8
|
+
import { ComponentLibraryEntity } from '@memberjunction/core-entities';
|
|
9
|
+
import { ComponentLibraryDependency, ComponentStyles } from '@memberjunction/interactive-component-types';
|
|
10
|
+
|
|
7
11
|
/**
|
|
8
12
|
* Represents a compiled React component with its metadata
|
|
9
13
|
*/
|
|
@@ -36,20 +40,17 @@ export interface CompileOptions {
|
|
|
36
40
|
babelPlugins?: string[];
|
|
37
41
|
/** Custom Babel presets to use */
|
|
38
42
|
babelPresets?: string[];
|
|
39
|
-
}
|
|
40
43
|
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
style?: Record<string, any>;
|
|
49
|
-
/** Global CSS to inject */
|
|
50
|
-
globalCss?: string;
|
|
44
|
+
/** Library dependencies that the component requires */
|
|
45
|
+
libraries?: ComponentLibraryDependency[];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Required, metadata for all possible libraries allowed by the system
|
|
49
|
+
*/
|
|
50
|
+
allLibraries: ComponentLibraryEntity[];
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
|
|
53
54
|
/**
|
|
54
55
|
* Registry entry for a compiled component
|
|
55
56
|
*/
|
package/src/utilities/index.ts
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* @module @memberjunction/react-runtime/utilities
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export * from './runtime-utilities';
|
|
7
6
|
export * from './component-styles';
|
|
8
7
|
export * from './standard-libraries';
|
|
9
8
|
export * from './library-loader';
|
|
9
|
+
export * from './library-registry';
|
|
10
10
|
export * from './component-error-analyzer';
|
|
11
11
|
export * from './resource-manager';
|
|
12
12
|
export * from './cache-manager';
|
|
@@ -99,6 +99,24 @@ export class LibraryLoader {
|
|
|
99
99
|
const ReactDOM = coreResults.find((_, i) => coreLibraries[i].globalVariable === 'ReactDOM');
|
|
100
100
|
const Babel = coreResults.find((_, i) => coreLibraries[i].globalVariable === 'Babel');
|
|
101
101
|
|
|
102
|
+
// Expose React and ReactDOM as globals for UMD libraries that expect them
|
|
103
|
+
// Many React component libraries (Recharts, Victory, etc.) expect these as globals
|
|
104
|
+
if (typeof window !== 'undefined') {
|
|
105
|
+
if (React && !(window as any).React) {
|
|
106
|
+
(window as any).React = React;
|
|
107
|
+
console.log('✓ Exposed React as window.React for UMD compatibility');
|
|
108
|
+
}
|
|
109
|
+
if (ReactDOM && !(window as any).ReactDOM) {
|
|
110
|
+
(window as any).ReactDOM = ReactDOM;
|
|
111
|
+
console.log('✓ Exposed ReactDOM as window.ReactDOM for UMD compatibility');
|
|
112
|
+
}
|
|
113
|
+
// Also expose PropTypes as empty object if not present (for older libraries)
|
|
114
|
+
if (!(window as any).PropTypes) {
|
|
115
|
+
(window as any).PropTypes = {};
|
|
116
|
+
console.log('✓ Exposed empty PropTypes as window.PropTypes for UMD compatibility');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
102
120
|
// Now load plugin libraries from configuration
|
|
103
121
|
const config = StandardLibraryManager.getConfiguration();
|
|
104
122
|
const enabledLibraries = StandardLibraryManager.getEnabledLibraries();
|