@bleedingdev/modern-js-create 3.2.0-ultramodern.53 → 3.2.0-ultramodern.55

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.js CHANGED
@@ -1095,6 +1095,7 @@ function appDependencies(scope, packageSource, app) {
1095
1095
  dependencies['@modern-js/plugin-bff'] = modernPackageSpecifier('@modern-js/plugin-bff', packageSource);
1096
1096
  for (const remote of verticalEffectApps())dependencies[ultramodern_workspace_packageName(scope, remote.packageSuffix)] = WORKSPACE_PACKAGE_VERSION;
1097
1097
  }
1098
+ for (const remote of resolveRemoteRefs(app))dependencies[ultramodern_workspace_packageName(scope, remote.packageSuffix)] = WORKSPACE_PACKAGE_VERSION;
1098
1099
  if (appHasEffectApi(app)) dependencies['@modern-js/plugin-bff'] = modernPackageSpecifier('@modern-js/plugin-bff', packageSource);
1099
1100
  return dependencies;
1100
1101
  }
@@ -1305,6 +1306,10 @@ function createPackageTsConfig(packageDir, includeApi = false) {
1305
1306
  };
1306
1307
  }
1307
1308
  function createAppPackage(scope, app, packageSource, enableTailwind) {
1309
+ const packageExports = Object.fromEntries(Object.entries(app.exposes ?? {}).map(([expose, source])=>[
1310
+ expose,
1311
+ source
1312
+ ]));
1308
1313
  const packageJson = {
1309
1314
  private: true,
1310
1315
  name: ultramodern_workspace_packageName(scope, app.packageSuffix),
@@ -1332,13 +1337,14 @@ function createAppPackage(scope, app, packageSource, enableTailwind) {
1332
1337
  dependencies: appDependencies(scope, packageSource, app),
1333
1338
  devDependencies: appDevDependencies(packageSource, enableTailwind)
1334
1339
  };
1335
- if (appHasEffectApi(app)) packageJson.exports = {
1340
+ if (appHasEffectApi(app)) Object.assign(packageExports, {
1336
1341
  './effect/client': `./src/effect/${app.effectApi.stem}-client.ts`,
1337
1342
  './shared/effect/api': './shared/effect/api.ts'
1338
- };
1339
- else if ('shell' === app.kind) packageJson.exports = {
1343
+ });
1344
+ else if ('shell' === app.kind) Object.assign(packageExports, {
1340
1345
  './effect/clients': './src/effect/recommendations-client.ts'
1341
- };
1346
+ });
1347
+ if (Object.keys(packageExports).length > 0) packageJson.exports = packageExports;
1342
1348
  return packageJson;
1343
1349
  }
1344
1350
  function createServicePackage(scope, packageSource, enableTailwind, service = effectService) {
@@ -2769,13 +2775,19 @@ export default function BoundaryOverlay() {
2769
2775
  }
2770
2776
  `;
2771
2777
  }
2772
- function createShellRemoteComponents() {
2778
+ function createShellRemoteComponents(scope) {
2773
2779
  return `import { createLazyComponent } from '@module-federation/modern-js-v3/react';
2774
2780
  import { getInstance, loadRemote } from '@module-federation/modern-js-v3/runtime';
2775
- import type { JSX } from 'react';
2781
+ import { Suspense, useEffect, useMemo, useState, type ComponentType } from 'react';
2782
+ import HeaderServer from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/Header';
2783
+ import StorePickerServer from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/StorePicker';
2784
+ import RecommendationsServer from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/Recommendations';
2785
+ import ProductPageServer from '${ultramodern_workspace_packageName(scope, 'remote-decide')}/ProductPage';
2786
+ import MiniCartServer from '${ultramodern_workspace_packageName(scope, 'remote-checkout')}/MiniCart';
2787
+ import CartPageServer from '${ultramodern_workspace_packageName(scope, 'remote-checkout')}/CartPage';
2776
2788
 
2777
2789
  type RemoteComponentModule = {
2778
- default: () => JSX.Element;
2790
+ default: ComponentType;
2779
2791
  };
2780
2792
 
2781
2793
  const loadRemoteComponent = async (specifier: string) => {
@@ -2790,69 +2802,52 @@ const remoteFallback =
2790
2802
  ({ error }: { error: Error }) =>
2791
2803
  <div className="rounded-xl border border-red-900/20 bg-red-50 px-4 py-3 text-sm font-semibold text-red-900" data-remote-error={error.name}>Remote unavailable</div>;
2792
2804
 
2793
- const HeaderLoading = () => (
2794
- <div className="flex min-w-0 flex-1 items-center gap-5" data-mf-boundary="explore">
2795
- <div className="h-6 w-28 rounded-full bg-stone-200" />
2796
- <div className="hidden h-5 w-44 rounded-full bg-stone-100 sm:block" />
2797
- </div>
2798
- );
2805
+ const createHydratedRemote = (
2806
+ ServerComponent: ComponentType,
2807
+ specifier: string,
2808
+ ) => {
2809
+ return function HydratedRemote() {
2810
+ const [hydrated, setHydrated] = useState(false);
2799
2811
 
2800
- const MiniCartLoading = () => (
2801
- <div className="h-10 w-28 rounded-full bg-stone-100" data-mf-boundary="checkout" />
2802
- );
2812
+ useEffect(() => {
2813
+ setHydrated(true);
2814
+ }, []);
2803
2815
 
2804
- const PanelLoading = () => (
2805
- <section className="mx-auto mt-10 max-w-7xl rounded-2xl bg-white/75 p-6 shadow-xl shadow-stone-900/10">
2806
- <div className="h-5 w-40 rounded-full bg-stone-200" />
2807
- <div className="mt-5 grid gap-4 md:grid-cols-2">
2808
- <div className="h-36 rounded-xl bg-stone-100" />
2809
- <div className="h-36 rounded-xl bg-stone-100" />
2810
- </div>
2811
- </section>
2812
- );
2816
+ const FederatedComponent = useMemo(() => {
2817
+ if (!hydrated) {
2818
+ return undefined;
2819
+ }
2820
+ const instance = getInstance();
2821
+ if (!instance) {
2822
+ return undefined;
2823
+ }
2824
+ return createLazyComponent({
2825
+ export: 'default',
2826
+ fallback: remoteFallback,
2827
+ instance,
2828
+ loader: () => loadRemoteComponent(specifier),
2829
+ loading: <ServerComponent />,
2830
+ });
2831
+ }, [hydrated]);
2813
2832
 
2814
- export const Header = createLazyComponent({
2815
- export: 'default',
2816
- fallback: remoteFallback,
2817
- instance: getInstance(),
2818
- loader: () => loadRemoteComponent('explore/Header'),
2819
- loading: <HeaderLoading />,
2820
- });
2821
- export const StorePicker = createLazyComponent({
2822
- export: 'default',
2823
- fallback: remoteFallback,
2824
- instance: getInstance(),
2825
- loader: () => loadRemoteComponent('explore/StorePicker'),
2826
- loading: <PanelLoading />,
2827
- });
2828
- export const Recommendations = createLazyComponent({
2829
- export: 'default',
2830
- fallback: remoteFallback,
2831
- instance: getInstance(),
2832
- loader: () => loadRemoteComponent('explore/Recommendations'),
2833
- loading: <PanelLoading />,
2834
- });
2835
- export const ProductPage = createLazyComponent({
2836
- export: 'default',
2837
- fallback: remoteFallback,
2838
- instance: getInstance(),
2839
- loader: () => loadRemoteComponent('decide/ProductPage'),
2840
- loading: <PanelLoading />,
2841
- });
2842
- export const MiniCart = createLazyComponent({
2843
- export: 'default',
2844
- fallback: remoteFallback,
2845
- instance: getInstance(),
2846
- loader: () => loadRemoteComponent('checkout/MiniCart'),
2847
- loading: <MiniCartLoading />,
2848
- });
2849
- export const CartPage = createLazyComponent({
2850
- export: 'default',
2851
- fallback: remoteFallback,
2852
- instance: getInstance(),
2853
- loader: () => loadRemoteComponent('checkout/CartPage'),
2854
- loading: <PanelLoading />,
2855
- });
2833
+ if (!FederatedComponent) {
2834
+ return <ServerComponent />;
2835
+ }
2836
+
2837
+ return (
2838
+ <Suspense fallback={<ServerComponent />}>
2839
+ <FederatedComponent />
2840
+ </Suspense>
2841
+ );
2842
+ };
2843
+ };
2844
+
2845
+ export const Header = createHydratedRemote(HeaderServer, 'explore/Header');
2846
+ export const StorePicker = createHydratedRemote(StorePickerServer, 'explore/StorePicker');
2847
+ export const Recommendations = createHydratedRemote(RecommendationsServer, 'explore/Recommendations');
2848
+ export const ProductPage = createHydratedRemote(ProductPageServer, 'decide/ProductPage');
2849
+ export const MiniCart = createHydratedRemote(MiniCartServer, 'checkout/MiniCart');
2850
+ export const CartPage = createHydratedRemote(CartPageServer, 'checkout/CartPage');
2856
2851
  `;
2857
2852
  }
2858
2853
  function createRemotePage(app) {
@@ -3161,13 +3156,15 @@ export default function ${componentName}() {
3161
3156
  }
3162
3157
  `;
3163
3158
  }
3164
- function createDecideRemoteComponents() {
3159
+ function createDecideRemoteComponents(scope) {
3165
3160
  return `import { createLazyComponent } from '@module-federation/modern-js-v3/react';
3166
3161
  import { getInstance, loadRemote } from '@module-federation/modern-js-v3/runtime';
3167
- import type { JSX } from 'react';
3162
+ import { Suspense, useEffect, useMemo, useState, type ComponentType } from 'react';
3163
+ import RecommendationsServer from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/Recommendations';
3164
+ import AddToCartServer from '${ultramodern_workspace_packageName(scope, 'remote-checkout')}/AddToCart';
3168
3165
 
3169
3166
  type RemoteComponentModule = {
3170
- default: () => JSX.Element;
3167
+ default: ComponentType;
3171
3168
  };
3172
3169
 
3173
3170
  const loadRemoteComponent = async (specifier: string) => {
@@ -3182,39 +3179,48 @@ const remoteFallback =
3182
3179
  ({ error }: { error: Error }) =>
3183
3180
  <div className="rounded-xl border border-red-900/20 bg-red-50 px-4 py-3 text-sm font-semibold text-red-900" data-remote-error={error.name}>Remote unavailable</div>;
3184
3181
 
3185
- const AddToCartLoading = () => (
3186
- <div className="mt-8 flex gap-3" data-mf-boundary="checkout">
3187
- <div className="h-11 w-32 rounded-full bg-stone-200" />
3188
- <div className="h-11 w-28 rounded-full bg-white/80" />
3189
- </div>
3190
- );
3182
+ const createHydratedRemote = (
3183
+ ServerComponent: ComponentType,
3184
+ specifier: string,
3185
+ ) => {
3186
+ return function HydratedRemote() {
3187
+ const [hydrated, setHydrated] = useState(false);
3191
3188
 
3192
- const RecommendationsLoading = () => (
3193
- <section className="mx-auto mt-12 max-w-7xl" data-mf-boundary="explore">
3194
- <div className="h-8 w-64 rounded-full bg-stone-200" />
3195
- <div className="mt-5 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
3196
- <div className="h-48 rounded-2xl bg-white/80" />
3197
- <div className="h-48 rounded-2xl bg-white/80" />
3198
- <div className="h-48 rounded-2xl bg-white/80" />
3199
- <div className="h-48 rounded-2xl bg-white/80" />
3200
- </div>
3201
- </section>
3202
- );
3189
+ useEffect(() => {
3190
+ setHydrated(true);
3191
+ }, []);
3203
3192
 
3204
- export const AddToCart = createLazyComponent({
3205
- export: 'default',
3206
- fallback: remoteFallback,
3207
- instance: getInstance(),
3208
- loader: () => loadRemoteComponent('checkout/AddToCart'),
3209
- loading: <AddToCartLoading />,
3210
- });
3211
- export const Recommendations = createLazyComponent({
3212
- export: 'default',
3213
- fallback: remoteFallback,
3214
- instance: getInstance(),
3215
- loader: () => loadRemoteComponent('explore/Recommendations'),
3216
- loading: <RecommendationsLoading />,
3217
- });
3193
+ const FederatedComponent = useMemo(() => {
3194
+ if (!hydrated) {
3195
+ return undefined;
3196
+ }
3197
+ const instance = getInstance();
3198
+ if (!instance) {
3199
+ return undefined;
3200
+ }
3201
+ return createLazyComponent({
3202
+ export: 'default',
3203
+ fallback: remoteFallback,
3204
+ instance,
3205
+ loader: () => loadRemoteComponent(specifier),
3206
+ loading: <ServerComponent />,
3207
+ });
3208
+ }, [hydrated]);
3209
+
3210
+ if (!FederatedComponent) {
3211
+ return <ServerComponent />;
3212
+ }
3213
+
3214
+ return (
3215
+ <Suspense fallback={<ServerComponent />}>
3216
+ <FederatedComponent />
3217
+ </Suspense>
3218
+ );
3219
+ };
3220
+ };
3221
+
3222
+ export const AddToCart = createHydratedRemote(AddToCartServer, 'checkout/AddToCart');
3223
+ export const Recommendations = createHydratedRemote(RecommendationsServer, 'explore/Recommendations');
3218
3224
  `;
3219
3225
  }
3220
3226
  function remoteComponentOutputPath(app, expose) {
@@ -5380,7 +5386,7 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind) {
5380
5386
  writeFile(targetDir, `${app.directory}/src/routes/[lang]/page.tsx`, 'shell' === app.kind ? createShellPage() : createRemotePage(app));
5381
5387
  for (const route of createRouteOwnedI18nPaths(app))if ('/' !== route.canonicalPath && 'shell' !== app.kind) writeFile(targetDir, createRoutePageFilePath(app, route.canonicalPath), createRouteAliasPage(route.canonicalPath));
5382
5388
  if ('shell' === app.kind) {
5383
- writeFile(targetDir, `${app.directory}/src/routes/remote-components.tsx`, createShellRemoteComponents());
5389
+ writeFile(targetDir, `${app.directory}/src/routes/remote-components.tsx`, createShellRemoteComponents(scope));
5384
5390
  writeFile(targetDir, `${app.directory}/src/routes/shell-frame.tsx`, createShellFrameComponent());
5385
5391
  writeFile(targetDir, `${app.directory}/src/routes/boundary-overlay.tsx`, createShellBoundaryOverlay());
5386
5392
  writeFile(targetDir, `${app.directory}/src/effect/recommendations-client.ts`, createShellEffectClient(scope));
@@ -5395,7 +5401,7 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind) {
5395
5401
  }
5396
5402
  if ('vertical' === app.kind || 'horizontal-remote' === app.kind) {
5397
5403
  writeFile(targetDir, `${app.directory}/src/remote-entry.tsx`, createRemoteEntry(app));
5398
- if ('remote-decide' === app.id) writeFile(targetDir, `${app.directory}/src/components/remote-components.tsx`, createDecideRemoteComponents());
5404
+ if ('remote-decide' === app.id) writeFile(targetDir, `${app.directory}/src/components/remote-components.tsx`, createDecideRemoteComponents(scope));
5399
5405
  if ('remote-checkout' === app.id) writeFile(targetDir, `${app.directory}/src/cart-store.ts`, createCheckoutCartStore());
5400
5406
  for (const expose of Object.keys(app.exposes ?? {})){
5401
5407
  const outputPath = remoteComponentOutputPath(app, expose);
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
24
- "version": "3.2.0-ultramodern.53",
24
+ "version": "3.2.0-ultramodern.55",
25
25
  "types": "./dist/types/index.d.ts",
26
26
  "main": "./dist/index.js",
27
27
  "bin": {
@@ -41,7 +41,7 @@
41
41
  "@types/node": "^25.9.1",
42
42
  "@typescript/native-preview": "7.0.0-dev.20260527.2",
43
43
  "tsx": "^4.22.3",
44
- "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.53"
44
+ "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.2.0-ultramodern.55"
45
45
  },
46
46
  "publishConfig": {
47
47
  "registry": "https://registry.npmjs.org/",
@@ -54,6 +54,6 @@
54
54
  "start": "node ./dist/index.js"
55
55
  },
56
56
  "ultramodern": {
57
- "frameworkVersion": "3.2.0-ultramodern.53"
57
+ "frameworkVersion": "3.2.0-ultramodern.55"
58
58
  }
59
59
  }
@@ -1,13 +1,6 @@
1
1
  minimumReleaseAge: 1440
2
2
  minimumReleaseAgeStrict: true
3
3
  minimumReleaseAgeIgnoreMissingTime: false
4
- minimumReleaseAgeExclude:
5
- - '@modern-js/*'
6
- - '@bleedingdev/*'
7
- - '@effect/tsgo'
8
- - '@effect/tsgo-*'
9
- - '@typescript/native-preview'
10
- - '@typescript/native-preview-*'
11
4
  trustPolicy: no-downgrade
12
5
  trustPolicyIgnoreAfter: 1440
13
6
  blockExoticSubdeps: true
@@ -321,18 +321,8 @@ if (readPnpmConfig('minimumReleaseAgeIgnoreMissingTime') !== false) {
321
321
  console.error('pnpm minimumReleaseAgeIgnoreMissingTime must be false');
322
322
  process.exit(1);
323
323
  }
324
- if (
325
- JSON.stringify(readPnpmConfig('minimumReleaseAgeExclude')) !==
326
- JSON.stringify([
327
- '@modern-js/*',
328
- '@bleedingdev/*',
329
- '@effect/tsgo',
330
- '@effect/tsgo-*',
331
- '@typescript/native-preview',
332
- '@typescript/native-preview-*',
333
- ])
334
- ) {
335
- console.error('pnpm minimumReleaseAgeExclude must retain framework exceptions');
324
+ if (readPnpmConfig('minimumReleaseAgeExclude') !== undefined) {
325
+ console.error('pnpm minimumReleaseAgeExclude must stay unset');
336
326
  process.exit(1);
337
327
  }
338
328
  if (readPnpmConfig('trustPolicy') !== 'no-downgrade') {