@bleedingdev/modern-js-create 3.4.0-ultramodern.2 → 3.4.0-ultramodern.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.
@@ -10,8 +10,7 @@ import { VerticalShowcase } from '../vertical-components';
10
10
  import { ultramodernUiMarker } from '../../ultramodern-build';
11
11
 
12
12
  export default function ShellHome() {
13
- const { i18nInstance } = useModernI18n();
14
- const t = i18nInstance['t'].bind(i18nInstance);
13
+ const { t } = useModernI18n();
15
14
 
16
15
  return (
17
16
  <ShellFrame>
@@ -84,8 +83,7 @@ const loadRemoteComponent = (specifier: string) =>
84
83
 
85
84
  const createRemoteFallback = (specifier: string) =>
86
85
  ({ error }: { error: Error }) => {
87
- const { i18nInstance } = useModernI18n();
88
- const t = i18nInstance['t'].bind(i18nInstance);
86
+ const { t } = useModernI18n();
89
87
  const classification = classifyModuleFederationFallback(error);
90
88
  const telemetry = createModuleFederationFallbackTelemetry({
91
89
  appName: '${shellApp.id}',
@@ -112,7 +110,7 @@ const createRemoteFallback = (specifier: string) =>
112
110
  remote: specifier,
113
111
  status: 'degraded',
114
112
  });
115
- }, [classification, error, specifier, telemetry]);
113
+ }, [classification, error, telemetry]);
116
114
 
117
115
  return <div className="${tw('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} {...toModuleFederationFallbackAttributes(telemetry)}>{t('shell.remoteUnavailable')}</div>;
118
116
  };
@@ -167,8 +165,7 @@ const createHydratedRemote =
167
165
  ${hydratedExports}
168
166
 
