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
@@ -523,6 +523,24 @@ function getClientOrServerUrl(src, serverFallback) {
523
523
  return typeof src === "string" ? new URL(src, fallback) : src;
524
524
  }
525
525
 
526
+ // src/host/shared/lifecycle.ts
527
+ function makeReactEmitter(callbacks) {
528
+ return {
529
+ beforeLoad(src) {
530
+ callbacks.onBeforeLoad?.(src);
531
+ },
532
+ load(src) {
533
+ callbacks.onLoad?.(src);
534
+ },
535
+ error(error, _src) {
536
+ callbacks.onError?.(error);
537
+ },
538
+ change(info) {
539
+ callbacks.onChange?.(info);
540
+ }
541
+ };
542
+ }
543
+
526
544
  // src/host/shared/polyfill.tsx
527
545
  import { jsx } from "react/jsx-runtime";
528
546
  function sharedPolyfills(shared2, resolveClientUrl) {
@@ -728,32 +746,6 @@ async function buildWebpackResolve(hostShared, remoteShared, bundle, reactModule
728
746
  return resolve;
729
747
  }
730
748
 
731
- // src/host/shared/state.ts
732
- function createHostState() {
733
- return {
734
- stage: "idle",
735
- prevSrc: void 0,
736
- prevUrl: void 0,
737
- prevName: void 0,
738
- prevIsRemoteComponent: false,
739
- abortController: void 0
740
- };
741
- }
742
-
743
- // src/host/utils/resolve-name-from-src.ts
744
- function resolveNameFromSrc(src, defaultName) {
745
- if (!src) {
746
- return defaultName;
747
- }
748
- const hash = typeof src === "string" ? src : src.hash;
749
- const hashIndex = hash.indexOf("#");
750
- if (hashIndex < 0) {
751
- return defaultName;
752
- }
753
- const name = hash.slice(hashIndex + 1);
754
- return name || defaultName;
755
- }
756
-
757
749
  // src/runtime/html/html-spec.ts
758
750
  var ORIGIN_REWRITE_TAGS = [
759
751
  "img",
@@ -956,48 +948,6 @@ function parseRemoteComponentDocument(doc, name, url) {
956
948
  };
957
949
  }
958
950
 
959
- // src/runtime/html/set-attributes-from-props.ts
960
- var DOMAttributeNames = {
961
- acceptCharset: "accept-charset",
962
- className: "class",
963
- htmlFor: "for",
964
- httpEquiv: "http-equiv",
965
- noModule: "noModule"
966
- };
967
- var ignoreProps = [
968
- "onLoad",
969
- "onReady",
970
- "dangerouslySetInnerHTML",
971
- "children",
972
- "onError",
973
- "strategy",
974
- "stylesheets"
975
- ];
976
- function isBooleanScriptAttribute(attr) {
977
- return ["async", "defer", "noModule"].includes(attr);
978
- }
979
- function setAttributesFromProps(el, props) {
980
- for (const [p, value] of Object.entries(props)) {
981
- if (!Object.hasOwn(props, p))
982
- continue;
983
- if (ignoreProps.includes(p))
984
- continue;
985
- if (value === void 0) {
986
- continue;
987
- }
988
- const attr = DOMAttributeNames[p] || p.toLowerCase();
989
- if (el.tagName === "SCRIPT" && isBooleanScriptAttribute(attr)) {
990
- el[attr] = Boolean(value);
991
- } else {
992
- el.setAttribute(attr, String(value));
993
- }
994
- if (value === false || el.tagName === "SCRIPT" && isBooleanScriptAttribute(attr) && (!value || value === "false")) {
995
- el.setAttribute(attr, "");
996
- el.removeAttribute(attr);
997
- }
998
- }
999
- }
1000
-
1001
951
  // src/runtime/loaders/component-loader.ts
1002
952
  import * as React from "react";
1003
953
  import * as JSXDevRuntime from "react/jsx-dev-runtime";
@@ -1278,7 +1228,7 @@ var REMOTE_SHARED_ASSIGNMENT_RE = new RegExp(
1278
1228
  `\\.TURBOPACK_REMOTE_SHARED\\s*=\\s*await (?:__turbopack_context__|[a-z])\\.A\\((?<sharedModuleId>${MODULE_ID_PATTERN})\\)`
1279
1229
  );
1280
1230
  var ASYNC_MODULE_LOADER_RE = new RegExp(
1281
- `(?:__turbopack_context__|e)\\.A\\((?<asyncSharedModuleId>${MODULE_ID_PATTERN})\\)`
1231
+ `(?:__turbopack_context__|[a-z])\\.A\\((?<asyncSharedModuleId>${MODULE_ID_PATTERN})\\)`
1282
1232
  );
1283
1233
  var ASYNC_MODULE_CALLBACK_RE = new RegExp(
1284
1234
  `(?:parentImport|[a-z])\\((?<sharedModuleId>${MODULE_ID_PATTERN})\\)`
@@ -2237,6 +2187,188 @@ async function loadStaticRemoteComponent(scripts, url, resolveClientUrl) {
2237
2187
  );
2238
2188
  }
2239
2189
 
2190
+ // src/host/shared/pipeline.ts
2191
+ function preparePipeline(input) {
2192
+ const parser = new DOMParser();
2193
+ const doc = parser.parseFromString(input.html, "text/html");
2194
+ const parsed = parseRemoteComponentDocument(doc, input.name, input.url);
2195
+ const remoteShared = input.remoteShared ?? parsed.remoteShared;
2196
+ if ("__remote_components_missing_shared__" in remoteShared) {
2197
+ throw new RemoteComponentsError(
2198
+ remoteShared.__remote_components_missing_shared__
2199
+ );
2200
+ }
2201
+ applyOriginToNodes(doc, input.url, input.resolveClientUrl);
2202
+ const scriptDescriptors = buildScriptDescriptors(parsed.scripts, input.url);
2203
+ return { doc, parsed, scriptDescriptors };
2204
+ }
2205
+ async function loadPrepared(input) {
2206
+ const { prepared, url, signal, resolveClientUrl, container, rscName } = input;
2207
+ const { doc, parsed, scriptDescriptors } = prepared;
2208
+ if (signal.aborted) {
2209
+ return { status: "aborted" };
2210
+ }
2211
+ const userShared = await input.shared;
2212
+ if (signal.aborted) {
2213
+ return { status: "aborted" };
2214
+ }
2215
+ if (parsed.isRemoteComponent) {
2216
+ return loadStaticPath({
2217
+ parsed,
2218
+ doc,
2219
+ url,
2220
+ resolveClientUrl
2221
+ });
2222
+ }
2223
+ return loadDynamicPath({
2224
+ parsed,
2225
+ doc,
2226
+ url,
2227
+ scriptDescriptors,
2228
+ shared: userShared,
2229
+ resolveClientUrl,
2230
+ container,
2231
+ rscName
2232
+ });
2233
+ }
2234
+ function buildScriptDescriptors(scripts, url) {
2235
+ return scripts.map((script) => {
2236
+ const scriptSrc = script.getAttribute("data-src") || script.getAttribute("src") || script.src;
2237
+ const { prefix, id: path } = REMOTE_COMPONENT_REGEX.exec(scriptSrc)?.groups ?? {
2238
+ prefix: void 0,
2239
+ id: scriptSrc
2240
+ };
2241
+ return {
2242
+ src: new URL(collapseDoubleSlashes(`${prefix ?? ""}${path}`), url).href
2243
+ };
2244
+ });
2245
+ }
2246
+ async function loadStaticPath(input) {
2247
+ const { parsed, doc, url, resolveClientUrl } = input;
2248
+ const scripts = Array.from(
2249
+ parsed.component.querySelectorAll("script")
2250
+ );
2251
+ const { mount, unmount } = await loadStaticRemoteComponent(
2252
+ scripts,
2253
+ url,
2254
+ resolveClientUrl
2255
+ );
2256
+ return {
2257
+ status: "static",
2258
+ mount,
2259
+ unmount,
2260
+ metadata: parsed.metadata,
2261
+ parsed,
2262
+ doc
2263
+ };
2264
+ }
2265
+ async function loadDynamicPath(input) {
2266
+ const {
2267
+ parsed,
2268
+ doc,
2269
+ url,
2270
+ scriptDescriptors,
2271
+ shared: shared2,
2272
+ resolveClientUrl,
2273
+ container
2274
+ } = input;
2275
+ const rscName = input.rscName ?? (parsed.rsc ? `__remote_component_rsc_${escapeString(url.href)}_${escapeString(parsed.name)}` : void 0);
2276
+ const rscData = parsed.rsc ? (parsed.rsc.textContent || "").split("\n").filter(Boolean) : [];
2277
+ const result = await loadRemoteComponent({
2278
+ url,
2279
+ name: parsed.name,
2280
+ rscName,
2281
+ bundle: parsed.metadata.bundle,
2282
+ route: parsed.metadata.route,
2283
+ runtime: parsed.metadata.runtime,
2284
+ data: rscData,
2285
+ nextData: parsed.nextData,
2286
+ scripts: scriptDescriptors,
2287
+ shared: buildHostShared(shared2, resolveClientUrl),
2288
+ remoteShared: parsed.remoteShared,
2289
+ container,
2290
+ resolveClientUrl
2291
+ });
2292
+ if (result.error) {
2293
+ return { status: "error", error: result.error };
2294
+ }
2295
+ return {
2296
+ status: "loaded",
2297
+ component: result.component,
2298
+ metadata: parsed.metadata,
2299
+ parsed,
2300
+ doc
2301
+ };
2302
+ }
2303
+
2304
+ // src/host/shared/state.ts
2305
+ function createHostState() {
2306
+ return {
2307
+ stage: "idle",
2308
+ prevSrc: void 0,
2309
+ prevUrl: void 0,
2310
+ prevName: void 0,
2311
+ prevIsRemoteComponent: false,
2312
+ abortController: void 0
2313
+ };
2314
+ }
2315
+
2316
+ // src/host/utils/resolve-name-from-src.ts
2317
+ function resolveNameFromSrc(src, defaultName) {
2318
+ if (!src) {
2319
+ return defaultName;
2320
+ }
2321
+ const hash = typeof src === "string" ? src : src.hash;
2322
+ const hashIndex = hash.indexOf("#");
2323
+ if (hashIndex < 0) {
2324
+ return defaultName;
2325
+ }
2326
+ const name = hash.slice(hashIndex + 1);
2327
+ return name || defaultName;
2328
+ }
2329
+
2330
+ // src/runtime/html/set-attributes-from-props.ts
2331
+ var DOMAttributeNames = {
2332
+ acceptCharset: "accept-charset",
2333
+ className: "class",
2334
+ htmlFor: "for",
2335
+ httpEquiv: "http-equiv",
2336
+ noModule: "noModule"
2337
+ };
2338
+ var ignoreProps = [
2339
+ "onLoad",
2340
+ "onReady",
2341
+ "dangerouslySetInnerHTML",
2342
+ "children",
2343
+ "onError",
2344
+ "strategy",
2345
+ "stylesheets"
2346
+ ];
2347
+ function isBooleanScriptAttribute(attr) {
2348
+ return ["async", "defer", "noModule"].includes(attr);
2349
+ }
2350
+ function setAttributesFromProps(el, props) {
2351
+ for (const [p, value] of Object.entries(props)) {
2352
+ if (!Object.hasOwn(props, p))
2353
+ continue;
2354
+ if (ignoreProps.includes(p))
2355
+ continue;
2356
+ if (value === void 0) {
2357
+ continue;
2358
+ }
2359
+ const attr = DOMAttributeNames[p] || p.toLowerCase();
2360
+ if (el.tagName === "SCRIPT" && isBooleanScriptAttribute(attr)) {
2361
+ el[attr] = Boolean(value);
2362
+ } else {
2363
+ el.setAttribute(attr, String(value));
2364
+ }
2365
+ if (value === false || el.tagName === "SCRIPT" && isBooleanScriptAttribute(attr) && (!value || value === "false")) {
2366
+ el.setAttribute(attr, "");
2367
+ el.removeAttribute(attr);
2368
+ }
2369
+ }
2370
+ }
2371
+
2240
2372
  // src/host/react/hooks/use-resolve-client-url.ts
2241
2373
  import { useMemo } from "react";
2242
2374
  import { useRemoteComponentsContext } from "#internal/host/react/context";
@@ -2337,6 +2469,10 @@ function ConsumeRemoteComponent({
2337
2469
  const { credentials: contextCredentials, shared: contextShared } = useRemoteComponentsContext2();
2338
2470
  const credentials = credentialsProp ?? contextCredentials ?? "same-origin";
2339
2471
  const shared2 = sharedProp ?? contextShared ?? {};
2472
+ const emitter = useMemo2(
2473
+ () => makeReactEmitter({ onBeforeLoad, onLoad, onError, onChange }),
2474
+ [onBeforeLoad, onLoad, onError, onChange]
2475
+ );
2340
2476
  const name = useMemo2(
2341
2477
  () => resolveNameFromSrc(src, nameProp),
2342
2478
  [src, nameProp]
@@ -2426,7 +2562,7 @@ function ConsumeRemoteComponent({
2426
2562
  hostStateRef.current.abortController?.abort();
2427
2563
  hostStateRef.current.abortController = new AbortController();
2428
2564
  const { signal } = hostStateRef.current.abortController;
2429
- onBeforeLoad?.(src);
2565
+ emitter.beforeLoad(src);
2430
2566
  hostStateRef.current.stage = "loading";
2431
2567
  startTransition(async () => {
2432
2568
  try {
@@ -2457,19 +2593,26 @@ function ConsumeRemoteComponent({
2457
2593
  }
2458
2594
  if (signal.aborted)
2459
2595
  return;
2460
- const parser = new DOMParser();
2461
- const doc = parser.parseFromString(html, "text/html");
2596
+ const userShared = await shared2;
2597
+ if (signal.aborted)
2598
+ return;
2599
+ const prepared = preparePipeline({
2600
+ html,
2601
+ name,
2602
+ url,
2603
+ shared: userShared,
2604
+ resolveClientUrl
2605
+ });
2606
+ const { doc, parsed } = prepared;
2462
2607
  const {
2463
2608
  component,
2464
2609
  name: remoteName,
2465
2610
  isRemoteComponent,
2466
2611
  metadata,
2467
- nextData,
2468
2612
  rsc,
2469
2613
  remoteShared,
2470
- links: linkElements,
2471
- scripts: scriptElements
2472
- } = parseRemoteComponentDocument(doc, name, url);
2614
+ links: linkElements
2615
+ } = parsed;
2473
2616
  if (hostStateRef.current.prevIsRemoteComponent) {
2474
2617
  if (shadowRoot) {
2475
2618
  shadowRoot.innerHTML = "";
@@ -2490,7 +2633,6 @@ function ConsumeRemoteComponent({
2490
2633
  hostStateRef.current.prevIsRemoteComponent = isRemoteComponent;
2491
2634
  hostStateRef.current.prevUrl = url;
2492
2635
  hostStateRef.current.prevName = remoteName;
2493
- applyOriginToNodes(doc, url, resolveClientUrl);
2494
2636
  const links = linkElements.map((link) => ({
2495
2637
  href: new URL(link.getAttribute("href") ?? link.href, url).href,
2496
2638
  ...link.getAttributeNames().reduce((acc, key) => {
@@ -2500,7 +2642,6 @@ function ConsumeRemoteComponent({
2500
2642
  return acc;
2501
2643
  }, {})
2502
2644
  }));
2503
- const scripts = scriptElements;
2504
2645
  const inlineScripts = (isRemoteComponent ? component : doc).querySelectorAll(
2505
2646
  "script:not([src]):not([data-src]):not([id*='_rsc']):not([id='__NEXT_DATA__']):not([id='__REMOTE_NEXT_DATA__'])"
2506
2647
  );
@@ -2579,20 +2720,10 @@ function ConsumeRemoteComponent({
2579
2720
  componentHydrationHtml.current = `${Array.from(
2580
2721
  doc.querySelectorAll("link,style")
2581
2722
  ).map((link) => link.outerHTML).join("")}${reset ? `<style data-remote-components-reset="">:host { all: initial; }</style>` : ""}${component.innerHTML}`;
2582
- const userShared = await shared2;
2583
- if ("__remote_components_missing_shared__" in userShared) {
2584
- userShared.__remote_components_missing_shared__().catch((e) => {
2585
- throw e;
2586
- });
2587
- } else if ("__remote_components_missing_shared__" in remoteShared) {
2588
- throw new RemoteComponentsError(
2589
- remoteShared.__remote_components_missing_shared__
2590
- );
2591
- }
2592
2723
  if (isRemoteComponent) {
2593
2724
  if (previousSrc !== void 0) {
2594
- onChange?.({
2595
- previousSrc,
2725
+ emitter.change({
2726
+ previousSrc: previousSrc ?? null,
2596
2727
  nextSrc: src,
2597
2728
  previousName,
2598
2729
  nextName: remoteName
@@ -2613,7 +2744,7 @@ function ConsumeRemoteComponent({
2613
2744
  await Promise.all(
2614
2745
  Array.from(mount).map((mountFn) => mountFn(shadowRoot))
2615
2746
  );
2616
- onLoad?.(src);
2747
+ emitter.load(src);
2617
2748
  } else if (isolate === false) {
2618
2749
  setRemoteComponent(
2619
2750
  // TODO: remove wrapper div by converting HTML to RSC or React tree
@@ -2637,59 +2768,42 @@ function ConsumeRemoteComponent({
2637
2768
  (mountFn) => mountFn(prevRemoteComponentContainerRef.current)
2638
2769
  )
2639
2770
  );
2640
- onLoad?.(src);
2771
+ emitter.load(src);
2641
2772
  }
2642
2773
  hostStateRef.current.stage = "loaded";
2643
2774
  } else {
2644
- const result = await loadRemoteComponent({
2775
+ const result = await loadPrepared({
2776
+ prepared,
2645
2777
  url,
2646
- name: remoteName,
2647
- rscName,
2648
- bundle: metadata.bundle,
2649
- route: metadata.route,
2650
- runtime: metadata.runtime,
2651
- data: newData.data,
2652
- nextData,
2653
- scripts: Array.from(scripts).map((script) => {
2654
- const scriptSrc = script.getAttribute("data-src") || script.getAttribute("src") || script.src;
2655
- const { prefix, id: path } = REMOTE_COMPONENT_REGEX.exec(
2656
- scriptSrc
2657
- )?.groups ?? {
2658
- prefix: void 0,
2659
- id: scriptSrc
2660
- };
2661
- return {
2662
- src: new URL(
2663
- collapseDoubleSlashes(`${prefix ?? ""}${path}`),
2664
- url
2665
- ).href
2666
- };
2667
- }),
2668
- shared: buildHostShared(userShared, resolveClientUrl),
2669
- remoteShared,
2778
+ signal,
2779
+ shared: userShared,
2780
+ resolveClientUrl,
2670
2781
  container: shadowRoot,
2671
- resolveClientUrl
2782
+ rscName
2672
2783
  });
2673
2784
  if (rsc) {
2674
2785
  rsc.remove();
2675
2786
  }
2676
2787
  setData(newData);
2677
2788
  if (previousSrc !== void 0) {
2678
- onChange?.({
2679
- previousSrc,
2789
+ emitter.change({
2790
+ previousSrc: previousSrc ?? null,
2680
2791
  nextSrc: src,
2681
2792
  previousName,
2682
2793
  nextName: remoteName
2683
2794
  });
2684
2795
  }
2685
- if (result.error) {
2796
+ if (result.status === "aborted") {
2797
+ return;
2798
+ }
2799
+ if (result.status === "error") {
2686
2800
  hostStateRef.current.stage = "error";
2687
2801
  setRemoteComponent(result.error);
2688
- onError?.(result.error);
2689
- } else {
2802
+ emitter.error(result.error);
2803
+ } else if (result.status === "loaded") {
2690
2804
  hostStateRef.current.stage = "loaded";
2691
2805
  setRemoteComponent(result.component);
2692
- onLoad?.(src);
2806
+ emitter.load(src);
2693
2807
  }
2694
2808
  }
2695
2809
  } catch (error) {
@@ -2699,7 +2813,7 @@ function ConsumeRemoteComponent({
2699
2813
  }
2700
2814
  hostStateRef.current.stage = "error";
2701
2815
  setRemoteComponent(error);
2702
- onError?.(error);
2816
+ emitter.error(error);
2703
2817
  }
2704
2818
  });
2705
2819
  }
@@ -2713,10 +2827,10 @@ function ConsumeRemoteComponent({
2713
2827
  shadowRoot,
2714
2828
  reset,
2715
2829
  id,
2716
- onBeforeLoad,
2717
- onLoad,
2718
- onError,
2719
- onChange,
2830
+ emitter.beforeLoad,
2831
+ emitter.load,
2832
+ emitter.error,
2833
+ emitter.change,
2720
2834
  onRequest,
2721
2835
  onResponse,
2722
2836
  resolveClientUrl
@@ -2758,7 +2872,7 @@ function ConsumeRemoteComponent({
2758
2872
  );
2759
2873
  }).then(() => {
2760
2874
  if (src) {
2761
- onLoad?.(src);
2875
+ emitter.load(src);
2762
2876
  }
2763
2877
  }).catch((e) => {
2764
2878
  const error = new RemoteComponentsError(
@@ -2768,7 +2882,7 @@ function ConsumeRemoteComponent({
2768
2882
  }
2769
2883
  );
2770
2884
  setRemoteComponent(error);
2771
- onError?.(error);
2885
+ emitter.error(error);
2772
2886
  });
2773
2887
  }
2774
2888
  }