remote-components 0.3.4 → 0.3.5

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.
Files changed (42) hide show
  1. package/dist/host/html.cjs +471 -413
  2. package/dist/host/html.cjs.map +1 -1
  3. package/dist/host/html.js +471 -413
  4. package/dist/host/html.js.map +1 -1
  5. package/dist/host/nextjs/app/client-only.cjs +245 -131
  6. package/dist/host/nextjs/app/client-only.cjs.map +1 -1
  7. package/dist/host/nextjs/app/client-only.js +245 -131
  8. package/dist/host/nextjs/app/client-only.js.map +1 -1
  9. package/dist/host/nextjs/app.cjs +34 -2
  10. package/dist/host/nextjs/app.cjs.map +1 -1
  11. package/dist/host/nextjs/app.js +35 -3
  12. package/dist/host/nextjs/app.js.map +1 -1
  13. package/dist/host/react.cjs +245 -131
  14. package/dist/host/react.cjs.map +1 -1
  15. package/dist/host/react.js +245 -131
  16. package/dist/host/react.js.map +1 -1
  17. package/dist/internal/host/nextjs/app-client.cjs +38 -24
  18. package/dist/internal/host/nextjs/app-client.cjs.map +1 -1
  19. package/dist/internal/host/nextjs/app-client.js +38 -24
  20. package/dist/internal/host/nextjs/app-client.js.map +1 -1
  21. package/dist/internal/host/nextjs/remote-component-links.cjs +24 -13
  22. package/dist/internal/host/nextjs/remote-component-links.cjs.map +1 -1
  23. package/dist/internal/host/nextjs/remote-component-links.d.ts +3 -0
  24. package/dist/internal/host/nextjs/remote-component-links.js +24 -13
  25. package/dist/internal/host/nextjs/remote-component-links.js.map +1 -1
  26. package/dist/internal/host/shared/lifecycle.cjs +69 -0
  27. package/dist/internal/host/shared/lifecycle.cjs.map +1 -0
  28. package/dist/internal/host/shared/lifecycle.d.ts +34 -0
  29. package/dist/internal/host/shared/lifecycle.js +44 -0
  30. package/dist/internal/host/shared/lifecycle.js.map +1 -0
  31. package/dist/internal/host/shared/pipeline.cjs +222 -0
  32. package/dist/internal/host/shared/pipeline.cjs.map +1 -0
  33. package/dist/internal/host/shared/pipeline.d.ts +153 -0
  34. package/dist/internal/host/shared/pipeline.js +200 -0
  35. package/dist/internal/host/shared/pipeline.js.map +1 -0
  36. package/dist/internal/runtime/turbopack/patterns.cjs +1 -1
  37. package/dist/internal/runtime/turbopack/patterns.cjs.map +1 -1
  38. package/dist/internal/runtime/turbopack/patterns.js +1 -1
  39. package/dist/internal/runtime/turbopack/patterns.js.map +1 -1
  40. package/dist/internal/runtime/turbopack/remote-scope-setup.cjs.map +1 -1
  41. package/dist/internal/runtime/turbopack/remote-scope-setup.js.map +1 -1
  42. package/package.json +2 -2
@@ -543,6 +543,24 @@ function getClientOrServerUrl(src, serverFallback) {
543
543
  return typeof src === "string" ? new URL(src, fallback) : src;
544
544
  }
545
545
 
546
+ // src/host/shared/lifecycle.ts
547
+ function makeReactEmitter(callbacks) {
548
+ return {
549
+ beforeLoad(src) {
550
+ callbacks.onBeforeLoad?.(src);
551
+ },
552
+ load(src) {
553
+ callbacks.onLoad?.(src);
554
+ },
555
+ error(error, _src) {
556
+ callbacks.onError?.(error);
557
+ },
558
+ change(info) {
559
+ callbacks.onChange?.(info);
560
+ }
561
+ };
562
+ }
563
+
546
564
  // src/host/shared/polyfill.tsx
547
565
  var import_jsx_runtime = require("react/jsx-runtime");