169
167
  export const Header = () => {
170
- const { i18nInstance } = useModernI18n();
171
- const t = i18nInstance['t'].bind(i18nInstance);
168
+ const { t } = useModernI18n();
172
169
 
173
170
  return (
174
171
  <header className="${tw('flex min-w-0 flex-wrap items-center gap-x-8 gap-y-2 md:flex-1')}" data-modern-boundary-id="${shellApp.mfName}" data-modern-mf-expose="shell/Header">
@@ -178,8 +175,7 @@ const createHydratedRemote =
178
175
  };
179
176
 
180
177
  export const StatusBadge = () => {
181
- const { i18nInstance } = useModernI18n();
182
- const t = i18nInstance['t'].bind(i18nInstance);
178
+ const { t } = useModernI18n();
183
179
 
184
180
  return (
185
181
  <span className="${tw('inline-flex h-10 shrink-0 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 text-sm font-extrabold text-stone-950 shadow-lg shadow-stone-900/5')}">
@@ -189,8 +185,7 @@ export const StatusBadge = () => {
189
185
  };
190
186
 
191
187
  export const VerticalShowcase = () => {
192
- const { i18nInstance } = useModernI18n();
193
- const t = i18nInstance['t'].bind(i18nInstance);
188
+ const { t } = useModernI18n();
194
189
 
195
190
  if (widgetCount === 0) {
196
191
  return (
@@ -257,8 +252,7 @@ import { ultramodernUiMarker } from '../../ultramodern-build';
257
252
  ` : '';
258
253
  return `${effectBffImport}
259
254
  export default function ${toPascalCase(app.id)}Home() {
260
- const { i18nInstance, language, supportedLanguages } = useModernI18n();
261
- const t = i18nInstance['t'].bind(i18nInstance);
255
+ const { language, supportedLanguages, t } = useModernI18n();
262
256
  ${effectBffState} return (
263
257
  <main className="${tw('min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8')}">
264
258
  <UltramodernRouteHead />
@@ -304,8 +298,7 @@ function createRemoteEntry(app) {
304
298
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
305
299
 
306
300
  export default function ${toPascalCase(domain)}Route() {
307
- const { i18nInstance } = useModernI18n();
308
- const t = i18nInstance['t'].bind(i18nInstance);
301
+ const { t } = useModernI18n();
309
302
 
310
303
  return (
311
304
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Route">
@@ -323,8 +316,7 @@ function createRemoteWidget(app) {
323
316
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
324
317
 
325
318
  export default function ${componentName}() {
326
- const { i18nInstance } = useModernI18n();
327
- const t = i18nInstance['t'].bind(i18nInstance);
319
+ const { t } = useModernI18n();
328
320
 
329
321
  return (
330
322
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Widget">
@@ -343,8 +335,7 @@ function createRemoteExposeComponent(app, expose) {
343
335
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
344
336
 
345
337
  export default function ${componentName}() {
346
- const { i18nInstance } = useModernI18n();
347
- const t = i18nInstance['t'].bind(i18nInstance);
338
+ const { t } = useModernI18n();
348
339
 
349
340
  return (
350
341
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="${expose}">
@@ -36,27 +36,51 @@ function serviceHasCheckoutCartState(service) {
36
36
  function createCheckoutCartSharedSchemas(service) {
37
37
  if (!serviceHasCheckoutCartState(service)) return '';
38
38
  return `
39
- export const checkoutCartLineSchema = Schema.Struct({
39
+ export interface CheckoutCartLine {
40
+ readonly sku: string;
41
+ readonly name: string;
42
+ readonly quantity: number;
43
+ readonly unitPriceCents: number;
44
+ }
45
+
46
+ export interface CheckoutCart {
47
+ readonly lines: ReadonlyArray<CheckoutCartLine>;
48
+ readonly subtotalCents: number;
49
+ readonly totalQuantity: number;
50
+ }
51
+
52
+ export interface CheckoutAddCartItemPayload {
53
+ readonly sku: string;
54
+ readonly name?: string;
55
+ readonly quantity: number;
56
+ readonly unitPriceCents?: number;
57
+ }
58
+
59
+ export interface CheckoutRemoveCartItemPayload {
60
+ readonly sku: string;
61
+ }
62
+
63
+ export const checkoutCartLineSchema: Schema.Schema<CheckoutCartLine> = Schema.Struct({
40
64
  sku: Schema.String,
41
65
  name: Schema.String,
42
66
  quantity: Schema.Finite,
43
67
  unitPriceCents: Schema.Finite,
44
68
  });
45
69
 
46
- export const checkoutCartSchema = Schema.Struct({
70
+ export const checkoutCartSchema: Schema.Schema<CheckoutCart> = Schema.Struct({
47
71
  lines: Schema.Array(checkoutCartLineSchema),
48
72
  subtotalCents: Schema.Finite,
49
73
  totalQuantity: Schema.Finite,
50
74
  });
51
75
 
52
- export const checkoutAddCartItemPayloadSchema = Schema.Struct({
76
+ export const checkoutAddCartItemPayloadSchema: Schema.Schema<CheckoutAddCartItemPayload> = Schema.Struct({
53
77
  sku: Schema.String,
54
78
  name: Schema.optional(Schema.String),
55
79
  quantity: Schema.Finite,
56
80
  unitPriceCents: Schema.optional(Schema.Finite),
57
81
  });
58
82
 
59
- export const checkoutRemoveCartItemPayloadSchema = Schema.Struct({
83
+ export const checkoutRemoveCartItemPayloadSchema: Schema.Schema<CheckoutRemoveCartItemPayload> = Schema.Struct({
60
84
  sku: Schema.String,
61
85
  });
62
86
  `;
@@ -209,6 +233,7 @@ function createCheckoutCartClientExports(service) {
209
233
  const pascalStem = toPascalCase(stem);
210
234
  const clientOptionsName = `${pascalStem}ClientOptions`;
211
235
  const createClientName = `create${pascalStem}Client`;
236
+ const clientEffectTypeName = `${pascalStem}ClientEffect`;
212
237
  return `
213
238
  export interface CheckoutCartLine {
214
239
  sku: string;
@@ -232,7 +257,7 @@ export interface CheckoutAddCartItemInput {
232
257
 
233
258
  export const getCheckoutCart = (
234
259
  options: ${clientOptionsName} = {},
235
- ) =>
260
+ ): ${clientEffectTypeName}<CheckoutCart> =>
236
261
  ${createClientName}({
237
262
  ...options,
238
263
  operationContext:
@@ -244,7 +269,7 @@ export const getCheckoutCart = (
244
269
  export const addCheckoutCartItem = (
245
270
  payload: CheckoutAddCartItemInput,
246
271
  options: ${clientOptionsName} = {},
247
- ) =>
272
+ ): ${clientEffectTypeName}<CheckoutCart> =>
248
273
  ${createClientName}({
249
274
  ...options,
250
275
  operationContext:
@@ -258,7 +283,7 @@ export const addCheckoutCartItem = (
258
283
  export const removeCheckoutCartItem = (
259
284
  sku: string,
260
285
  options: ${clientOptionsName} = {},
261
- ) =>
286
+ ): ${clientEffectTypeName}<CheckoutCart> =>
262
287
  ${createClientName}({
263
288
  ...options,
264
289
  operationContext:
@@ -271,7 +296,7 @@ export const removeCheckoutCartItem = (
271
296
 
272
297
  export const clearCheckoutCart = (
273
298
  options: ${clientOptionsName} = {},
274
- ) =>
299
+ ): ${clientEffectTypeName}<CheckoutCart> =>
275
300
  ${createClientName}({
276
301
  ...options,
277
302
  operationContext:
@@ -302,12 +327,63 @@ function createEffectSharedApiContract(service) {
302
327
  const apiName = verticalEffectApiName(service);
303
328
  const groupName = verticalEffectGroupName(service);
304
329
  const stem = effectApiStem(service);
330
+ const pascalStem = toPascalCase(stem);
331
+ const markerType = `${pascalStem}Marker`;
332
+ const itemType = `${pascalStem}Item`;
333
+ const readinessType = `${pascalStem}Readiness`;
334
+ const createPayloadType = `${pascalStem}CreatePayload`;
335
+ const createResponseType = `${pascalStem}CreateResponse`;
336
+ const listResponseType = `${pascalStem}ListResponse`;
305
337
  const apiPrefix = effectApiPrefix(service);
306
338
  const checkoutCartSharedSchemas = createCheckoutCartSharedSchemas(service);
307
339
  const checkoutCartSharedSchemaSection = '' === checkoutCartSharedSchemas ? '' : `${checkoutCartSharedSchemas}\n`;
308
340
  const checkoutCartOperationContexts = createCheckoutCartOperationContexts(service).trimStart();
309
341
  const checkoutCartOperationContextEntries = '' === checkoutCartOperationContexts ? '' : `${checkoutCartOperationContexts}\n`;
310
- return `export const ${markerSchemaExport} = Schema.Struct({
342
+ return `export interface ${markerType} {
343
+ readonly appId: string;
344
+ readonly build: string;
345
+ readonly deployProfile: string;
346
+ readonly packageName: string;
347
+ readonly surface: string;
348
+ readonly version: string;
349
+ }
350
+
351
+ export interface ${itemType} {
352
+ readonly id: string;
353
+ readonly marker: ${markerType};
354
+ readonly title: string;
355
+ }
356
+
357
+ export interface ${readinessType} {
358
+ readonly checks: {
359
+ readonly effectBff: 'ready';
360
+ readonly moduleFederation: 'ready';
361
+ readonly ssr: 'ready';
362
+ readonly translations: 'ready';
363
+ };
364
+ readonly marker: ${markerType};
365
+ readonly status: 'ready';
366
+ readonly versionSkew: 'none';
367
+ }
368
+
369
+ export interface ${createPayloadType} {
370
+ readonly title: string;
371
+ }
372
+
373
+ export interface ${listResponseType} {
374
+ readonly items: ReadonlyArray<${itemType}>;
375
+ }
376
+
377
+ export interface ${createResponseType} {
378
+ readonly item: ${itemType};
379
+ }
380
+
381
+ export interface ${notFoundErrorExport} {
382
+ readonly _tag: '${notFoundErrorExport}';
383
+ readonly id: string;
384
+ }
385
+
386
+ export const ${markerSchemaExport}: Schema.Schema<${markerType}> = Schema.Struct({
311
387
  appId: Schema.String,
312
388
  build: Schema.String,
313
389
  deployProfile: Schema.String,
@@ -316,13 +392,13 @@ function createEffectSharedApiContract(service) {
316
392
  version: Schema.String,
317
393
  });
318
394
 
319
- export const ${schemaExport} = Schema.Struct({
395
+ export const ${schemaExport}: Schema.Schema<${itemType}> = Schema.Struct({
320
396
  id: Schema.String,
321
397
  marker: ${markerSchemaExport},
322
398
  title: Schema.String,
323
399
  });
324
400
 
325
- export const ${readinessSchemaExport} = Schema.Struct({
401
+ export const ${readinessSchemaExport}: Schema.Schema<${readinessType}> = Schema.Struct({
326
402
  checks: Schema.Struct({
327
403
  effectBff: Schema.Literal('ready'),
328
404
  moduleFederation: Schema.Literal('ready'),
@@ -334,18 +410,13 @@ export const ${readinessSchemaExport} = Schema.Struct({
334
410
  versionSkew: Schema.Literal('none'),
335
411
  });
336
412
 
337
- export const ${createPayloadSchemaExport} = Schema.Struct({
413
+ export const ${createPayloadSchemaExport}: Schema.Schema<${createPayloadType}> = Schema.Struct({
338
414
  title: Schema.String,
339
415
  });
340
416
 
341
- ${checkoutCartSharedSchemaSection}export class ${notFoundErrorExport} extends Schema.TaggedErrorClass<${notFoundErrorExport}>()(
342
- '${notFoundErrorExport}',
343
- {
344
- id: Schema.String,
345
- },
346
- ) {}
347
-
348
- export const ${notFoundSchemaExport} = ${notFoundErrorExport}.pipe(
417
+ ${checkoutCartSharedSchemaSection}export const ${notFoundSchemaExport}: Schema.Schema<${notFoundErrorExport}> = Schema.TaggedStruct('${notFoundErrorExport}', {
418
+ id: Schema.String,
419
+ }).pipe(
349
420
  HttpApiSchema.status(404),
350
421
  );
351
422
 
@@ -449,13 +520,20 @@ function createEffectServiceEntry(service, contractImportPath) {
449
520
  HttpApiBuilder,
450
521
  Layer,
451
522
  } from '@modern-js/plugin-bff/effect-edge';
523
+ import type {
524
+ EffectBffDefinition,
525
+ EffectBffRuntime,
526
+ EffectRuntimeLayer,
527
+ } from '@modern-js/plugin-bff/effect-edge';
452
528
  import { ultramodernApiMarker } from '../../src/ultramodern-build.ts';
453
529
  import {
454
530
  ${apiExport},
455
531
  ${groupName}OperationContexts,
532
+ } from '${contractImportPath}';
533
+ import type {
456
534
  ${notFoundErrorExport},
535
+ OperationContext,
457
536
  } from '${contractImportPath}';
458
- import type { OperationContext } from '${contractImportPath}';
459
537
 
460
538
  const ${groupName}Items = [
461
539
  {
@@ -516,9 +594,13 @@ const ${groupName}Layer = HttpApiBuilder.group(
516
594
  const matchedItem = ${groupName}Items.find(
517
595
  candidate => candidate.id === params.id,
518
596
  );
597
+ const notFound: ${notFoundErrorExport} = {
598
+ _tag: '${notFoundErrorExport}',
599
+ id: params.id,
600
+ };
519
601
  const result =
520
602
  matchedItem === undefined
521
- ? Effect.fail(new ${notFoundErrorExport}({ id: params.id }))
603
+ ? Effect.fail(notFound)
522
604
  : Effect.succeed(matchedItem);
523
605
 
524
606
  return result.pipe(
@@ -549,12 +631,15 @@ const ${groupName}Layer = HttpApiBuilder.group(
549
631
 
550
632
  const layer = HttpApiBuilder.layer(${apiExport}).pipe(
551
633
  Layer.provide(${groupName}Layer),
552
- );
634
+ ) satisfies EffectRuntimeLayer;
553
635
 
554
- export default defineEffectBff({
636
+ const effectBff: EffectBffDefinition<typeof ${apiExport}, EffectRuntimeLayer> &
637
+ EffectBffRuntime<typeof ${apiExport}, EffectRuntimeLayer> = defineEffectBff({
555
638
  api: ${apiExport},
556
639
  layer,
557
640
  });
641
+
642
+ export default effectBff;
558
643
  `;
559
644
  }
560
645
  function createEffectClient(service, contractImportPath) {
@@ -565,25 +650,71 @@ function createEffectClient(service, contractImportPath) {
565
650
  const singular = verticalEffectErrorStem(service);
566
651
  const clientOptionsName = `${toPascalCase(stem)}ClientOptions`;
567
652
  const createClientName = `create${toPascalCase(stem)}Client`;
653
+ const clientTypeName = `${toPascalCase(stem)}Client`;
654
+ const clientEffectTypeName = `${toPascalCase(stem)}ClientEffect`;
568
655
  const listName = `list${toPascalCase(stem)}`;
569
656
  const readinessName = `get${toPascalCase(stem)}Readiness`;
570
657
  const getName = `get${toPascalCase(singular)}`;
571
658
  const createName = `create${toPascalCase(singular)}`;
659
+ const notFoundErrorExport = verticalEffectNotFoundErrorExport(service);
660
+ const pascalStem = toPascalCase(stem);
661
+ const itemType = `${pascalStem}Item`;
662
+ const readinessType = `${pascalStem}Readiness`;
663
+ const createResponseType = `${pascalStem}CreateResponse`;
664
+ const listResponseType = `${pascalStem}ListResponse`;
572
665
  const checkoutCartClientExports = createCheckoutCartClientExports(service);
573
666
  return `import {
574
667
  Effect,
575
668
  makeEffectHttpApiClient,
576
669
  runEffectRequest,
577
670
  } from '@modern-js/plugin-bff/effect-client';
671
+ import type {
672
+ HttpClientError,
673
+ HttpApi,
674
+ HttpApiClient,
675
+ HttpApiGroup,
676
+ Schema,
677
+ } from '@modern-js/plugin-bff/effect-client';
578
678
  import {
579
679
  ${contractExport}ApiContract,
580
680
  ${apiExport},
581
681
  ${groupName}OperationContexts,
582
682
  } from '${contractImportPath}';
583
- import type { OperationContext } from '${contractImportPath}';
683
+ import type {
684
+ ${createResponseType},
685
+ ${itemType},
686
+ ${listResponseType},
687
+ ${notFoundErrorExport},
688
+ OperationContext,
689
+ ${readinessType},
690
+ } from '${contractImportPath}';
584
691
 
585
692
  export { Effect, runEffectRequest };
586
693
 
694
+ type ${pascalStem}EffectGroups = typeof ${apiExport} extends HttpApi.HttpApi<
695
+ infer _ApiId,
696
+ infer Groups
697
+ >
698
+ ? Groups
699
+ : never;
700
+
701
+ export type ${clientTypeName} = HttpApiClient.Client<
702
+ Extract<${pascalStem}EffectGroups, HttpApiGroup.Any>,
703
+ never,
704
+ never
705
+ >;
706
+
707
+ export type ${pascalStem}ClientError =
708
+ | ${notFoundErrorExport}
709
+ | HttpClientError.HttpClientError
710
+ | Schema.SchemaError;
711
+
712
+ export type ${clientEffectTypeName}<Success> = Effect.Effect<
713
+ Success,
714
+ ${pascalStem}ClientError,
715
+ never
716
+ >;
717
+
587
718
  export interface ${clientOptionsName} {
588
719
  baseUrl?: string | URL;
589
720
  locale?: string;
@@ -593,7 +724,7 @@ export interface ${clientOptionsName} {
593
724
 
594
725
  export const ${createClientName} = (
595
726
  options: ${clientOptionsName} = {},
596
- ) =>
727
+ ): ${clientEffectTypeName}<${clientTypeName}> =>
597
728
  makeEffectHttpApiClient(${apiExport}, {
598
729
  baseUrl: options.baseUrl ?? ${contractExport}ApiContract.apiPrefix,
599
730
  requestContext: {
@@ -609,7 +740,7 @@ export const ${createClientName} = (
609
740
 
610
741
  export const ${listName} = (
611
742
  options: ${clientOptionsName} & { limit?: number } = {},
612
- ) =>
743
+ ): ${clientEffectTypeName}<${listResponseType}> =>
613
744
  ${createClientName}({
614
745
  ...options,
615
746
  operationContext:
@@ -622,7 +753,7 @@ export const ${listName} = (
622
753
 
623
754
  export const ${readinessName} = (
624
755
  options: ${clientOptionsName} = {},
625
- ) =>
756
+ ): ${clientEffectTypeName}<${readinessType}> =>
626
757
  ${createClientName}({
627
758
  ...options,
628
759
  operationContext:
@@ -634,7 +765,7 @@ export const ${readinessName} = (
634
765
  export const ${getName} = (
635
766
  id: string,
636
767
  options: ${clientOptionsName} = {},
637
- ) =>
768
+ ): ${clientEffectTypeName}<${itemType}> =>
638
769
  ${createClientName}({
639
770
  ...options,
640
771
  operationContext:
@@ -646,7 +777,7 @@ export const ${getName} = (
646
777
  export const ${createName} = (
647
778
  title: string,
648
779
  options: ${clientOptionsName} = {},
649
- ) =>
780
+ ): ${clientEffectTypeName}<${createResponseType}> =>
650
781
  ${createClientName}({
651
782
  ...options,
652
783
  operationContext:
@@ -217,12 +217,12 @@ ${bffPluginEntry} moduleFederationPlugin(),
217
217
  }
218
218
  function createSharedModuleFederationConfig() {
219
219
  return ` shared: {
220
- '@modern-js/plugin-i18n/runtime/no-react-i18next': {
220
+ '@modern-js/plugin-i18n/runtime': {
221
221
  requiredVersion: pluginI18nVersion,
222
222
  singleton: true,
223
223
  treeShaking: false,
224
224
  },
225
- '@modern-js/plugin-i18n/runtime': {
225
+ '@modern-js/plugin-i18n/runtime/no-react-i18next': {
226
226
  requiredVersion: pluginI18nVersion,
227
227
  singleton: true,
228
228
  treeShaking: false,
@@ -342,7 +342,9 @@ const reactVersion = (require('react/package.json') as { version: string }).vers
342
342
  const reactDomVersion = (require('react-dom/package.json') as { version: string }).version;
343
343
 
344
344
  ${createModuleFederationRemoteUrlHelpers(shellHost, remotes)}
345
- export default createModuleFederationConfig({
345
+ const moduleFederationConfig: Parameters<
346
+ typeof createModuleFederationConfig
347
+ >[0] = createModuleFederationConfig({
346
348
  bridge: {
347
349
  enableBridgeRouter: false,
348
350
  },
@@ -360,6 +362,8 @@ export default createModuleFederationConfig({
360
362
  ${createModuleFederationRemotesConfig(scope, shellHost, remotes)}${createSharedModuleFederationConfig()},
361
363
  treeShakingSharedExcludePlugins: ['RspackModuleFederationPlugin'],
362
364
  });
365
+
366
+ export default moduleFederationConfig;
363
367
  `;
364
368
  }
365
369
  function createBuildMarker(scope, app) {
@@ -400,7 +404,9 @@ const reactVersion = (require('react/package.json') as { version: string }).vers
400
404
  const reactDomVersion = (require('react-dom/package.json') as { version: string }).version;
401
405
 
402
406
  ${createModuleFederationRemoteUrlHelpers(app, remotes)}
403
- export default createModuleFederationConfig({
407
+ const moduleFederationConfig: Parameters<
408
+ typeof createModuleFederationConfig
409
+ >[0] = createModuleFederationConfig({
404
410
  bridge: {
405
411
  enableBridgeRouter: false,
406
412
  },
@@ -419,6 +425,8 @@ export default createModuleFederationConfig({
419
425
  ${createModuleFederationRemotesConfig(scope, app, remotes)}${createSharedModuleFederationConfig()},
420
426
  treeShakingSharedExcludePlugins: ['RspackModuleFederationPlugin'],
421
427
  });
428
+
429
+ export default moduleFederationConfig;
422
430
  `;
423
431
  }
424
432
  export { createAppModernConfig, createBuildMarker, createModuleFederationRemoteUrlHelpers, createModuleFederationRemotesConfig, createRemoteModuleFederationConfig, createSharedModuleFederationConfig, createShellModuleFederationConfig, createUltramodernBuildModule, formatTsObjectLiteral };
@@ -255,6 +255,10 @@ function createTsBuildInfoFile(packageDir) {
255
255
  const cacheKey = packageDir.replace(/[^a-zA-Z0-9._-]+/gu, '__');
256
256
  return `${relativeRootFor(packageDir)}/node_modules/.cache/tsgo/${cacheKey}.tsbuildinfo`;
257
257
  }
258
+ function createTsDeclarationOutDir(packageDir) {
259
+ const cacheKey = packageDir.replace(/[^a-zA-Z0-9._-]+/gu, '__');
260
+ return `${relativeRootFor(packageDir)}/node_modules/.cache/tsgo/declarations/${cacheKey}`;
261
+ }
258
262
  function createReferences(packageDir, references) {
259
263
  return [
260
264
  ...new Set(references)
@@ -268,8 +272,10 @@ function createPackageTsConfig(packageDir, options = {}) {
268
272
  } : options;
269
273
  const include = resolvedOptions.include ?? [
270
274
  'src',
275
+ 'locales/**/*.json',
271
276
  'modern.config.ts',
272
- 'module-federation.config.ts'
277
+ 'module-federation.config.ts',
278
+ 'package.json'
273
279
  ];
274
280
  if (resolvedOptions.includeApi) include.push('api', 'shared');
275
281
  const references = createReferences(packageDir, resolvedOptions.references ?? []);
@@ -277,7 +283,12 @@ function createPackageTsConfig(packageDir, options = {}) {
277
283
  extends: `${relativeRootFor(packageDir)}/tsconfig.base.json`,
278
284
  compilerOptions: {
279
285
  composite: true,
286
+ declaration: true,
287
+ declarationMap: false,
288
+ emitDeclarationOnly: true,
280
289
  incremental: true,
290
+ noEmit: false,
291
+ outDir: createTsDeclarationOutDir(packageDir),
281
292
  tsBuildInfoFile: createTsBuildInfoFile(packageDir)
282
293
  },
283
294
  include
@@ -669,6 +669,7 @@ function createTemplateManifest(modernVersion, packageSource) {
669
669
  'pnpm-workspace.yaml',
670
670
  "scripts/**",
671
671
  'topology/**',
672
+ 'tsconfig.json',
672
673
  'tsconfig.base.json'
673
674
  ],
674
675
  deniedPaths: [
@@ -733,6 +734,7 @@ function createTemplateManifest(modernVersion, packageSource) {
733
734
  expectedCommands: [
734
735
  'mise install',
735
736
  'pnpm install',
737
+ 'pnpm run typecheck',
736
738
  'pnpm run i18n:boundaries',
737
739
  'pnpm run contract:check',
738
740
  'pnpm run performance:readiness'
@@ -11,8 +11,7 @@ import { VerticalShowcase } from '../vertical-components';
11
11
  import { ultramodernUiMarker } from '../../ultramodern-build';
12
12
 
13
13
  export default function ShellHome() {
14
- const { i18nInstance } = useModernI18n();
15
- const t = i18nInstance['t'].bind(i18nInstance);
14
+ const { t } = useModernI18n();
16
15
 
17
16
  return (
18
17
  <ShellFrame>
@@ -85,8 +84,7 @@ const loadRemoteComponent = (specifier: string) =>
85
84
 
86
85
  const createRemoteFallback = (specifier: string) =>
87
86
  ({ error }: { error: Error }) => {
88
- const { i18nInstance } = useModernI18n();
89
- const t = i18nInstance['t'].bind(i18nInstance);
87
+ const { t } = useModernI18n();
90
88
  const classification = classifyModuleFederationFallback(error);
91
89
  const telemetry = createModuleFederationFallbackTelemetry({
92
90
  appName: '${shellApp.id}',
@@ -113,7 +111,7 @@ const createRemoteFallback = (specifier: string) =>
113
111
  remote: specifier,
114
112
  status: 'degraded',
115
113
  });
116
- }, [classification, error, specifier, telemetry]);
114
+ }, [classification, error, telemetry]);
117
115
 
118
116
  return <div className="${tw('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} {...toModuleFederationFallbackAttributes(telemetry)}>{t('shell.remoteUnavailable')}</div>;
119
117
  };
@@ -168,8 +166,7 @@ const createHydratedRemote =
168
166
  ${hydratedExports}
169
167
 
170
168
  export const Header = () => {
171
- const { i18nInstance } = useModernI18n();
172
- const t = i18nInstance['t'].bind(i18nInstance);
169
+ const { t } = useModernI18n();
173
170
 
174
171
  return (
175
172
  <header className="${tw('flex min-w-0 flex-wrap items-center gap-x-8 gap-y-2 md:flex-1')}" data-modern-boundary-id="${shellApp.mfName}" data-modern-mf-expose="shell/Header">
@@ -179,8 +176,7 @@ const createHydratedRemote =
179
176
  };
180
177
 
181
178
  export const StatusBadge = () => {
182
- const { i18nInstance } = useModernI18n();
183
- const t = i18nInstance['t'].bind(i18nInstance);
179
+ const { t } = useModernI18n();
184
180
 
185
181
  return (
186
182
  <span className="${tw('inline-flex h-10 shrink-0 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 text-sm font-extrabold text-stone-950 shadow-lg shadow-stone-900/5')}">
@@ -190,8 +186,7 @@ export const StatusBadge = () => {
190
186
  };
191
187
 
192
188
  export const VerticalShowcase = () => {
193
- const { i18nInstance } = useModernI18n();
194
- const t = i18nInstance['t'].bind(i18nInstance);
189
+ const { t } = useModernI18n();
195
190
 
196
191
  if (widgetCount === 0) {
197
192
  return (
@@ -258,8 +253,7 @@ import { ultramodernUiMarker } from '../../ultramodern-build';
258
253
  ` : '';
259
254
  return `${effectBffImport}
260
255
  export default function ${toPascalCase(app.id)}Home() {
261
- const { i18nInstance, language, supportedLanguages } = useModernI18n();
262
- const t = i18nInstance['t'].bind(i18nInstance);
256
+ const { language, supportedLanguages, t } = useModernI18n();
263
257
  ${effectBffState} return (
264
258
  <main className="${tw('min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8')}">
265
259
  <UltramodernRouteHead />
@@ -305,8 +299,7 @@ function createRemoteEntry(app) {
305
299
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
306
300
 
307
301
  export default function ${toPascalCase(domain)}Route() {
308
- const { i18nInstance } = useModernI18n();
309
- const t = i18nInstance['t'].bind(i18nInstance);
302
+ const { t } = useModernI18n();
310
303
 
311
304
  return (
312
305
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Route">
@@ -324,8 +317,7 @@ function createRemoteWidget(app) {
324
317
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
325
318
 
326
319
  export default function ${componentName}() {
327
- const { i18nInstance } = useModernI18n();
328
- const t = i18nInstance['t'].bind(i18nInstance);
320
+ const { t } = useModernI18n();
329
321
 
330
322
  return (
331
323
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Widget">
@@ -344,8 +336,7 @@ function createRemoteExposeComponent(app, expose) {
344
336
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
345
337
 
346
338
  export default function ${componentName}() {
347
- const { i18nInstance } = useModernI18n();
348
- const t = i18nInstance['t'].bind(i18nInstance);
339
+ const { t } = useModernI18n();
349
340
 
350
341
  return (
351
342
  <section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="${expose}">