@probat/react 0.1.2 → 0.1.4
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/dist/index.d.mts +1 -30
- package/dist/index.d.ts +1 -30
- package/dist/index.js +328 -193
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +330 -191
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -1
- package/src/context/ProbatContext.tsx +1 -12
- package/src/hoc/itrt-frontend.code-workspace +3 -0
- package/src/hoc/withExperiment.tsx +4 -12
- package/src/index.ts +0 -6
- package/src/utils/api.ts +347 -42
package/src/utils/api.ts
CHANGED
|
@@ -15,6 +15,8 @@ export type ComponentVariantInfo = {
|
|
|
15
15
|
|
|
16
16
|
export type ComponentExperimentConfig = {
|
|
17
17
|
proposal_id: string;
|
|
18
|
+
repo_full_name: string;
|
|
19
|
+
base_ref?: string; // Git branch/ref (default: "main")
|
|
18
20
|
variants: Record<string, ComponentVariantInfo>;
|
|
19
21
|
};
|
|
20
22
|
|
|
@@ -82,7 +84,7 @@ export async function sendMetric(
|
|
|
82
84
|
captured_at: new Date().toISOString(),
|
|
83
85
|
};
|
|
84
86
|
try {
|
|
85
|
-
|
|
87
|
+
await fetch(url, {
|
|
86
88
|
method: "POST",
|
|
87
89
|
headers: {
|
|
88
90
|
Accept: "application/json",
|
|
@@ -91,29 +93,8 @@ export async function sendMetric(
|
|
|
91
93
|
credentials: "include", // CRITICAL: Include cookies to distinguish different users
|
|
92
94
|
body: JSON.stringify(body),
|
|
93
95
|
});
|
|
94
|
-
|
|
95
|
-
//
|
|
96
|
-
if (!response.ok) {
|
|
97
|
-
console.warn('[PROBAT] Metric send failed:', {
|
|
98
|
-
status: response.status,
|
|
99
|
-
statusText: response.statusText,
|
|
100
|
-
url,
|
|
101
|
-
body,
|
|
102
|
-
});
|
|
103
|
-
} else {
|
|
104
|
-
console.log('[PROBAT] Metric sent successfully:', {
|
|
105
|
-
metricName,
|
|
106
|
-
proposalId,
|
|
107
|
-
variantLabel,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
} catch (error) {
|
|
111
|
-
// Log error in development, but don't break the app
|
|
112
|
-
console.error('[PROBAT] Error sending metric:', {
|
|
113
|
-
error: error instanceof Error ? error.message : String(error),
|
|
114
|
-
url,
|
|
115
|
-
body,
|
|
116
|
-
});
|
|
96
|
+
} catch {
|
|
97
|
+
// Silently fail - metrics should not break the app
|
|
117
98
|
}
|
|
118
99
|
}
|
|
119
100
|
|
|
@@ -197,6 +178,7 @@ export async function fetchComponentExperimentConfig(
|
|
|
197
178
|
|
|
198
179
|
// Cache for variant component loads
|
|
199
180
|
const variantComponentCache = new Map<string, Promise<React.ComponentType<any> | null>>();
|
|
181
|
+
const moduleCache = new Map<string, any>(); // Cache for loaded modules (relative imports)
|
|
200
182
|
|
|
201
183
|
// Make React available globally for variant components
|
|
202
184
|
if (typeof window !== "undefined") {
|
|
@@ -204,11 +186,146 @@ if (typeof window !== "undefined") {
|
|
|
204
186
|
(window as any).React = (window as any).React || React;
|
|
205
187
|
}
|
|
206
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Resolve relative import path to absolute path
|
|
191
|
+
*/
|
|
192
|
+
function resolveRelativePath(relativePath: string, basePath: string): string {
|
|
193
|
+
// Remove file extension if present
|
|
194
|
+
const baseDir = basePath.substring(0, basePath.lastIndexOf('/'));
|
|
195
|
+
const parts = baseDir.split('/').filter(Boolean);
|
|
196
|
+
const relativeParts = relativePath.split('/').filter(Boolean);
|
|
197
|
+
|
|
198
|
+
for (const part of relativeParts) {
|
|
199
|
+
if (part === '..') {
|
|
200
|
+
parts.pop();
|
|
201
|
+
} else if (part !== '.') {
|
|
202
|
+
parts.push(part);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return '/' + parts.join('/');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Fetch and compile a module from absolute path
|
|
211
|
+
*/
|
|
212
|
+
async function loadRelativeModule(
|
|
213
|
+
absolutePath: string,
|
|
214
|
+
baseFilePath: string,
|
|
215
|
+
repoFullName?: string,
|
|
216
|
+
baseRef?: string
|
|
217
|
+
): Promise<any> {
|
|
218
|
+
const cacheKey = `${baseFilePath}:${absolutePath}`;
|
|
219
|
+
if (moduleCache.has(cacheKey)) {
|
|
220
|
+
return moduleCache.get(cacheKey);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Try to determine file extension
|
|
224
|
+
const extensions = ['.jsx', '.tsx', '.js', '.ts'];
|
|
225
|
+
let moduleCode: string | null = null;
|
|
226
|
+
let modulePath: string | null = null;
|
|
227
|
+
|
|
228
|
+
// Try each extension
|
|
229
|
+
for (const ext of extensions) {
|
|
230
|
+
const testPath = absolutePath + (absolutePath.includes('.') ? '' : ext);
|
|
231
|
+
|
|
232
|
+
// Try local first
|
|
233
|
+
try {
|
|
234
|
+
const localRes = await fetch(testPath, {
|
|
235
|
+
method: "GET",
|
|
236
|
+
headers: { Accept: "text/plain" },
|
|
237
|
+
});
|
|
238
|
+
if (localRes.ok) {
|
|
239
|
+
moduleCode = await localRes.text();
|
|
240
|
+
modulePath = testPath;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
} catch {
|
|
244
|
+
// Continue to next extension or GitHub
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Try GitHub if local failed
|
|
248
|
+
if (!moduleCode && repoFullName) {
|
|
249
|
+
try {
|
|
250
|
+
const githubPath = testPath.startsWith('/') ? testPath.substring(1) : testPath;
|
|
251
|
+
const githubUrl = `https://raw.githubusercontent.com/${repoFullName}/${baseRef || 'main'}/${githubPath}`;
|
|
252
|
+
const res = await fetch(githubUrl, { method: "GET", headers: { Accept: "text/plain" } });
|
|
253
|
+
if (res.ok) {
|
|
254
|
+
moduleCode = await res.text();
|
|
255
|
+
modulePath = testPath;
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
} catch {
|
|
259
|
+
// Continue
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (!moduleCode || !modulePath) {
|
|
265
|
+
throw new Error(`Could not resolve module: ${absolutePath} from ${baseFilePath}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Compile the module
|
|
269
|
+
let Babel: any;
|
|
270
|
+
if (typeof window !== "undefined" && (window as any).Babel) {
|
|
271
|
+
Babel = (window as any).Babel;
|
|
272
|
+
} else {
|
|
273
|
+
try {
|
|
274
|
+
// @ts-ignore
|
|
275
|
+
const babelModule = await import("@babel/standalone");
|
|
276
|
+
Babel = babelModule.default || babelModule;
|
|
277
|
+
} catch {
|
|
278
|
+
throw new Error("Babel not available for compiling relative import");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Preprocess module code
|
|
283
|
+
let processedCode = moduleCode;
|
|
284
|
+
processedCode = processedCode.replace(/^import\s+['"].*\.css['"];?\s*$/gm, "");
|
|
285
|
+
processedCode = processedCode.replace(/^import\s+React\s+from\s+['"]react['"];?\s*$/m, "const React = window.React || globalThis.React;");
|
|
286
|
+
processedCode = processedCode.replace(/import\.meta\.env\.[\w$]+/g, "undefined");
|
|
287
|
+
processedCode = processedCode.replace(/\bimport\.meta\b/g, "({})");
|
|
288
|
+
|
|
289
|
+
const isTSX = modulePath.endsWith(".tsx");
|
|
290
|
+
const compiled = Babel.transform(processedCode, {
|
|
291
|
+
presets: [
|
|
292
|
+
["react", { runtime: "classic" }],
|
|
293
|
+
["typescript", { allExtensions: true, isTSX }],
|
|
294
|
+
],
|
|
295
|
+
plugins: [["transform-modules-commonjs", { allowTopLevelThis: true }]],
|
|
296
|
+
sourceType: "module",
|
|
297
|
+
filename: modulePath,
|
|
298
|
+
}).code;
|
|
299
|
+
|
|
300
|
+
// Execute compiled module
|
|
301
|
+
const moduleCodeWrapper = `
|
|
302
|
+
var require = function(name) {
|
|
303
|
+
if (name === "react" || name === "react/jsx-runtime") {
|
|
304
|
+
return window.React || globalThis.React;
|
|
305
|
+
}
|
|
306
|
+
if (name.startsWith("/@vite") || name.includes("@vite/client")) {
|
|
307
|
+
return {};
|
|
308
|
+
}
|
|
309
|
+
throw new Error("Unsupported module in relative import: " + name);
|
|
310
|
+
};
|
|
311
|
+
var module = { exports: {} };
|
|
312
|
+
var exports = module.exports;
|
|
313
|
+
${compiled}
|
|
314
|
+
return module.exports;
|
|
315
|
+
`;
|
|
316
|
+
|
|
317
|
+
const moduleExports = new Function(moduleCodeWrapper)();
|
|
318
|
+
moduleCache.set(cacheKey, moduleExports);
|
|
319
|
+
return moduleExports;
|
|
320
|
+
}
|
|
321
|
+
|
|
207
322
|
export async function loadVariantComponent(
|
|
208
323
|
baseUrl: string,
|
|
209
324
|
proposalId: string,
|
|
210
325
|
experimentId: string,
|
|
211
|
-
filePath: string | null
|
|
326
|
+
filePath: string | null,
|
|
327
|
+
repoFullName?: string,
|
|
328
|
+
baseRef?: string
|
|
212
329
|
): Promise<React.ComponentType<any> | null> {
|
|
213
330
|
if (!filePath) {
|
|
214
331
|
return null;
|
|
@@ -225,29 +342,220 @@ export async function loadVariantComponent(
|
|
|
225
342
|
// Create new load promise
|
|
226
343
|
const loadPromise = (async () => {
|
|
227
344
|
try {
|
|
228
|
-
//
|
|
229
|
-
|
|
345
|
+
// ============================================
|
|
346
|
+
// Hybrid approach: Dynamic import for CSR (Vite), fetch+babel for SSR (Next.js)
|
|
347
|
+
// ============================================
|
|
348
|
+
let code: string = "";
|
|
349
|
+
let rawCode: string = "";
|
|
350
|
+
let rawCodeFetched = false;
|
|
351
|
+
|
|
352
|
+
// Try dynamic import first (works great for Vite/CSR, resolves relative imports automatically)
|
|
353
|
+
// Only attempt in browser and not during Next.js server-side compilation
|
|
354
|
+
const isBrowser = typeof window !== "undefined";
|
|
355
|
+
const isNextJSServer = typeof window === "undefined" ||
|
|
356
|
+
(typeof (globalThis as any).process !== "undefined" && (globalThis as any).process.env?.NEXT_RUNTIME === "nodejs");
|
|
357
|
+
|
|
358
|
+
if (isBrowser && !isNextJSServer) {
|
|
359
|
+
try {
|
|
360
|
+
const variantUrl = `/probat/${filePath}`;
|
|
361
|
+
// Use dynamic import - Vite can resolve relative imports automatically
|
|
362
|
+
const mod = await import(/* @vite-ignore */ variantUrl);
|
|
363
|
+
const VariantComponent = (mod as any)?.default || mod;
|
|
364
|
+
if (VariantComponent && typeof VariantComponent === "function") {
|
|
365
|
+
console.log(`[PROBAT] ✅ Loaded variant via dynamic import (CSR): ${variantUrl}`);
|
|
366
|
+
return VariantComponent as React.ComponentType<any>;
|
|
367
|
+
}
|
|
368
|
+
} catch (dynamicImportError) {
|
|
369
|
+
// Dynamic import failed (might be Next.js or other issue), fall through to fetch+babel
|
|
370
|
+
console.debug(`[PROBAT] Dynamic import failed, using fetch+babel:`, dynamicImportError);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
230
373
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
374
|
+
// Fallback: fetch + babel compilation (works for Next.js SSR and when dynamic import fails)
|
|
375
|
+
const localUrl = `/probat/${filePath}`;
|
|
376
|
+
try {
|
|
377
|
+
const localRes = await fetch(localUrl, {
|
|
378
|
+
method: "GET",
|
|
379
|
+
headers: { Accept: "text/plain" },
|
|
380
|
+
});
|
|
381
|
+
if (localRes.ok) {
|
|
382
|
+
rawCode = await localRes.text();
|
|
383
|
+
rawCodeFetched = true;
|
|
384
|
+
console.log(`[PROBAT] ✅ Loaded variant from local (user's repo): ${localUrl}`);
|
|
385
|
+
}
|
|
386
|
+
} catch {
|
|
387
|
+
console.debug(`[PROBAT] Local file not available (${localUrl}), trying GitHub...`);
|
|
388
|
+
}
|
|
236
389
|
|
|
237
|
-
if (!
|
|
238
|
-
|
|
390
|
+
if (!rawCodeFetched && repoFullName) {
|
|
391
|
+
const githubPath = `probat/${filePath}`;
|
|
392
|
+
const gitRef = baseRef || "main";
|
|
393
|
+
const githubUrl = `https://raw.githubusercontent.com/${repoFullName}/${gitRef}/${githubPath}`;
|
|
394
|
+
const res = await fetch(githubUrl, { method: "GET", headers: { Accept: "text/plain" } });
|
|
395
|
+
if (res.ok) {
|
|
396
|
+
rawCode = await res.text();
|
|
397
|
+
rawCodeFetched = true;
|
|
398
|
+
console.log(`[PROBAT] ⚠️ Loaded variant from GitHub (fallback): ${githubUrl}`);
|
|
399
|
+
} else {
|
|
400
|
+
console.warn(`[PROBAT] ⚠️ GitHub fetch failed (${res.status}), falling back to server compilation`);
|
|
401
|
+
}
|
|
239
402
|
}
|
|
240
403
|
|
|
241
|
-
|
|
404
|
+
if (rawCodeFetched && rawCode) {
|
|
405
|
+
let Babel: any;
|
|
406
|
+
if (typeof window !== "undefined" && (window as any).Babel) {
|
|
407
|
+
Babel = (window as any).Babel;
|
|
408
|
+
} else {
|
|
409
|
+
try {
|
|
410
|
+
// @ts-ignore
|
|
411
|
+
const babelModule = await import("@babel/standalone");
|
|
412
|
+
Babel = babelModule.default || babelModule;
|
|
413
|
+
} catch (importError) {
|
|
414
|
+
try {
|
|
415
|
+
await new Promise<void>((resolve, reject) => {
|
|
416
|
+
if (typeof document === "undefined") {
|
|
417
|
+
reject(new Error("Document not available"));
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if ((window as any).Babel) {
|
|
421
|
+
Babel = (window as any).Babel;
|
|
422
|
+
resolve();
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const script = document.createElement("script");
|
|
426
|
+
script.src = "https://unpkg.com/@babel/standalone/babel.min.js";
|
|
427
|
+
script.async = true;
|
|
428
|
+
script.onload = () => {
|
|
429
|
+
Babel = (window as any).Babel;
|
|
430
|
+
if (!Babel) reject(new Error("Babel not found after script load"));
|
|
431
|
+
else resolve();
|
|
432
|
+
};
|
|
433
|
+
script.onerror = () => reject(new Error("Failed to load Babel from CDN"));
|
|
434
|
+
document.head.appendChild(script);
|
|
435
|
+
});
|
|
436
|
+
} catch (babelError) {
|
|
437
|
+
console.error("[PROBAT] Failed to load Babel, falling back to server compilation", babelError);
|
|
438
|
+
rawCodeFetched = false;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (rawCodeFetched && rawCode && Babel) {
|
|
444
|
+
const isTSX = filePath.endsWith(".tsx");
|
|
445
|
+
rawCode = rawCode.replace(/^import\s+['"].*\.css['"];?\s*$/gm, "");
|
|
446
|
+
rawCode = rawCode.replace(/^import\s+.*from\s+['"].*\.css['"];?\s*$/gm, "");
|
|
447
|
+
rawCode = rawCode.replace(
|
|
448
|
+
/^import\s+React(?:\s*,\s*\{[^}]*\})?\s+from\s+['"]react['"];?\s*$/m,
|
|
449
|
+
"const React = window.React || globalThis.React;"
|
|
450
|
+
);
|
|
451
|
+
rawCode = rawCode.replace(
|
|
452
|
+
/^import\s+\*\s+as\s+React\s+from\s+['"]react['"];?\s*$/m,
|
|
453
|
+
"const React = window.React || globalThis.React;"
|
|
454
|
+
);
|
|
455
|
+
rawCode = rawCode.replace(
|
|
456
|
+
/^import\s+\{([^}]+)\}\s+from\s+['"]react['"];?\s*$/m,
|
|
457
|
+
(match, imports) => `const {${imports}} = window.React || globalThis.React;`
|
|
458
|
+
);
|
|
459
|
+
rawCode = rawCode.replace(/import\.meta\.env\.[\w$]+/g, "undefined");
|
|
460
|
+
rawCode = rawCode.replace(/\bimport\.meta\b/g, "({})");
|
|
461
|
+
rawCode = rawCode.replace(/^import\s+.*\/@vite\/client.*$/gm, "");
|
|
462
|
+
rawCode = rawCode.replace(/import\.meta\.hot(?:\.[\w$]+)*/g, "undefined");
|
|
463
|
+
|
|
464
|
+
// Preprocess relative imports: convert to absolute paths that can be fetched
|
|
465
|
+
// This allows the require shim to fetch them later
|
|
466
|
+
const relativeImportMap = new Map<string, string>();
|
|
467
|
+
rawCode = rawCode.replace(
|
|
468
|
+
/^import\s+(\w+)\s+from\s+['"](\.\.?\/[^'"]+)['"];?\s*$/gm,
|
|
469
|
+
(match, importName, relativePath) => {
|
|
470
|
+
// Resolve relative path to absolute
|
|
471
|
+
const baseDir = filePath.substring(0, filePath.lastIndexOf('/'));
|
|
472
|
+
const resolvedPath = resolveRelativePath(relativePath, baseDir);
|
|
473
|
+
// Try to find the file with extension
|
|
474
|
+
const absolutePath = resolvedPath.startsWith('/') ? resolvedPath : '/' + resolvedPath;
|
|
475
|
+
relativeImportMap.set(importName, absolutePath);
|
|
476
|
+
// Replace with absolute path import - Babel will compile this to require()
|
|
477
|
+
return `import ${importName} from "${absolutePath}";`;
|
|
478
|
+
}
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
const compiled = Babel.transform(rawCode, {
|
|
482
|
+
presets: [
|
|
483
|
+
["react", { runtime: "classic" }],
|
|
484
|
+
["typescript", { allExtensions: true, isTSX }],
|
|
485
|
+
],
|
|
486
|
+
plugins: [["transform-modules-commonjs", { allowTopLevelThis: true }]],
|
|
487
|
+
sourceType: "module",
|
|
488
|
+
filename: filePath,
|
|
489
|
+
}).code;
|
|
490
|
+
|
|
491
|
+
// Pre-load relative imports if any
|
|
492
|
+
const relativeModules: Record<string, any> = {};
|
|
493
|
+
if (relativeImportMap.size > 0) {
|
|
494
|
+
for (const [importName, absolutePath] of relativeImportMap.entries()) {
|
|
495
|
+
try {
|
|
496
|
+
const moduleExports = await loadRelativeModule(absolutePath, filePath, repoFullName, baseRef);
|
|
497
|
+
relativeModules[absolutePath] = moduleExports.default || moduleExports;
|
|
498
|
+
} catch (err) {
|
|
499
|
+
console.warn(`[PROBAT] Failed to load relative import ${absolutePath}:`, err);
|
|
500
|
+
relativeModules[absolutePath] = null;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Build require shim that can resolve relative imports
|
|
506
|
+
const relativeModulesJson = JSON.stringify(relativeModules);
|
|
507
|
+
code = `
|
|
508
|
+
var __probatVariant = (function() {
|
|
509
|
+
var relativeModules = ${relativeModulesJson};
|
|
510
|
+
var require = function(name) {
|
|
511
|
+
if (name === "react" || name === "react/jsx-runtime") {
|
|
512
|
+
return window.React || globalThis.React;
|
|
513
|
+
}
|
|
514
|
+
if (name.startsWith("/@vite") || name.includes("@vite/client") || name.includes(".vite/deps")) {
|
|
515
|
+
return {};
|
|
516
|
+
}
|
|
517
|
+
if (name === "react/jsx-runtime.js") {
|
|
518
|
+
return window.React || globalThis.React;
|
|
519
|
+
}
|
|
520
|
+
// Handle relative imports (now converted to absolute paths)
|
|
521
|
+
if (name.startsWith("/") && relativeModules.hasOwnProperty(name)) {
|
|
522
|
+
var mod = relativeModules[name];
|
|
523
|
+
if (mod === null) {
|
|
524
|
+
throw new Error("Failed to load module: " + name);
|
|
525
|
+
}
|
|
526
|
+
return mod;
|
|
527
|
+
}
|
|
528
|
+
throw new Error("Unsupported module: " + name);
|
|
529
|
+
};
|
|
530
|
+
var module = { exports: {} };
|
|
531
|
+
var exports = module.exports;
|
|
532
|
+
${compiled}
|
|
533
|
+
return module.exports.default || module.exports;
|
|
534
|
+
})();
|
|
535
|
+
`;
|
|
536
|
+
} else {
|
|
537
|
+
rawCodeFetched = false;
|
|
538
|
+
code = "";
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (!rawCodeFetched || code === "") {
|
|
543
|
+
const variantUrl = `${baseUrl.replace(/\/$/, "")}/variants/${filePath}`;
|
|
544
|
+
const serverRes = await fetch(variantUrl, {
|
|
545
|
+
method: "GET",
|
|
546
|
+
headers: { Accept: "text/javascript" },
|
|
547
|
+
credentials: "include",
|
|
548
|
+
});
|
|
549
|
+
if (!serverRes.ok) {
|
|
550
|
+
throw new Error(`HTTP ${serverRes.status}`);
|
|
551
|
+
}
|
|
552
|
+
code = await serverRes.text();
|
|
553
|
+
}
|
|
242
554
|
|
|
243
|
-
// The server returns an IIFE that assigns to __probatVariant
|
|
244
|
-
// Execute the code to get the component
|
|
245
|
-
// First, ensure React is available globally
|
|
246
555
|
if (typeof window !== "undefined") {
|
|
247
556
|
(window as any).React = (window as any).React || React;
|
|
248
557
|
}
|
|
249
558
|
|
|
250
|
-
// Execute the IIFE code
|
|
251
559
|
const evalFunc = new Function(`
|
|
252
560
|
var __probatVariant;
|
|
253
561
|
${code}
|
|
@@ -255,10 +563,7 @@ export async function loadVariantComponent(
|
|
|
255
563
|
`);
|
|
256
564
|
|
|
257
565
|
const result = evalFunc();
|
|
258
|
-
|
|
259
|
-
// The result is { default: Component } from esbuild's IIFE output
|
|
260
566
|
const VariantComponent = result?.default || result;
|
|
261
|
-
|
|
262
567
|
if (typeof VariantComponent === "function") {
|
|
263
568
|
return VariantComponent as React.ComponentType<any>;
|
|
264
569
|
}
|