548
566
  function sharedPolyfills(shared2, resolveClientUrl) {
@@ -748,32 +766,6 @@ async function buildWebpackResolve(hostShared, remoteShared, bundle, reactModule
748
766
  return resolve;
749
767
  }
750
768
 
751
- // src/host/shared/state.ts
752
- function createHostState() {
753
- return {
754
- stage: "idle",
755
- prevSrc: void 0,
756
- prevUrl: void 0,
757
- prevName: void 0,
758
- prevIsRemoteComponent: false,
759
- abortController: void 0
760
- };
761
- }
762
-
763
- // src/host/utils/resolve-name-from-src.ts
764
- function resolveNameFromSrc(src, defaultName) {
765
- if (!src) {
766
- return defaultName;
767
- }
768
- const hash = typeof src === "string" ? src : src.hash;
769
- const hashIndex = hash.indexOf("#");
770
- if (hashIndex < 0) {
771
- return defaultName;
772
- }
773
- const name = hash.slice(hashIndex + 1);
774
- return name || defaultName;
775
- }
776
-
777
769
  // src/runtime/html/html-spec.ts
778
770
  var ORIGIN_REWRITE_TAGS = [
779
771
  "img",
@@ -976,48 +968,6 @@ function parseRemoteComponentDocument(doc, name, url) {
976
968
  };
977
969
  }
978
970
 
979
- // src/runtime/html/set-attributes-from-props.ts
980
- var DOMAttributeNames = {
981
- acceptCharset: "accept-charset",
982
- className: "class",
983
- htmlFor: "for",
984
- httpEquiv: "http-equiv",
985
- noModule: "noModule"
986
- };
987
- var ignoreProps = [
988
- "onLoad",
989
- "onReady",
990
- "dangerouslySetInnerHTML",
991
- "children",
992
- "onError",
993
- "strategy",
994
- "stylesheets"
995
- ];
996
- function isBooleanScriptAttribute(attr) {
997
- return ["async", "defer", "noModule"].includes(attr);
998
- }
999
- function setAttributesFromProps(el, props) {
1000
- for (const [p, value] of Object.entries(props)) {
1001
- if (!Object.hasOwn(props, p))
1002
- continue;
1003
- if (ignoreProps.includes(p))
1004
- continue;
1005
- if (value === void 0) {
1006
- continue;
1007
- }
1008
- const attr = DOMAttributeNames[p] || p.toLowerCase();
1009
- if (el.tagName === "SCRIPT" && isBooleanScriptAttribute(attr)) {
1010
- el[attr] = Boolean(value);
1011
- } else {
1012
- el.setAttribute(attr, String(value));
1013
- }
1014
- if (value === false || el.tagName === "SCRIPT" && isBooleanScriptAttribute(attr) && (!value || value === "false")) {
1015
- el.setAttribute(attr, "");
1016
- el.removeAttribute(attr);
1017
- }
1018
- }
1019
- }
1020
-
1021
971
  // src/runtime/loaders/component-loader.ts
1022
972
  var React = __toESM(require("react"), 1);
1023
973
  var JSXDevRuntime = __toESM(require("react/jsx-dev-runtime"), 1);
@@ -1298,7 +1248,7 @@ var REMOTE_SHARED_ASSIGNMENT_RE = new RegExp(
1298
1248
  `\\.TURBOPACK_REMOTE_SHARED\\s*=\\s*await (?:__turbopack_context__|[a-z])\\.A\\((?<sharedModuleId>${MODULE_ID_PATTERN})\\)`
1299
1249
  );
1300
1250
  var ASYNC_MODULE_LOADER_RE = new RegExp(
1301
- `(?:__turbopack_context__|e)\\.A\\((?<asyncSharedModuleId>${MODULE_ID_PATTERN})\\)`
1251
+ `(?:__turbopack_context__|[a-z])\\.A\\((?<asyncSharedModuleId>${MODULE_ID_PATTERN})\\)`
1302
1252
  );
1303
1253
  var ASYNC_MODULE_CALLBACK_RE = new RegExp(
1304
1254
  `(?:parentImport|[a-z])\\((?<sharedModuleId>${MODULE_ID_PATTERN})\\)`
@@ -2257,6 +2207,188 @@ async function loadStaticRemoteComponent(scripts, url, resolveClientUrl) {
2257
2207
  );
2258
2208
  }
2259
2209
 
2210
+ // src/host/shared/pipeline.ts
2211
+ function preparePipeline(input) {
2212
+ const parser = new DOMParser();
2213
+ const doc = parser.parseFromString(input.html, "text/html");
2214
+ const parsed = parseRemoteComponentDocument(doc, input.name, input.url);
2215
+ const remoteShared = input.remoteShared ?? parsed.remoteShared;
2216
+ if ("__remote_components_missing_shared__" in remoteShared) {
2217
+ throw new RemoteComponentsError(
2218
+ remoteShared.__remote_components_missing_shared__
2219
+ );
2220
+ }
2221
+ applyOriginToNodes(doc, input.url, input.resolveClientUrl);
2222
+ const scriptDescriptors = buildScriptDescriptors(parsed.scripts, input.url);
2223
+ return { doc, parsed, scriptDescriptors };
2224
+ }
2225
+ async function loadPrepared(input) {
2226
+ const { prepared, url, signal, resolveClientUrl, container, rscName } = input;
2227
+ const { doc, parsed, scriptDescriptors } = prepared;
2228
+ if (signal.aborted) {
2229
+ return { status: "aborted" };
2230
+ }
2231
+ const userShared = await input.shared;
2232
+ if (signal.aborted) {
2233
+ return { status: "aborted" };
2234
+ }
2235
+ if (parsed.isRemoteComponent) {
2236
+ return loadStaticPath({
2237
+ parsed,
2238
+ doc,
2239
+ url,
2240
+ resolveClientUrl
2241
+ });
2242
+ }
2243
+ return loadDynamicPath({
2244
+ parsed,
2245
+ doc,
2246
+ url,
2247
+ scriptDescriptors,
2248
+ shared: userShared,
2249
+ resolveClientUrl,
2250
+ container,
2251
+ rscName
2252
+ });
2253
+ }
2254
+ function buildScriptDescriptors(scripts, url) {
2255
+ return scripts.map((script) => {
2256
+ const scriptSrc = script.getAttribute("data-src") || script.getAttribute("src") || script.src;
2257
+ const { prefix, id: path } = REMOTE_COMPONENT_REGEX.exec(scriptSrc)?.groups ?? {
2258
+ prefix: void 0,
2259
+ id: scriptSrc
2260
+ };
2261
+ return {
2262
+ src: new URL(collapseDoubleSlashes(`${prefix ?? ""}${path}`), url).href
2263
+ };
2264
+ });
2265
+ }
2266
+ async function loadStaticPath(input) {
2267
+ const { parsed, doc, url, resolveClientUrl } = input;
2268
+ const scripts = Array.from(
2269
+ parsed.component.querySelectorAll("script")
2270
+ );
2271
+ const { mount, unmount } = await loadStaticRemoteComponent(
2272
+ scripts,
2273
+ url,
2274
+ resolveClientUrl
2275
+ );
2276
+ return {
2277
+ status: "static",
2278
+ mount,
2279
+ unmount,
2280
+ metadata: parsed.metadata,
2281
+ parsed,
2282
+ doc
2283
+ };
2284
+ }
2285
+ async function loadDynamicPath(input) {
2286
+ const {
2287
+ parsed,
2288
+ doc,
2289
+ url,
2290
+ scriptDescriptors,
2291
+ shared: shared2,
2292
+ resolveClientUrl,
2293
+ container
2294
+ } = input;
2295
+ const rscName = input.rscName ?? (parsed.rsc ? `__remote_component_rsc_${escapeString(url.href)}_${escapeString(parsed.name)}` : void 0);
2296
+ const rscData = parsed.rsc ? (parsed.rsc.textContent || "").split("\n").filter(Boolean) : [];
2297
+ const result = await loadRemoteComponent({
2298
+ url,
2299
+ name: parsed.name,
2300
+ rscName,
2301
+ bundle: parsed.metadata.bundle,
2302
+ route: parsed.metadata.route,
2303
+ runtime: parsed.metadata.runtime,
2304
+ data: rscData,
2305
+ nextData: parsed.nextData,
2306
+ scripts: scriptDescriptors,
2307
+ shared: buildHostShared(shared2, resolveClientUrl),
2308
+ remoteShared: parsed.remoteShared,
2309
+ container,
2310
+ resolveClientUrl
2311
+ });
2312
+ if (result.error) {
2313
+ return { status: "error", error: result.error };
2314
+ }
2315
+ return {
2316
+ status: "loaded",
2317
+ component: result.component,
2318
+ metadata: parsed.metadata,
2319
+ parsed,
2320
+ doc
2321
+ };
2322
+ }
2323
+
2324
+ // src/host/shared/state.ts
2325
+ function createHostState() {
2326
+ return {
2327
+ stage: "idle",
2328
+ prevSrc: void 0,
2329
+ prevUrl: void 0,
2330
+ prevName: void 0,
2331
+ prevIsRemoteComponent: false,
2332
+ abortController: void 0
2333
+ };
2334
+ }
2335
+
2336
+ // src/host/utils/resolve-name-from-src.ts
2337
+ function resolveNameFromSrc(src, defaultName) {
2338
+ if (!src) {
2339
+ return defaultName;
2340
+ }
2341
+ const hash = typeof src === "string" ? src : src.hash;
2342
+ const hashIndex = hash.indexOf("#");
2343
+ if (hashIndex < 0) {
2344
+ return defaultName;
2345
+ }
2346
+ const name = hash.slice(hashIndex + 1);
2347
+ return name || defaultName;
2348
+ }
2349
+
2350
+ // src/runtime/html/set-attributes-from-props.ts
2351
+ var DOMAttributeNames = {
2352
+ acceptCharset: "accept-charset",
2353
+ className: "class",
2354
+ htmlFor: "for",
2355
+ httpEquiv: "http-equiv",
2356
+ noModule: "noModule"
2357
+ };
2358
+ var ignoreProps = [
2359
+ "onLoad",
2360
+ "onReady",
2361
+ "dangerouslySetInnerHTML",
2362
+ "children",
2363
+ "onError",
2364
+ "strategy",
2365
+ "stylesheets"
2366
+ ];
2367
+ function isBooleanScriptAttribute(attr) {
2368
+ return ["async", "defer", "noModule"].includes(attr);
2369
+ }
2370
+ function setAttributesFromProps(el, props) {
2371
+ for (const [p, value] of Object.entries(props)) {
2372
+ if (!Object.hasOwn(props, p))
2373
+ continue;
2374
+ if (ignoreProps.includes(p))
2375
+ continue;
2376
+ if (value === void 0) {
2377
+ continue;
2378
+ }
2379
+ const attr = DOMAttributeNames[p] || p.toLowerCase();
2380
+ if (el.tagName === "SCRIPT" && isBooleanScriptAttribute(attr)) {
2381
+ el[attr] = Boolean(value);
2382
+ } else {
2383
+ el.setAttribute(attr, String(value));
2384
+ }
2385
+ if (value === false || el.tagName === "SCRIPT" && isBooleanScriptAttribute(attr) && (!value || value === "false")) {
2386
+ el.setAttribute(attr, "");
2387
+ el.removeAttribute(attr);
2388
+ }
2389
+ }
2390
+ }
2391
+
2260
2392
  // src/host/react/hooks/use-resolve-client-url.ts
2261
2393
  var import_react2 = require("react");
2262
2394
  var import_context = require("#internal/host/react/context");
@@ -2360,6 +2492,10 @@ function ConsumeRemoteComponent({
2360
2492
  const { credentials: contextCredentials, shared: contextShared } = (0, import_context2.useRemoteComponentsContext)();
2361
2493
  const credentials = credentialsProp ?? contextCredentials ?? "same-origin";
2362
2494
  const shared2 = sharedProp ?? contextShared ?? {};
2495
+ const emitter = (0, import_react4.useMemo)(
2496
+ () => makeReactEmitter({ onBeforeLoad, onLoad, onError, onChange }),
2497
+ [onBeforeLoad, onLoad, onError, onChange]
2498
+ );
2363
2499
  const name = (0, import_react4.useMemo)(
2364
2500
  () => resolveNameFromSrc(src, nameProp),
2365
2501
  [src, nameProp]
@@ -2449,7 +2585,7 @@ function ConsumeRemoteComponent({
2449
2585
  hostStateRef.current.abortController?.abort();
2450
2586
  hostStateRef.current.abortController = new AbortController();
2451
2587
  const { signal } = hostStateRef.current.abortController;
2452
- onBeforeLoad?.(src);
2588
+ emitter.beforeLoad(src);
2453
2589
  hostStateRef.current.stage = "loading";
2454
2590
  (0, import_react4.startTransition)(async () => {
2455
2591
  try {
@@ -2480,19 +2616,26 @@ function ConsumeRemoteComponent({
2480
2616
  }
2481
2617
  if (signal.aborted)
2482
2618
  return;
2483
- const parser = new DOMParser();
2484
- const doc = parser.parseFromString(html, "text/html");
2619
+ const userShared = await shared2;
2620
+ if (signal.aborted)
2621
+ return;
2622
+ const prepared = preparePipeline({
2623
+ html,
2624
+ name,
2625
+ url,
2626
+ shared: userShared,
2627
+ resolveClientUrl
2628
+ });
2629
+ const { doc, parsed } = prepared;
2485
2630
  const {
2486
2631
  component,
2487
2632
  name: remoteName,
2488
2633
  isRemoteComponent,
2489
2634
  metadata,
2490
- nextData,
2491
2635
  rsc,
2492
2636
  remoteShared,
2493
- links: linkElements,
2494
- scripts: scriptElements
2495
- } = parseRemoteComponentDocument(doc, name, url);
2637
+ links: linkElements
2638
+ } = parsed;
2496
2639
  if (hostStateRef.current.prevIsRemoteComponent) {
2497
2640
  if (shadowRoot) {
2498
2641
  shadowRoot.innerHTML = "";
@@ -2513,7 +2656,6 @@ function ConsumeRemoteComponent({
2513
2656
  hostStateRef.current.prevIsRemoteComponent = isRemoteComponent;
2514
2657
  hostStateRef.current.prevUrl = url;
2515
2658
  hostStateRef.current.prevName = remoteName;
2516
- applyOriginToNodes(doc, url, resolveClientUrl);
2517
2659
  const links = linkElements.map((link) => ({
2518
2660
  href: new URL(link.getAttribute("href") ?? link.href, url).href,
2519
2661
  ...link.getAttributeNames().reduce((acc, key) => {
@@ -2523,7 +2665,6 @@ function ConsumeRemoteComponent({
2523
2665
  return acc;
2524
2666
  }, {})
2525
2667
  }));
2526
- const scripts = scriptElements;
2527
2668
  const inlineScripts = (isRemoteComponent ? component : doc).querySelectorAll(
2528
2669
  "script:not([src]):not([data-src]):not([id*='_rsc']):not([id='__NEXT_DATA__']):not([id='__REMOTE_NEXT_DATA__'])"
2529
2670
  );
@@ -2602,20 +2743,10 @@ function ConsumeRemoteComponent({
2602
2743
  componentHydrationHtml.current = `${Array.from(
2603
2744
  doc.querySelectorAll("link,style")
2604
2745
  ).map((link) => link.outerHTML).join("")}${reset ? `<style data-remote-components-reset="">:host { all: initial; }</style>` : ""}${component.innerHTML}`;
2605
- const userShared = await shared2;
2606
- if ("__remote_components_missing_shared__" in userShared) {
2607
- userShared.__remote_components_missing_shared__().catch((e) => {
2608
- throw e;
2609
- });
2610
- } else if ("__remote_components_missing_shared__" in remoteShared) {
2611
- throw new RemoteComponentsError(
2612
- remoteShared.__remote_components_missing_shared__
2613
- );
2614
- }
2615
2746
  if (isRemoteComponent) {
2616
2747
  if (previousSrc !== void 0) {
2617
- onChange?.({
2618
- previousSrc,
2748
+ emitter.change({
2749
+ previousSrc: previousSrc ?? null,
2619
2750
  nextSrc: src,
2620
2751
  previousName,
2621
2752
  nextName: remoteName
@@ -2636,7 +2767,7 @@ function ConsumeRemoteComponent({
2636
2767
  await Promise.all(
2637
2768
  Array.from(mount).map((mountFn) => mountFn(shadowRoot))
2638
2769
  );
2639
- onLoad?.(src);
2770
+ emitter.load(src);
2640
2771
  } else if (isolate === false) {
2641
2772
  setRemoteComponent(
2642
2773
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
@@ -2659,59 +2790,42 @@ function ConsumeRemoteComponent({
2659
2790
  (mountFn) => mountFn(prevRemoteComponentContainerRef.current)
2660
2791
  )
2661
2792
  );
2662
- onLoad?.(src);
2793
+ emitter.load(src);
2663
2794
  }
2664
2795
  hostStateRef.current.stage = "loaded";
2665
2796
  } else {
2666
- const result = await loadRemoteComponent({
2797
+ const result = await loadPrepared({
2798
+ prepared,
2667
2799
  url,
2668
- name: remoteName,
2669
- rscName,
2670
- bundle: metadata.bundle,
2671
- route: metadata.route,
2672
- runtime: metadata.runtime,
2673
- data: newData.data,
2674
- nextData,
2675
- scripts: Array.from(scripts).map((script) => {
2676
- const scriptSrc = script.getAttribute("data-src") || script.getAttribute("src") || script.src;
2677
- const { prefix, id: path } = REMOTE_COMPONENT_REGEX.exec(
2678
- scriptSrc
2679
- )?.groups ?? {
2680
- prefix: void 0,
2681
- id: scriptSrc
2682
- };
2683
- return {
2684
- src: new URL(
2685
- collapseDoubleSlashes(`${prefix ?? ""}${path}`),
2686
- url
2687
- ).href
2688
- };
2689
- }),
2690
- shared: buildHostShared(userShared, resolveClientUrl),
2691
- remoteShared,
2800
+ signal,
2801
+ shared: userShared,
2802
+ resolveClientUrl,
2692
2803
  container: shadowRoot,
2693
- resolveClientUrl
2804
+ rscName
2694
2805
  });
2695
2806
  if (rsc) {
2696
2807
  rsc.remove();
2697
2808
  }
2698
2809
  setData(newData);
2699
2810
  if (previousSrc !== void 0) {
2700
- onChange?.({
2701
- previousSrc,
2811
+ emitter.change({
2812
+ previousSrc: previousSrc ?? null,
2702
2813
  nextSrc: src,
2703
2814
  previousName,
2704
2815
  nextName: remoteName
2705
2816
  });
2706
2817
  }
2707
- if (result.error) {
2818
+ if (result.status === "aborted") {
2819
+ return;
2820
+ }
2821
+ if (result.status === "error") {
2708
2822
  hostStateRef.current.stage = "error";
2709
2823
  setRemoteComponent(result.error);
2710
- onError?.(result.error);
2711
- } else {
2824
+ emitter.error(result.error);
2825
+ } else if (result.status === "loaded") {
2712
2826
  hostStateRef.current.stage = "loaded";
2713
2827
  setRemoteComponent(result.component);
2714
- onLoad?.(src);
2828
+ emitter.load(src);
2715
2829
  }
2716
2830
  }
2717
2831
  } catch (error) {
@@ -2721,7 +2835,7 @@ function ConsumeRemoteComponent({
2721
2835
  }
2722
2836
  hostStateRef.current.stage = "error";
2723
2837
  setRemoteComponent(error);
2724
- onError?.(error);
2838
+ emitter.error(error);
2725
2839
  }
2726
2840
  });
2727
2841
  }
@@ -2735,10 +2849,10 @@ function ConsumeRemoteComponent({
2735
2849
  shadowRoot,
2736
2850
  reset,
2737
2851
  id,
2738
- onBeforeLoad,
2739
- onLoad,
2740
- onError,
2741
- onChange,
2852
+ emitter.beforeLoad,
2853
+ emitter.load,
2854
+ emitter.error,
2855
+ emitter.change,
2742
2856
  onRequest,
2743
2857
  onResponse,
2744
2858
  resolveClientUrl
@@ -2780,7 +2894,7 @@ function ConsumeRemoteComponent({
2780
2894
  );
2781
2895
  }).then(() => {
2782
2896
  if (src) {
2783
- onLoad?.(src);
2897
+ emitter.load(src);
2784
2898
  }
2785
2899
  }).catch((e) => {
2786
2900
  const error = new RemoteComponentsError(
@@ -2790,7 +2904,7 @@ function ConsumeRemoteComponent({
2790
2904
  }
2791
2905
  );
2792
2906
  setRemoteComponent(error);
2793
- onError?.(error);
2907
+ emitter.error(error);
2794
2908
  });
2795
2909
  }
2796
2910
  }