@bleedingdev/modern-js-create 3.2.0-ultramodern.2 → 3.2.0-ultramodern.20

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 (63) hide show
  1. package/README.md +12 -0
  2. package/dist/index.js +676 -198
  3. package/package.json +5 -2
  4. package/template/.agents/skills-lock.json +34 -0
  5. package/template/.github/renovate.json +53 -0
  6. package/template/.github/workflows/ultramodern-gates.yml.handlebars +26 -4
  7. package/template/AGENTS.md +27 -0
  8. package/template/README.md +7 -3
  9. package/template/api/effect/index.ts.handlebars +7 -45
  10. package/template/config/public/locales/cs/translation.json +39 -0
  11. package/template/config/public/locales/en/translation.json +39 -0
  12. package/template/modern.config.ts.handlebars +44 -23
  13. package/template/oxfmt.config.ts +8 -0
  14. package/template/oxlint.config.ts +12 -0
  15. package/template/package.json.handlebars +56 -27
  16. package/template/pnpm-workspace.yaml +24 -0
  17. package/template/rstest.config.mts +7 -0
  18. package/template/scripts/bootstrap-agent-skills.mjs +95 -0
  19. package/template/scripts/check-i18n-strings.mjs +83 -0
  20. package/template/scripts/validate-ultramodern.mjs.handlebars +350 -16
  21. package/template/shared/effect/api.ts.handlebars +1 -2
  22. package/template/src/modern-app-env.d.ts +2 -0
  23. package/template/src/modern.runtime.ts.handlebars +17 -3
  24. package/template/src/routes/[lang]/page.tsx.handlebars +211 -0
  25. package/template/src/routes/index.css.handlebars +14 -3
  26. package/template/src/routes/layout.tsx.handlebars +1 -1
  27. package/template/tests/tsconfig.json +7 -0
  28. package/template/tests/ultramodern.contract.test.ts +67 -0
  29. package/template/tsconfig.json +106 -2
  30. package/template-workspace/.agents/agent-reference-repos.json +23 -0
  31. package/template-workspace/.agents/rstackjs-agent-skills-LICENSE +21 -0
  32. package/template-workspace/.agents/skills/rsbuild-best-practices/SKILL.md +57 -0
  33. package/template-workspace/.agents/skills/rsdoctor-analysis/SKILL.md +96 -0
  34. package/template-workspace/.agents/skills/rsdoctor-analysis/references/command-map.md +113 -0
  35. package/template-workspace/.agents/skills/rsdoctor-analysis/references/common-analysis-patterns.md +190 -0
  36. package/template-workspace/.agents/skills/rsdoctor-analysis/references/install-rsdoctor-common.md +88 -0
  37. package/template-workspace/.agents/skills/rsdoctor-analysis/references/install-rsdoctor-rspack.md +138 -0
  38. package/template-workspace/.agents/skills/rsdoctor-analysis/references/install-rsdoctor-webpack.md +71 -0
  39. package/template-workspace/.agents/skills/rsdoctor-analysis/references/install-rsdoctor.md +39 -0
  40. package/template-workspace/.agents/skills/rsdoctor-analysis/references/rsdoctor-data-types.md +103 -0
  41. package/template-workspace/.agents/skills/rslib-best-practices/SKILL.md +58 -0
  42. package/template-workspace/.agents/skills/rslib-modern-package/SKILL.md +173 -0
  43. package/template-workspace/.agents/skills/rspack-best-practices/SKILL.md +70 -0
  44. package/template-workspace/.agents/skills/rspack-tracing/SKILL.md +75 -0
  45. package/template-workspace/.agents/skills/rspack-tracing/references/bottlenecks.md +47 -0
  46. package/template-workspace/.agents/skills/rspack-tracing/references/tracing-guide.md +38 -0
  47. package/template-workspace/.agents/skills/rspack-tracing/scripts/analyze_trace.js +184 -0
  48. package/template-workspace/.agents/skills/rstest-best-practices/SKILL.md +133 -0
  49. package/template-workspace/.agents/skills-lock.json +95 -0
  50. package/template-workspace/.github/renovate.json +29 -0
  51. package/template-workspace/.github/workflows/ultramodern-workspace-gates.yml.handlebars +52 -0
  52. package/template-workspace/.gitignore.handlebars +6 -0
  53. package/template-workspace/AGENTS.md +61 -0
  54. package/template-workspace/README.md.handlebars +11 -1
  55. package/template-workspace/oxfmt.config.ts +16 -0
  56. package/template-workspace/oxlint.config.ts +19 -0
  57. package/template-workspace/pnpm-workspace.yaml +24 -6
  58. package/template-workspace/scripts/bootstrap-agent-skills.mjs +95 -0
  59. package/template-workspace/scripts/check-i18n-strings.mjs +83 -0
  60. package/template-workspace/scripts/setup-agent-reference-repos.mjs +217 -0
  61. package/template-workspace/scripts/validate-ultramodern-workspace.mjs.handlebars +397 -59
  62. package/template/biome.json +0 -41
  63. package/template/src/routes/page.tsx.handlebars +0 -119
package/dist/index.js CHANGED
@@ -485,7 +485,7 @@ const EN_LOCALE = {
485
485
  example7: ' create my-app --bff',
486
486
  example8: ' create my-app --router tanstack --bff-runtime effect',
487
487
  example9: ' create my-app --router tanstack --bff-runtime effect --workspace',
488
- example10: ' create my-super-app --ultramodern-workspace --ultramodern-package-source install --ultramodern-package-scope bleedingdev',
488
+ example10: ' pnpm dlx @bleedingdev/modern-js-create my-super-app',
489
489
  moreInfo: '📚 Learn more: https://modernjs.dev'
490
490
  },
491
491
  version: {
@@ -556,13 +556,39 @@ const ultramodern_workspace_dirname = node_path.dirname(fileURLToPath(import.met
556
556
  const workspaceTemplateDir = node_path.resolve(ultramodern_workspace_dirname, '..', 'template-workspace');
557
557
  const TANSTACK_ROUTER_VERSION = '1.170.1';
558
558
  const MODULE_FEDERATION_VERSION = '2.4.0';
559
- const TYPESCRIPT_VERSION = '6.0.3';
559
+ const ZEPHYR_MODERNJS_PLUGIN_VERSION = '1.1.1';
560
+ const EFFECT_TSGO_VERSION = '0.7.3';
561
+ const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260518.1';
562
+ const OXLINT_VERSION = '1.65.0';
563
+ const OXFMT_VERSION = '0.50.0';
564
+ const ULTRACITE_VERSION = '7.7.0';
565
+ const I18NEXT_VERSION = '26.2.0';
560
566
  const REACT_VERSION = '^19.2.6';
561
567
  const REACT_DOM_VERSION = '^19.2.6';
568
+ const REACT_I18NEXT_VERSION = '17.0.8';
562
569
  const WORKSPACE_PACKAGE_VERSION = 'workspace:*';
570
+ const RSTACK_AGENT_SKILLS_COMMIT = '61c948b42512e223bad44b83af4080eba48b2677';
571
+ const baselineAgentSkills = [
572
+ 'rsbuild-best-practices',
573
+ 'rspack-best-practices',
574
+ 'rspack-tracing',
575
+ 'rsdoctor-analysis',
576
+ 'rslib-best-practices',
577
+ 'rslib-modern-package',
578
+ 'rstest-best-practices'
579
+ ];
580
+ const privateAgentSkills = [
581
+ 'plan-graph',
582
+ 'dag',
583
+ 'subagent-graph',
584
+ 'helm',
585
+ 'debugger-mode'
586
+ ];
587
+ const effectTsgoTypecheckCommand = "node -e \"const fs = require('node:fs'); const { execFileSync, spawnSync } = require('node:child_process'); const bin = execFileSync('effect-tsgo', ['get-exe-path'], { encoding: 'utf8' }).trim(); if (process.platform !== 'win32') fs.chmodSync(bin, 0o755); const result = spawnSync(bin, ['--noEmit', '-p', 'tsconfig.json'], { stdio: 'inherit' }); process.exit(result.status ?? 1);\"";
563
588
  const modernPackageNames = [
564
589
  '@modern-js/app-tools',
565
590
  '@modern-js/plugin-bff',
591
+ '@modern-js/plugin-i18n',
566
592
  '@modern-js/plugin-tanstack',
567
593
  '@modern-js/runtime'
568
594
  ];
@@ -609,7 +635,7 @@ const remoteApps = [
609
635
  mfName: 'remoteCommerce',
610
636
  exposes: {
611
637
  './Route': './src/remote-entry.tsx',
612
- './Widget': './src/components/CommerceWidget.tsx'
638
+ './Widget': './src/components/commerce-widget.tsx'
613
639
  },
614
640
  ownership: {
615
641
  team: 'commerce-experience',
@@ -638,7 +664,7 @@ const remoteApps = [
638
664
  mfName: 'remoteIdentity',
639
665
  exposes: {
640
666
  './Route': './src/remote-entry.tsx',
641
- './Widget': './src/components/IdentityWidget.tsx'
667
+ './Widget': './src/components/identity-widget.tsx'
642
668
  },
643
669
  ownership: {
644
670
  team: 'identity-platform',
@@ -666,7 +692,7 @@ const remoteApps = [
666
692
  port: 3023,
667
693
  mfName: 'remoteDesignSystem',
668
694
  exposes: {
669
- './Button': './src/components/Button.tsx',
695
+ './Button': './src/components/button.tsx',
670
696
  './tokens': './src/tokens.ts'
671
697
  },
672
698
  ownership: {
@@ -706,6 +732,81 @@ const effectService = {
706
732
  }
707
733
  }
708
734
  };
735
+ const effectDiagnostics = [
736
+ 'anyUnknownInErrorContext',
737
+ 'classSelfMismatch',
738
+ 'duplicatePackage',
739
+ 'effectFnImplicitAny',
740
+ 'floatingEffect',
741
+ 'genericEffectServices',
742
+ 'missingEffectContext',
743
+ 'missingEffectError',
744
+ 'missingLayerContext',
745
+ 'missingReturnYieldStar',
746
+ 'missingStarInYieldEffectGen',
747
+ 'nonObjectEffectServiceType',
748
+ 'outdatedApi',
749
+ 'overriddenSchemaConstructor',
750
+ 'catchUnfailableEffect',
751
+ 'effectFnIife',
752
+ 'effectGenUsesAdapter',
753
+ 'effectInFailure',
754
+ 'effectInVoidSuccess',
755
+ 'globalErrorInEffectCatch',
756
+ 'globalErrorInEffectFailure',
757
+ 'layerMergeAllWithDependencies',
758
+ 'lazyPromiseInEffectSync',
759
+ 'leakingRequirements',
760
+ 'multipleEffectProvide',
761
+ 'returnEffectInGen',
762
+ 'runEffectInsideEffect',
763
+ 'schemaSyncInEffect',
764
+ 'scopeInLayerEffect',
765
+ 'strictEffectProvide',
766
+ 'tryCatchInEffectGen',
767
+ 'unknownInEffectCatch',
768
+ 'asyncFunction',
769
+ 'cryptoRandomUUID',
770
+ 'cryptoRandomUUIDInEffect',
771
+ 'extendsNativeError',
772
+ 'globalConsole',
773
+ 'globalConsoleInEffect',
774
+ 'globalDate',
775
+ 'globalDateInEffect',
776
+ 'globalFetch',
777
+ 'globalFetchInEffect',
778
+ 'globalRandom',
779
+ 'globalRandomInEffect',
780
+ 'globalTimers',
781
+ 'globalTimersInEffect',
782
+ 'instanceOfSchema',
783
+ 'newPromise',
784
+ 'nodeBuiltinImport',
785
+ 'preferSchemaOverJson',
786
+ 'processEnv',
787
+ 'processEnvInEffect',
788
+ 'unsafeEffectTypeAssertion',
789
+ 'catchAllToMapError',
790
+ 'deterministicKeys',
791
+ 'effectDoNotation',
792
+ 'effectFnOpportunity',
793
+ 'effectMapFlatten',
794
+ 'effectMapVoid',
795
+ 'effectSucceedWithVoid',
796
+ 'missedPipeableOpportunity',
797
+ 'missingEffectServiceDependency',
798
+ 'nestedEffectGenYield',
799
+ 'redundantSchemaTagIdentifier',
800
+ 'schemaStructWithTag',
801
+ 'schemaUnionOfLiterals',
802
+ 'serviceNotAsClass',
803
+ 'strictBooleanExpressions',
804
+ 'unnecessaryArrowBlock',
805
+ 'unnecessaryEffectGen',
806
+ 'unnecessaryFailYieldableError',
807
+ 'unnecessaryPipe',
808
+ 'unnecessaryPipeChain'
809
+ ];
709
810
  const sharedPackages = [
710
811
  {
711
812
  id: 'shared-contracts',
@@ -820,24 +921,29 @@ function modernPackageSpecifier(packageName, packageSource) {
820
921
  }
821
922
  function appDependencies(scope, packageSource) {
822
923
  return {
924
+ '@modern-js/plugin-i18n': modernPackageSpecifier('@modern-js/plugin-i18n', packageSource),
823
925
  '@modern-js/plugin-tanstack': modernPackageSpecifier('@modern-js/plugin-tanstack', packageSource),
824
926
  '@modern-js/runtime': modernPackageSpecifier('@modern-js/runtime', packageSource),
825
927
  '@module-federation/modern-js-v3': MODULE_FEDERATION_VERSION,
826
928
  '@module-federation/runtime': MODULE_FEDERATION_VERSION,
827
929
  '@tanstack/react-router': TANSTACK_ROUTER_VERSION,
930
+ 'zephyr-modernjs-plugin': ZEPHYR_MODERNJS_PLUGIN_VERSION,
828
931
  [ultramodern_workspace_packageName(scope, 'shared-contracts')]: WORKSPACE_PACKAGE_VERSION,
829
932
  [ultramodern_workspace_packageName(scope, 'shared-design-tokens')]: WORKSPACE_PACKAGE_VERSION,
933
+ i18next: I18NEXT_VERSION,
830
934
  react: REACT_VERSION,
831
- 'react-dom': REACT_DOM_VERSION
935
+ 'react-dom': REACT_DOM_VERSION,
936
+ 'react-i18next': REACT_I18NEXT_VERSION
832
937
  };
833
938
  }
834
939
  function appDevDependencies(packageSource) {
835
940
  return {
836
941
  '@modern-js/app-tools': modernPackageSpecifier('@modern-js/app-tools', packageSource),
942
+ '@effect/tsgo': EFFECT_TSGO_VERSION,
943
+ "@typescript/native-preview": TYPESCRIPT_NATIVE_PREVIEW_VERSION,
837
944
  '@types/node': '^20',
838
945
  '@types/react': '^19.1.8',
839
- '@types/react-dom': '^19.1.6',
840
- typescript: TYPESCRIPT_VERSION
946
+ '@types/react-dom': '^19.1.6'
841
947
  };
842
948
  }
843
949
  function createRootPackageJson(scope, packageSource) {
@@ -845,6 +951,8 @@ function createRootPackageJson(scope, packageSource) {
845
951
  private: true,
846
952
  name: scope,
847
953
  version: '0.1.0',
954
+ type: 'module',
955
+ packageManager: 'pnpm@11.1.2',
848
956
  scripts: {
849
957
  dev: `pnpm --parallel --filter ${ultramodern_workspace_packageName(scope, shellApp.packageSuffix)} --filter ${ultramodern_workspace_packageName(scope, 'remote-commerce')} --filter ${ultramodern_workspace_packageName(scope, 'remote-identity')} --filter ${ultramodern_workspace_packageName(scope, 'remote-design-system')} dev`,
850
958
  'dev:shell': `pnpm --filter ${ultramodern_workspace_packageName(scope, shellApp.packageSuffix)} dev`,
@@ -853,13 +961,23 @@ function createRootPackageJson(scope, packageSource) {
853
961
  'dev:design-system': `pnpm --filter ${ultramodern_workspace_packageName(scope, 'remote-design-system')} dev`,
854
962
  'dev:recommendations': `pnpm --filter ${ultramodern_workspace_packageName(scope, effectService.packageSuffix)} dev`,
855
963
  build: 'pnpm -r --filter ./apps/** --filter ./services/** build',
856
- typecheck: 'pnpm -r --filter ./apps/** --filter ./services/** --filter ./packages/** typecheck',
964
+ format: 'oxfmt .',
965
+ 'format:check': 'oxfmt --check .',
966
+ 'i18n:check': "node ./scripts/check-i18n-strings.mjs",
967
+ lint: 'oxlint .',
968
+ 'lint:fix': 'oxlint . --fix',
969
+ typecheck: `pnpm -r --filter "@${scope}/*" typecheck`,
970
+ 'skills:install': "node ./scripts/bootstrap-agent-skills.mjs",
971
+ 'skills:check': "node ./scripts/bootstrap-agent-skills.mjs --check",
972
+ 'agents:refs:install': "node ./scripts/setup-agent-reference-repos.mjs",
973
+ 'agents:refs:check': "node ./scripts/setup-agent-reference-repos.mjs --check",
857
974
  'ultramodern:check': "node ./scripts/validate-ultramodern-workspace.mjs",
858
- check: 'pnpm ultramodern:check'
975
+ postinstall: "node ./scripts/setup-agent-reference-repos.mjs",
976
+ check: 'pnpm format:check && pnpm lint && pnpm typecheck && pnpm i18n:check && pnpm skills:check && pnpm ultramodern:check'
859
977
  },
860
978
  engines: {
861
979
  node: '>=20',
862
- pnpm: '>=10.0.0'
980
+ pnpm: '>=11.0.0'
863
981
  },
864
982
  workspaces: [
865
983
  'apps/*',
@@ -878,35 +996,56 @@ function createRootPackageJson(scope, packageSource) {
878
996
  }
879
997
  },
880
998
  devDependencies: {
881
- '@biomejs/biome': '1.9.4',
882
- typescript: TYPESCRIPT_VERSION
999
+ '@effect/tsgo': EFFECT_TSGO_VERSION,
1000
+ "@typescript/native-preview": TYPESCRIPT_NATIVE_PREVIEW_VERSION,
1001
+ oxlint: OXLINT_VERSION,
1002
+ oxfmt: OXFMT_VERSION,
1003
+ ultracite: ULTRACITE_VERSION
883
1004
  }
884
1005
  };
885
1006
  }
886
- function createTsConfigBase(scope) {
1007
+ function createTsConfigBase() {
887
1008
  return {
888
1009
  compilerOptions: {
889
- target: 'ES2022',
1010
+ target: 'ESNext',
890
1011
  lib: [
1012
+ 'ESNext',
891
1013
  'DOM',
892
- 'DOM.Iterable',
893
- 'ES2022'
1014
+ 'DOM.Iterable'
894
1015
  ],
895
- module: 'ESNext',
1016
+ module: 'preserve',
896
1017
  moduleResolution: 'Bundler',
1018
+ moduleDetection: 'force',
897
1019
  jsx: 'preserve',
1020
+ isolatedModules: true,
1021
+ verbatimModuleSyntax: true,
898
1022
  strict: true,
899
1023
  noEmit: true,
1024
+ allowJs: true,
900
1025
  esModuleInterop: true,
1026
+ noUncheckedIndexedAccess: true,
1027
+ exactOptionalPropertyTypes: true,
1028
+ noImplicitOverride: true,
1029
+ noFallthroughCasesInSwitch: true,
1030
+ noPropertyAccessFromIndexSignature: true,
1031
+ noImplicitReturns: true,
901
1032
  skipLibCheck: true,
902
1033
  resolveJsonModule: true,
903
- baseUrl: '.',
904
- paths: Object.fromEntries(sharedPackages.map((sharedPackage)=>[
905
- ultramodern_workspace_packageName(scope, sharedPackage.id),
906
- [
907
- `${sharedPackage.directory}/src/index.ts`
908
- ]
909
- ]))
1034
+ plugins: [
1035
+ {
1036
+ name: '@effect/language-service',
1037
+ diagnostics: true,
1038
+ includeSuggestionsInTsc: true,
1039
+ ignoreEffectSuggestionsInTscExitCode: false,
1040
+ ignoreEffectWarningsInTscExitCode: false,
1041
+ ignoreEffectErrorsInTscExitCode: false,
1042
+ skipDisabledOptimization: true,
1043
+ diagnosticSeverity: Object.fromEntries(effectDiagnostics.map((name)=>[
1044
+ name,
1045
+ 'error'
1046
+ ]))
1047
+ }
1048
+ ]
910
1049
  }
911
1050
  };
912
1051
  }
@@ -919,20 +1058,6 @@ function createPackageTsConfig(packageDir, includeApi = false) {
919
1058
  if (includeApi) include.push('api', 'shared');
920
1059
  return {
921
1060
  extends: `${relativeRootFor(packageDir)}/tsconfig.base.json`,
922
- compilerOptions: {
923
- baseUrl: '.',
924
- paths: {
925
- '@/*': [
926
- './src/*'
927
- ],
928
- '@api/*': [
929
- './api/*'
930
- ],
931
- '@shared/*': [
932
- './shared/*'
933
- ]
934
- }
935
- },
936
1061
  include
937
1062
  };
938
1063
  }
@@ -945,7 +1070,7 @@ function createAppPackage(scope, app, packageSource) {
945
1070
  dev: 'modern dev',
946
1071
  build: 'modern build',
947
1072
  serve: 'modern serve',
948
- typecheck: 'tsgo --noEmit -p tsconfig.json'
1073
+ typecheck: effectTsgoTypecheckCommand
949
1074
  },
950
1075
  modernjs: {
951
1076
  preset: 'presetUltramodern',
@@ -966,7 +1091,7 @@ function createServicePackage(scope, packageSource) {
966
1091
  dev: 'modern dev',
967
1092
  build: 'modern build',
968
1093
  serve: 'modern serve',
969
- typecheck: 'tsgo --noEmit -p tsconfig.json'
1094
+ typecheck: effectTsgoTypecheckCommand
970
1095
  },
971
1096
  modernjs: {
972
1097
  preset: 'presetUltramodern',
@@ -983,10 +1108,11 @@ function createServicePackage(scope, packageSource) {
983
1108
  devDependencies: {
984
1109
  '@modern-js/app-tools': modernPackageSpecifier('@modern-js/app-tools', packageSource),
985
1110
  '@modern-js/plugin-bff': modernPackageSpecifier('@modern-js/plugin-bff', packageSource),
1111
+ '@effect/tsgo': EFFECT_TSGO_VERSION,
1112
+ "@typescript/native-preview": TYPESCRIPT_NATIVE_PREVIEW_VERSION,
986
1113
  '@types/node': '^20',
987
1114
  '@types/react': '^19.1.8',
988
- '@types/react-dom': '^19.1.6',
989
- typescript: TYPESCRIPT_VERSION
1115
+ '@types/react-dom': '^19.1.6'
990
1116
  }
991
1117
  };
992
1118
  }
@@ -1001,46 +1127,84 @@ function createSharedPackage(scope, id, description) {
1001
1127
  '.': './src/index.ts'
1002
1128
  },
1003
1129
  scripts: {
1004
- typecheck: 'tsgo --noEmit -p tsconfig.json'
1130
+ typecheck: effectTsgoTypecheckCommand
1005
1131
  },
1006
1132
  devDependencies: {
1007
- typescript: TYPESCRIPT_VERSION
1133
+ '@effect/tsgo': EFFECT_TSGO_VERSION,
1134
+ "@typescript/native-preview": TYPESCRIPT_NATIVE_PREVIEW_VERSION
1008
1135
  }
1009
1136
  };
1010
1137
  }
1011
1138
  function createAppModernConfig(app) {
1012
- return `import { appTools, defineConfig, presetUltramodern } from '@modern-js/app-tools';
1139
+ return `// @effect-diagnostics processEnv:off
1140
+ import { appTools, defineConfig, presetUltramodern } from '@modern-js/app-tools';
1141
+ import { i18nPlugin } from '@modern-js/plugin-i18n';
1013
1142
  import { tanstackRouterPlugin } from '@modern-js/plugin-tanstack';
1014
1143
  import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
1144
+ import { withZephyr } from 'zephyr-modernjs-plugin';
1015
1145
 
1016
1146
  const appId = '${app.id}';
1017
- const port = Number(process.env.${app.portEnv} ?? ${app.port});
1147
+ const port = Number(process.env['${app.portEnv}'] ?? ${app.port});
1148
+ const configuredSiteUrl = process.env['MODERN_PUBLIC_SITE_URL'];
1149
+ const hasConfiguredSiteUrl = typeof configuredSiteUrl === 'string' && configuredSiteUrl.length > 0;
1150
+ const isProductionBuild =
1151
+ process.env['NODE_ENV'] === 'production' || process.argv.includes('build');
1152
+
1153
+ if (isProductionBuild && !hasConfiguredSiteUrl) {
1154
+ throw new Error(
1155
+ 'MODERN_PUBLIC_SITE_URL must be set for production builds so canonical and hreflang URLs use the deployed origin.',
1156
+ );
1157
+ }
1158
+
1159
+ const siteUrl = hasConfiguredSiteUrl ? configuredSiteUrl : \`http://localhost:\${port}\`;
1018
1160
 
1019
1161
  export default defineConfig(
1020
1162
  presetUltramodern(
1021
1163
  {
1022
- server: {
1023
- port,
1024
- ssr: {
1025
- mode: 'string',
1026
- moduleFederationAppSSR: true,
1027
- },
1028
- },
1029
1164
  output: {
1030
- polyfill: 'off',
1031
1165
  disableTsChecker: true,
1166
+ distPath: {
1167
+ html: './',
1168
+ },
1169
+ polyfill: 'off',
1032
1170
  splitRouteChunks: false,
1033
1171
  },
1172
+ html: {
1173
+ outputStructure: 'flat',
1174
+ },
1034
1175
  plugins: [
1035
- appTools(),
1176
+ appTools({
1177
+ bundler: 'rspack',
1178
+ }),
1179
+ i18nPlugin({
1180
+ localeDetection: {
1181
+ fallbackLanguage: 'en',
1182
+ languages: ['en', 'cs'],
1183
+ localePathRedirect: true,
1184
+ },
1185
+ }),
1036
1186
  tanstackRouterPlugin(),
1037
1187
  moduleFederationPlugin(),
1188
+ withZephyr(),
1038
1189
  ],
1190
+ server: {
1191
+ port,
1192
+ ssr: {
1193
+ mode: 'string',
1194
+ moduleFederationAppSSR: true,
1195
+ },
1196
+ },
1197
+ source: {
1198
+ mainEntryName: 'index',
1199
+ globalVars: {
1200
+ ULTRAMODERN_SITE_URL: siteUrl,
1201
+ },
1202
+ },
1039
1203
  },
1040
1204
  {
1041
1205
  appId,
1042
- enableModuleFederationSSR: true,
1043
1206
  enableBffRequestId: true,
1207
+ enableModuleFederationSSR: true,
1044
1208
  enableTelemetryExporters: true,
1045
1209
  telemetryFailLoudStartup: false,
1046
1210
  },
@@ -1048,129 +1212,122 @@ export default defineConfig(
1048
1212
  );
1049
1213
  `;
1050
1214
  }
1215
+ function createSharedModuleFederationConfig() {
1216
+ return ` shared: {
1217
+ '@modern-js/runtime': {
1218
+ requiredVersion: runtimeVersion,
1219
+ singleton: true,
1220
+ treeShaking: false,
1221
+ },
1222
+ '@tanstack/react-router': {
1223
+ requiredVersion: dependencies['@tanstack/react-router'],
1224
+ singleton: true,
1225
+ treeShaking: false,
1226
+ },
1227
+ i18next: {
1228
+ requiredVersion: dependencies.i18next,
1229
+ singleton: true,
1230
+ treeShaking: false,
1231
+ },
1232
+ react: {
1233
+ requiredVersion: reactVersion,
1234
+ singleton: true,
1235
+ treeShaking: false,
1236
+ },
1237
+ 'react-dom': {
1238
+ requiredVersion: reactDomVersion,
1239
+ singleton: true,
1240
+ treeShaking: false,
1241
+ },
1242
+ 'react-i18next': {
1243
+ requiredVersion: dependencies['react-i18next'],
1244
+ singleton: true,
1245
+ treeShaking: false,
1246
+ },
1247
+ }`;
1248
+ }
1249
+ function formatTsObjectLiteral(value) {
1250
+ const entries = Object.entries(value).sort(([left], [right])=>left.localeCompare(right));
1251
+ if (0 === entries.length) return '{}';
1252
+ return `{
1253
+ ${entries.map(([key, entryValue])=>` '${key}': '${entryValue}',`).join('\n')}
1254
+ }`;
1255
+ }
1051
1256
  function createShellModuleFederationConfig() {
1052
- return `import { createRequire } from 'node:module';
1257
+ return `// @effect-diagnostics nodeBuiltinImport:off processEnv:off
1258
+ import { createRequire } from 'node:module';
1053
1259
  import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
1054
1260
  import { dependencies } from './package.json';
1055
1261
 
1056
1262
  const require = createRequire(import.meta.url);
1057
- const runtimeVersion = (
1058
- require('@modern-js/runtime/package.json') as { version: string }
1059
- ).version;
1060
- const reactVersion = (require('react/package.json') as { version: string })
1061
- .version;
1062
- const reactDomVersion = (
1063
- require('react-dom/package.json') as { version: string }
1064
- ).version;
1263
+ const runtimeVersion = (require('@modern-js/runtime/package.json') as { version: string }).version;
1264
+ const reactVersion = (require('react/package.json') as { version: string }).version;
1265
+ const reactDomVersion = (require('react-dom/package.json') as { version: string }).version;
1065
1266
 
1066
1267
  export default createModuleFederationConfig({
1067
- name: '${shellApp.mfName}',
1068
1268
  dts: false,
1269
+ filename: 'remoteEntry.js',
1270
+ name: '${shellApp.mfName}',
1069
1271
  remotes: {
1070
1272
  commerce:
1071
- process.env.REMOTE_COMMERCE_MF_MANIFEST ??
1273
+ process.env['REMOTE_COMMERCE_MF_MANIFEST'] ??
1072
1274
  'remoteCommerce@http://localhost:3021/mf-manifest.json',
1073
- identity:
1074
- process.env.REMOTE_IDENTITY_MF_MANIFEST ??
1075
- 'remoteIdentity@http://localhost:3022/mf-manifest.json',
1076
1275
  designSystem:
1077
- process.env.REMOTE_DESIGN_SYSTEM_MF_MANIFEST ??
1276
+ process.env['REMOTE_DESIGN_SYSTEM_MF_MANIFEST'] ??
1078
1277
  'remoteDesignSystem@http://localhost:3023/mf-manifest.json',
1278
+ identity:
1279
+ process.env['REMOTE_IDENTITY_MF_MANIFEST'] ??
1280
+ 'remoteIdentity@http://localhost:3022/mf-manifest.json',
1079
1281
  },
1080
- shared: {
1081
- react: {
1082
- singleton: true,
1083
- requiredVersion: reactVersion,
1084
- treeShaking: false,
1085
- },
1086
- 'react-dom': {
1087
- singleton: true,
1088
- requiredVersion: reactDomVersion,
1089
- treeShaking: false,
1090
- },
1091
- '@tanstack/react-router': {
1092
- singleton: true,
1093
- requiredVersion: dependencies['@tanstack/react-router'],
1094
- treeShaking: false,
1095
- },
1096
- '@modern-js/runtime': {
1097
- singleton: true,
1098
- requiredVersion: runtimeVersion,
1099
- treeShaking: false,
1100
- },
1101
- },
1282
+ ${createSharedModuleFederationConfig()},
1102
1283
  });
1103
1284
  `;
1104
1285
  }
1105
1286
  function createRemoteModuleFederationConfig(app) {
1106
- const exposes = JSON.stringify(app.exposes ?? {}, null, 4).replace(/^/gm, ' ');
1107
- return `import { createRequire } from 'node:module';
1287
+ const exposes = formatTsObjectLiteral(app.exposes ?? {});
1288
+ return `// @effect-diagnostics nodeBuiltinImport:off
1289
+ import { createRequire } from 'node:module';
1108
1290
  import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
1109
1291
  import { dependencies } from './package.json';
1110
1292
 
1111
1293
  const require = createRequire(import.meta.url);
1112
- const runtimeVersion = (
1113
- require('@modern-js/runtime/package.json') as { version: string }
1114
- ).version;
1115
- const reactVersion = (require('react/package.json') as { version: string })
1116
- .version;
1117
- const reactDomVersion = (
1118
- require('react-dom/package.json') as { version: string }
1119
- ).version;
1294
+ const runtimeVersion = (require('@modern-js/runtime/package.json') as { version: string }).version;
1295
+ const reactVersion = (require('react/package.json') as { version: string }).version;
1296
+ const reactDomVersion = (require('react-dom/package.json') as { version: string }).version;
1120
1297
 
1121
1298
  export default createModuleFederationConfig({
1122
- name: '${app.mfName}',
1123
1299
  dts: false,
1124
- filename: 'remoteEntry.js',
1125
1300
  exposes: ${exposes},
1126
- shared: {
1127
- react: {
1128
- singleton: true,
1129
- requiredVersion: reactVersion,
1130
- treeShaking: false,
1131
- },
1132
- 'react-dom': {
1133
- singleton: true,
1134
- requiredVersion: reactDomVersion,
1135
- treeShaking: false,
1136
- },
1137
- '@tanstack/react-router': {
1138
- singleton: true,
1139
- requiredVersion: dependencies['@tanstack/react-router'],
1140
- treeShaking: false,
1141
- },
1142
- '@modern-js/runtime': {
1143
- singleton: true,
1144
- requiredVersion: runtimeVersion,
1145
- treeShaking: false,
1146
- },
1147
- },
1301
+ filename: 'remoteEntry.js',
1302
+ name: '${app.mfName}',
1303
+ ${createSharedModuleFederationConfig()},
1148
1304
  });
1149
1305
  `;
1150
1306
  }
1151
1307
  function createServiceModernConfig() {
1152
- return `import { appTools, defineConfig, presetUltramodern } from '@modern-js/app-tools';
1308
+ return `// @effect-diagnostics processEnv:off
1309
+ import { appTools, defineConfig, presetUltramodern } from '@modern-js/app-tools';
1153
1310
  import { bffPlugin } from '@modern-js/plugin-bff';
1154
1311
 
1155
1312
  const appId = '${effectService.id}';
1156
- const port = Number(process.env.${effectService.portEnv} ?? ${effectService.port});
1313
+ const port = Number(process.env['${effectService.portEnv}'] ?? ${effectService.port});
1157
1314
 
1158
1315
  export default defineConfig(
1159
1316
  presetUltramodern(
1160
1317
  {
1161
- server: {
1162
- port,
1163
- },
1164
1318
  bff: {
1165
- prefix: '/recommendations-api',
1166
- runtimeFramework: 'effect',
1167
1319
  effect: {
1168
1320
  openapi: {
1169
1321
  path: '/openapi.json',
1170
1322
  },
1171
1323
  },
1324
+ prefix: '/recommendations-api',
1325
+ runtimeFramework: 'effect',
1172
1326
  },
1173
1327
  plugins: [appTools(), bffPlugin()],
1328
+ server: {
1329
+ port,
1330
+ },
1174
1331
  },
1175
1332
  {
1176
1333
  appId,
@@ -1182,21 +1339,135 @@ export default defineConfig(
1182
1339
  );
1183
1340
  `;
1184
1341
  }
1342
+ function createAppRuntimeConfig() {
1343
+ return `import { defineRuntimeConfig } from '@modern-js/runtime';
1344
+ import { createInstance } from 'i18next';
1345
+
1346
+ const i18nInstance = createInstance();
1347
+
1348
+ export default defineRuntimeConfig({
1349
+ i18n: {
1350
+ i18nInstance,
1351
+ initOptions: {
1352
+ defaultNS: 'translation',
1353
+ fallbackLng: 'en',
1354
+ interpolation: {
1355
+ escapeValue: false,
1356
+ },
1357
+ ns: ['translation'],
1358
+ supportedLngs: ['en', 'cs'],
1359
+ },
1360
+ },
1361
+ router: {
1362
+ framework: 'tanstack',
1363
+ },
1364
+ });
1365
+ `;
1366
+ }
1367
+ function createLocalizedHeadComponent(includeLocationSuffix = false) {
1368
+ return `const fallbackLanguage = 'en';
1369
+ const supportedLanguages = ['en', 'cs'] as const;
1370
+ type SupportedLanguage = (typeof supportedLanguages)[number];
1371
+
1372
+ const isSupportedLanguage = (value: string): value is SupportedLanguage =>
1373
+ supportedLanguages.includes(value as SupportedLanguage);
1374
+
1375
+ const stripLanguagePrefix = (pathname: string) => {
1376
+ const segments = pathname.split('/').filter(Boolean);
1377
+ if (segments.length > 0 && isSupportedLanguage(segments[0] ?? '')) {
1378
+ segments.shift();
1379
+ }
1380
+ return \`/\${segments.join('/')}\`;
1381
+ };
1382
+
1383
+ const localizedPath = (pathname: string, language: SupportedLanguage) => {
1384
+ const pathWithoutLanguage = stripLanguagePrefix(pathname);
1385
+ return pathWithoutLanguage === '/' ? \`/\${language}\` : \`/\${language}\${pathWithoutLanguage}\`;
1386
+ };
1387
+
1388
+ const absoluteUrl = (pathname: string) => {
1389
+ const origin = ULTRAMODERN_SITE_URL.replace(/\\/+$/u, '');
1390
+ return \`\${origin}\${pathname}\`;
1391
+ };
1392
+ ${includeLocationSuffix ? `
1393
+ const locationSuffix = (location: { hash?: unknown; search?: unknown; searchStr?: unknown }) => {
1394
+ const { hash, search, searchStr } = location;
1395
+ let locationSearch = '';
1396
+ if (typeof searchStr === 'string') {
1397
+ locationSearch = searchStr;
1398
+ } else if (typeof search === 'string') {
1399
+ locationSearch = search;
1400
+ }
1401
+ const locationHash = typeof hash === 'string' ? hash : '';
1402
+ return \`\${locationSearch}\${locationHash}\`;
1403
+ };
1404
+ ` : ''}
1405
+ const LocalizedHead = () => {
1406
+ const { language } = useModernI18n();
1407
+ const location = useLocation();
1408
+ const currentLanguage = isSupportedLanguage(language) ? language : fallbackLanguage;
1409
+ const canonicalPath = localizedPath(location.pathname, currentLanguage);
1410
+
1411
+ return (
1412
+ <Helmet>
1413
+ <link rel="canonical" href={absoluteUrl(canonicalPath)} />
1414
+ {supportedLanguages.map((code) => (
1415
+ <link
1416
+ href={absoluteUrl(localizedPath(location.pathname, code))}
1417
+ hrefLang={code}
1418
+ key={code}
1419
+ rel="alternate"
1420
+ />
1421
+ ))}
1422
+ <link
1423
+ href={absoluteUrl(localizedPath(location.pathname, fallbackLanguage))}
1424
+ hrefLang="x-default"
1425
+ rel="alternate"
1426
+ />
1427
+ </Helmet>
1428
+ );
1429
+ };
1430
+ `;
1431
+ }
1185
1432
  function createShellPage() {
1186
- return `const remotes = [
1187
- 'remote-commerce',
1188
- 'remote-identity',
1189
- 'remote-design-system',
1190
- ];
1433
+ return `import { Helmet } from '@modern-js/runtime/head';
1434
+ import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
1435
+ import { useLocation } from '@modern-js/plugin-tanstack/runtime';
1436
+ import { useTranslation } from 'react-i18next';
1437
+
1438
+ const remotes = ['remote-commerce', 'remote-identity', 'remote-design-system'];
1191
1439
 
1440
+ ${createLocalizedHeadComponent(true)}
1192
1441
  export default function ShellHome() {
1442
+ const { t } = useTranslation();
1443
+ const { language } = useModernI18n();
1444
+ const location = useLocation();
1445
+ const currentLanguage = isSupportedLanguage(language) ? language : fallbackLanguage;
1446
+ const suffix = locationSuffix(location);
1447
+ const languageOptions = supportedLanguages.map((code) => ({
1448
+ code,
1449
+ href: \`\${localizedPath(location.pathname, code)}\${suffix}\`,
1450
+ label: t(\`language.\${code}\`),
1451
+ }));
1193
1452
  return (
1194
1453
  <main>
1195
- <h1>UltraModern SuperApp Shell</h1>
1196
- <p data-testid="ultramodern-preset">presetUltramodern workspace</p>
1454
+ <LocalizedHead />
1455
+ <nav aria-label={t('language.switcher')}>
1456
+ {languageOptions.map((option) => (
1457
+ <a
1458
+ aria-current={currentLanguage === option.code ? 'page' : undefined}
1459
+ href={option.href}
1460
+ key={option.code}
1461
+ >
1462
+ {option.label}
1463
+ </a>
1464
+ ))}
1465
+ </nav>
1466
+ <h1>{t('shell.title')}</h1>
1467
+ <p data-testid="ultramodern-preset">{t('shell.preset')}</p>
1197
1468
  <ul>
1198
- {remotes.map(remote => (
1199
- <li key={remote}>{remote}</li>
1469
+ {remotes.map((remote) => (
1470
+ <li key={remote}>{t(\`shell.remotes.\${remote}\`)}</li>
1200
1471
  ))}
1201
1472
  </ul>
1202
1473
  </main>
@@ -1205,11 +1476,20 @@ export default function ShellHome() {
1205
1476
  `;
1206
1477
  }
1207
1478
  function createRemotePage(app) {
1208
- return `export default function ${toPascalCase(app.id)}Home() {
1479
+ return `import { Helmet } from '@modern-js/runtime/head';
1480
+ import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
1481
+ import { useLocation } from '@modern-js/plugin-tanstack/runtime';
1482
+ import { useTranslation } from 'react-i18next';
1483
+
1484
+ ${createLocalizedHeadComponent()}
1485
+ export default function ${toPascalCase(app.id)}Home() {
1486
+ const { t } = useTranslation();
1487
+
1209
1488
  return (
1210
1489
  <main>
1211
- <h1>${app.displayName}</h1>
1212
- <p data-mf-role="${app.kind}">${app.domain ?? app.kind}</p>
1490
+ <LocalizedHead />
1491
+ <h1>{t('remote.title')}</h1>
1492
+ <p data-mf-role="${app.kind}">{t('remote.domain')}</p>
1213
1493
  </main>
1214
1494
  );
1215
1495
  }
@@ -1224,17 +1504,21 @@ export default function Layout({ children }: { children: ReactNode }) {
1224
1504
  `;
1225
1505
  }
1226
1506
  function createRemoteEntry(app) {
1227
- const componentName = 'remote-identity' === app.id ? 'IdentityWidget' : 'CommerceWidget';
1228
- return `export { default } from './components/${componentName}';
1507
+ const componentFile = 'remote-identity' === app.id ? 'identity-widget' : 'commerce-widget';
1508
+ return `export { default } from './components/${componentFile}';
1229
1509
  `;
1230
1510
  }
1231
1511
  function createRemoteWidget(app) {
1232
1512
  const componentName = 'remote-identity' === app.id ? 'IdentityWidget' : 'CommerceWidget';
1233
- return `export default function ${componentName}() {
1513
+ return `import { useTranslation } from 'react-i18next';
1514
+
1515
+ export default function ${componentName}() {
1516
+ const { t } = useTranslation();
1517
+
1234
1518
  return (
1235
1519
  <section data-mf-remote="${app.id}">
1236
- <h2>${app.displayName}</h2>
1237
- <p>Owns the ${app.domain} vertical route surface.</p>
1520
+ <h2>{t('remote.widget.title')}</h2>
1521
+ <p>{t('remote.widget.body')}</p>
1238
1522
  </section>
1239
1523
  );
1240
1524
  }
@@ -1243,7 +1527,7 @@ function createRemoteWidget(app) {
1243
1527
  function createDesignButton() {
1244
1528
  return `import { designTokens } from '../tokens';
1245
1529
 
1246
- export default function Button({ label = 'Design System Button' }: { label?: string }) {
1530
+ export default function Button({ label }: { label: string }) {
1247
1531
  return (
1248
1532
  <button
1249
1533
  type="button"
@@ -1261,8 +1545,8 @@ export default function Button({ label = 'Design System Button' }: { label?: str
1261
1545
  function createDesignTokens() {
1262
1546
  return `export const designTokens = {
1263
1547
  color: {
1264
- foreground: '#133225',
1265
1548
  accent: '#2f8f68',
1549
+ foreground: '#133225',
1266
1550
  },
1267
1551
  radius: {
1268
1552
  control: '999px',
@@ -1270,6 +1554,62 @@ function createDesignTokens() {
1270
1554
  } as const;
1271
1555
  `;
1272
1556
  }
1557
+ function createEnglishTranslations(app) {
1558
+ if ('shell' === app.kind) return {
1559
+ language: {
1560
+ cs: 'Czech',
1561
+ en: 'English',
1562
+ switcher: 'Language'
1563
+ },
1564
+ shell: {
1565
+ preset: 'presetUltramodern workspace',
1566
+ remotes: {
1567
+ 'remote-commerce': 'Commerce Remote',
1568
+ 'remote-design-system': 'Design System Remote',
1569
+ 'remote-identity': 'Identity Remote'
1570
+ },
1571
+ title: 'UltraModern SuperApp Shell'
1572
+ }
1573
+ };
1574
+ return {
1575
+ remote: {
1576
+ domain: app.domain ?? app.kind,
1577
+ title: app.displayName,
1578
+ widget: {
1579
+ body: 'vertical' === app.kind ? `Owns the ${app.domain} vertical route surface.` : 'Provides shared UI primitives for the workspace.',
1580
+ title: app.displayName
1581
+ }
1582
+ }
1583
+ };
1584
+ }
1585
+ function createCzechTranslations(app) {
1586
+ if ('shell' === app.kind) return {
1587
+ language: {
1588
+ cs: 'Cestina',
1589
+ en: 'Anglictina',
1590
+ switcher: 'Jazyk'
1591
+ },
1592
+ shell: {
1593
+ preset: 'presetUltramodern workspace',
1594
+ remotes: {
1595
+ 'remote-commerce': 'Commerce remote',
1596
+ 'remote-design-system': 'Design system remote',
1597
+ 'remote-identity': 'Identity remote'
1598
+ },
1599
+ title: 'UltraModern SuperApp shell'
1600
+ }
1601
+ };
1602
+ return {
1603
+ remote: {
1604
+ domain: app.domain ?? app.kind,
1605
+ title: app.displayName,
1606
+ widget: {
1607
+ body: 'vertical' === app.kind ? `Vlastni ${app.domain} vertical route surface.` : 'Poskytuje sdilene UI prvky pro workspace.',
1608
+ title: app.displayName
1609
+ }
1610
+ }
1611
+ };
1612
+ }
1273
1613
  function createEffectSharedApi() {
1274
1614
  return `import {
1275
1615
  HttpApi,
@@ -1283,9 +1623,7 @@ const recommendationSchema = Schema.Struct({
1283
1623
  title: Schema.String,
1284
1624
  });
1285
1625
 
1286
- export const recommendationsEffectApi = HttpApi.make(
1287
- 'RecommendationsEffectApi',
1288
- ).add(
1626
+ export const recommendationsEffectApi = HttpApi.make('RecommendationsEffectApi').add(
1289
1627
  HttpApiGroup.make('recommendations').add(
1290
1628
  HttpApiEndpoint.get('list', '/effect/recommendations', {
1291
1629
  success: Schema.Struct({
@@ -1308,7 +1646,7 @@ import { recommendationsEffectApi } from '../../shared/effect/api';
1308
1646
  const recommendationsLayer = HttpApiBuilder.group(
1309
1647
  recommendationsEffectApi,
1310
1648
  'recommendations',
1311
- (handlers: any) =>
1649
+ (handlers) =>
1312
1650
  handlers.handle('list', () =>
1313
1651
  Effect.succeed({
1314
1652
  items: [
@@ -1532,11 +1870,17 @@ function createTemplateManifest(modernVersion, packageSource) {
1532
1870
  materialization: {
1533
1871
  targetRoot: 'generated-project-root',
1534
1872
  allowedPaths: [
1873
+ '.agents/**',
1874
+ '.github/**',
1875
+ '.gitignore',
1535
1876
  '.modernjs/**',
1877
+ 'AGENTS.md',
1536
1878
  'README.md',
1537
1879
  'apps/**',
1538
1880
  'packages/**',
1539
1881
  'package.json',
1882
+ 'oxfmt.config.ts',
1883
+ 'oxlint.config.ts',
1540
1884
  'pnpm-workspace.yaml',
1541
1885
  "scripts/**",
1542
1886
  'services/**',
@@ -1545,7 +1889,6 @@ function createTemplateManifest(modernVersion, packageSource) {
1545
1889
  ],
1546
1890
  deniedPaths: [
1547
1891
  '.git/**',
1548
- '.github/**',
1549
1892
  '.npmrc',
1550
1893
  '.yarnrc',
1551
1894
  '.env',
@@ -1561,6 +1904,22 @@ function createTemplateManifest(modernVersion, packageSource) {
1561
1904
  modernPackageSpecifier: modernPackageVersion(packageSource),
1562
1905
  generatedWorkspacePackageSpecifier: WORKSPACE_PACKAGE_VERSION
1563
1906
  },
1907
+ agentSkills: {
1908
+ installDir: '.agents/skills',
1909
+ source: {
1910
+ repository: 'https://github.com/rstackjs/agent-skills',
1911
+ commit: RSTACK_AGENT_SKILLS_COMMIT,
1912
+ license: 'MIT',
1913
+ licensePath: '.agents/rstackjs-agent-skills-LICENSE'
1914
+ },
1915
+ baseline: baselineAgentSkills,
1916
+ privateSource: {
1917
+ repository: 'https://github.com/TechsioCZ/skills',
1918
+ install: 'clone-if-authorized',
1919
+ baseline: privateAgentSkills
1920
+ },
1921
+ lockFile: '.agents/skills-lock.json'
1922
+ },
1564
1923
  validation: {
1565
1924
  schemaValidation: true,
1566
1925
  sourceValidation: [
@@ -1577,10 +1936,12 @@ function createTemplateManifest(modernVersion, packageSource) {
1577
1936
  ],
1578
1937
  postMaterializationValidation: [
1579
1938
  'ultramodern-workspace-contract-check',
1939
+ 'github-workflow-security-enforced',
1940
+ 'pnpm-11-policy-enforced',
1580
1941
  'template-manifest-retained'
1581
1942
  ],
1582
1943
  expectedCommands: [
1583
- "pnpm install --ignore-scripts",
1944
+ 'pnpm install',
1584
1945
  'pnpm run ultramodern:check'
1585
1946
  ]
1586
1947
  }
@@ -1589,18 +1950,21 @@ function createTemplateManifest(modernVersion, packageSource) {
1589
1950
  function writeApp(targetDir, scope, app, packageSource) {
1590
1951
  writeJson(targetDir, `${app.directory}/package.json`, createAppPackage(scope, app, packageSource));
1591
1952
  writeJson(targetDir, `${app.directory}/tsconfig.json`, createPackageTsConfig(app.directory));
1592
- writeFile(targetDir, `${app.directory}/src/modern-app-env.d.ts`, "/// <reference types='@modern-js/app-tools/types' />\n");
1953
+ writeFile(targetDir, `${app.directory}/src/modern-app-env.d.ts`, "/// <reference types='@modern-js/app-tools/types' />\n\ndeclare const ULTRAMODERN_SITE_URL: string;\n");
1593
1954
  writeFile(targetDir, `${app.directory}/modern.config.ts`, createAppModernConfig(app));
1955
+ writeFile(targetDir, `${app.directory}/src/modern.runtime.ts`, createAppRuntimeConfig());
1956
+ writeJson(targetDir, `${app.directory}/config/public/locales/en/translation.json`, createEnglishTranslations(app));
1957
+ writeJson(targetDir, `${app.directory}/config/public/locales/cs/translation.json`, createCzechTranslations(app));
1594
1958
  writeFile(targetDir, `${app.directory}/module-federation.config.ts`, 'shell' === app.kind ? createShellModuleFederationConfig() : createRemoteModuleFederationConfig(app));
1595
1959
  writeFile(targetDir, `${app.directory}/src/routes/layout.tsx`, createLayout(app.id));
1596
- writeFile(targetDir, `${app.directory}/src/routes/page.tsx`, 'shell' === app.kind ? createShellPage() : createRemotePage(app));
1960
+ writeFile(targetDir, `${app.directory}/src/routes/[lang]/page.tsx`, 'shell' === app.kind ? createShellPage() : createRemotePage(app));
1597
1961
  if ('vertical' === app.kind) {
1598
1962
  writeFile(targetDir, `${app.directory}/src/remote-entry.tsx`, createRemoteEntry(app));
1599
- const widgetFile = 'remote-identity' === app.id ? 'IdentityWidget.tsx' : 'CommerceWidget.tsx';
1963
+ const widgetFile = 'remote-identity' === app.id ? 'identity-widget.tsx' : 'commerce-widget.tsx';
1600
1964
  writeFile(targetDir, `${app.directory}/src/components/${widgetFile}`, createRemoteWidget(app));
1601
1965
  }
1602
1966
  if ('horizontal-design-system' === app.kind) {
1603
- writeFile(targetDir, `${app.directory}/src/components/Button.tsx`, createDesignButton());
1967
+ writeFile(targetDir, `${app.directory}/src/components/button.tsx`, createDesignButton());
1604
1968
  writeFile(targetDir, `${app.directory}/src/tokens.ts`, createDesignTokens());
1605
1969
  }
1606
1970
  }
@@ -1627,27 +1991,27 @@ function writeSharedPackages(targetDir, scope) {
1627
1991
  });
1628
1992
  }
1629
1993
  writeFile(targetDir, 'packages/shared-contracts/src/index.ts', `export const ultramodernWorkspaceContract = {
1994
+ ownership: 'topology/ownership.json',
1630
1995
  preset: 'presetUltramodern',
1631
1996
  topology: 'topology/reference-topology.json',
1632
- ownership: 'topology/ownership.json',
1633
1997
  } as const;
1634
1998
  `);
1635
1999
  writeFile(targetDir, 'packages/shared-design-tokens/src/index.ts', `export const sharedDesignTokens = {
1636
2000
  color: {
1637
- surface: '#f6fbf7',
1638
- foreground: '#133225',
1639
2001
  accent: '#2f8f68',
2002
+ foreground: '#133225',
2003
+ surface: '#f6fbf7',
1640
2004
  },
1641
2005
  } as const;
1642
2006
  `);
1643
- writeFile(targetDir, 'packages/shared-effect-api/src/index.ts', `export type Recommendation = {
2007
+ writeFile(targetDir, 'packages/shared-effect-api/src/index.ts', `export interface Recommendation {
1644
2008
  id: string;
1645
2009
  title: string;
1646
- };
2010
+ }
1647
2011
 
1648
2012
  export const recommendationsApiContract = {
1649
- serviceId: '${effectService.id}',
1650
2013
  basePath: '/recommendations-api/effect/recommendations',
2014
+ serviceId: '${effectService.id}',
1651
2015
  } as const;
1652
2016
  `);
1653
2017
  }
@@ -1662,7 +2026,7 @@ function generateUltramodernWorkspace(options) {
1662
2026
  packageScope: scope
1663
2027
  });
1664
2028
  writeJson(options.targetDir, 'package.json', createRootPackageJson(scope, packageSource));
1665
- writeJson(options.targetDir, 'tsconfig.base.json', createTsConfigBase(scope));
2029
+ writeJson(options.targetDir, 'tsconfig.base.json', createTsConfigBase());
1666
2030
  writeJson(options.targetDir, 'topology/reference-topology.json', createTopology(scope));
1667
2031
  writeJson(options.targetDir, 'topology/ownership.json', createOwnership(scope));
1668
2032
  writeJson(options.targetDir, 'topology/local-overlays/development.json', createDevelopmentOverlay());
@@ -1683,7 +2047,6 @@ const templateIdPattern = /^[a-z0-9][a-z0-9._-]*$/;
1683
2047
  const packageNamePattern = /^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/;
1684
2048
  const requiredDeniedPaths = [
1685
2049
  '.git/**',
1686
- '.github/**',
1687
2050
  '.npmrc',
1688
2051
  '.yarnrc',
1689
2052
  '.env',
@@ -1746,7 +2109,7 @@ function detectBffRuntime() {
1746
2109
  process.exit(1);
1747
2110
  }
1748
2111
  function src_renderTemplate(template, data) {
1749
- const tagRegex = /\{\{(#if|#unless|\/if|\/unless)(?:\s+(\w+))?\}\}/g;
2112
+ const tagRegex = /\{\{(~?)(#if|#unless|\/if|\/unless)(?:\s+(\w+))?(~?)\}\}/g;
1750
2113
  function renderConditionals(startIndex, expectedClose) {
1751
2114
  let rendered = '';
1752
2115
  let cursor = startIndex;
@@ -1757,7 +2120,7 @@ function src_renderTemplate(template, data) {
1757
2120
  rendered: rendered + template.slice(cursor),
1758
2121
  nextIndex: template.length
1759
2122
  };
1760
- const [raw, tag, condition] = match;
2123
+ const [raw, , tag, condition, rightTrim] = match;
1761
2124
  const tagIndex = match.index;
1762
2125
  rendered += template.slice(cursor, tagIndex);
1763
2126
  cursor = tagIndex + raw.length;
@@ -1773,10 +2136,17 @@ function src_renderTemplate(template, data) {
1773
2136
  }
1774
2137
  if ('/if' === tag || '/unless' === tag) {
1775
2138
  const kind = '/if' === tag ? 'if' : 'unless';
1776
- if (expectedClose === kind) return {
1777
- rendered,
1778
- nextIndex: cursor
1779
- };
2139
+ if (expectedClose === kind) {
2140
+ let nextIndex = cursor;
2141
+ if ('~' === rightTrim) {
2142
+ const trailingWhitespace = /^\s*/u.exec(template.slice(nextIndex));
2143
+ nextIndex += trailingWhitespace?.[0].length ?? 0;
2144
+ }
2145
+ return {
2146
+ rendered,
2147
+ nextIndex
2148
+ };
2149
+ }
1780
2150
  rendered += raw;
1781
2151
  }
1782
2152
  }
@@ -1857,20 +2227,28 @@ function createBuiltinTemplateManifest(version) {
1857
2227
  materialization: {
1858
2228
  targetRoot: 'generated-project-root',
1859
2229
  allowedPaths: [
2230
+ '.agents/**',
1860
2231
  '.browserslistrc',
2232
+ '.github/**',
1861
2233
  '.gitignore',
1862
2234
  '.modernjs/**',
1863
2235
  '.nvmrc',
2236
+ 'AGENTS.md',
1864
2237
  'README.md',
1865
2238
  'api/**',
1866
- 'biome.json',
2239
+ 'config/**',
1867
2240
  'modern.config.ts',
2241
+ 'oxfmt.config.ts',
2242
+ 'oxlint.config.ts',
1868
2243
  'package.json',
2244
+ 'pnpm-workspace.yaml',
1869
2245
  'postcss.config.mjs',
2246
+ 'rstest.config.mts',
1870
2247
  "scripts/**",
1871
2248
  'shared/**',
1872
2249
  'src/**',
1873
2250
  'tailwind.config.ts',
2251
+ 'tests/**',
1874
2252
  'tsconfig.json'
1875
2253
  ],
1876
2254
  deniedPaths: requiredDeniedPaths,
@@ -1899,10 +2277,15 @@ function createBuiltinTemplateManifest(version) {
1899
2277
  postMaterializationValidation: [
1900
2278
  'ultramodern-contract-check',
1901
2279
  'dependency-install-with-lifecycle-deny',
2280
+ 'github-workflow-security-enforced',
2281
+ 'package-source-retained',
2282
+ 'pnpm-11-policy-enforced',
2283
+ 'rstest-smoke-tests',
1902
2284
  'template-manifest-retained'
1903
2285
  ],
1904
2286
  expectedCommands: [
1905
- "pnpm install --ignore-scripts",
2287
+ 'pnpm install',
2288
+ 'pnpm test',
1906
2289
  'pnpm run ultramodern:check'
1907
2290
  ]
1908
2291
  }
@@ -2008,9 +2391,19 @@ function writeTemplateManifestEvidence(targetDir, manifest) {
2008
2391
  });
2009
2392
  node_fs.writeFileSync(evidencePath, `${JSON.stringify(manifest, null, 2)}\n`);
2010
2393
  }
2011
- function showVersion() {
2394
+ function readCreatePackageJson() {
2012
2395
  const createPackageJson = node_path.resolve(src_dirname, '..', 'package.json');
2013
- const createPackage = JSON.parse(node_fs.readFileSync(createPackageJson, 'utf-8'));
2396
+ return JSON.parse(node_fs.readFileSync(createPackageJson, 'utf-8'));
2397
+ }
2398
+ function isBleedingDevCreatePackage(createPackage) {
2399
+ return '@bleedingdev/modern-js-create' === createPackage.name;
2400
+ }
2401
+ function getBleedingDevFrameworkVersion(createPackage, fallbackVersion) {
2402
+ const frameworkVersion = createPackage.ultramodern?.frameworkVersion;
2403
+ return 'string' == typeof frameworkVersion && frameworkVersion.length > 0 ? frameworkVersion : fallbackVersion;
2404
+ }
2405
+ function showVersion() {
2406
+ const createPackage = readCreatePackageJson();
2014
2407
  const version = createPackage.version || 'unknown';
2015
2408
  console.log(i18n.t(localeKeys.version.message, {
2016
2409
  version
@@ -2081,14 +2474,15 @@ function detectWorkspaceProtocolFlag() {
2081
2474
  const args = process.argv.slice(2);
2082
2475
  return args.includes('--workspace');
2083
2476
  }
2084
- function detectUltramodernWorkspaceFlag() {
2477
+ function detectUltramodernWorkspaceFlag(createPackage) {
2085
2478
  const args = process.argv.slice(2);
2086
- return args.includes(ULTRAMODERN_WORKSPACE_FLAG);
2479
+ return args.includes(ULTRAMODERN_WORKSPACE_FLAG) || isBleedingDevCreatePackage(createPackage);
2087
2480
  }
2088
- function detectUltramodernPackageSource(args, modernVersion) {
2481
+ function detectUltramodernPackageSource(args, defaultPackageVersion, createPackage) {
2482
+ const bleedingDevDefaults = isBleedingDevCreatePackage(createPackage);
2089
2483
  const strategy = getOptionValue(args, [
2090
2484
  '--ultramodern-package-source'
2091
- ]) ?? 'workspace';
2485
+ ]) ?? (bleedingDevDefaults ? 'install' : 'workspace');
2092
2486
  if ('workspace' !== strategy && 'install' !== strategy) {
2093
2487
  console.error('--ultramodern-package-source must be "workspace" or "install"');
2094
2488
  process.exit(1);
@@ -2097,18 +2491,68 @@ function detectUltramodernPackageSource(args, modernVersion) {
2097
2491
  strategy,
2098
2492
  modernPackageVersion: getOptionValue(args, [
2099
2493
  '--ultramodern-package-version'
2100
- ]) ?? modernVersion,
2494
+ ]) ?? defaultPackageVersion,
2101
2495
  registry: getOptionValue(args, [
2102
2496
  '--ultramodern-package-registry'
2103
2497
  ]),
2104
2498
  aliasScope: getOptionValue(args, [
2105
2499
  '--ultramodern-package-scope'
2106
- ]),
2500
+ ]) ?? (bleedingDevDefaults && 'install' === strategy ? 'bleedingdev' : void 0),
2107
2501
  aliasPackageNamePrefix: getOptionValue(args, [
2108
2502
  '--ultramodern-package-name-prefix'
2109
2503
  ]) ?? 'modern-js-'
2110
2504
  };
2111
2505
  }
2506
+ function src_modernAliasPackageName(packageName, packageSource) {
2507
+ if (!packageSource.aliasScope) return packageName;
2508
+ const scope = packageSource.aliasScope.replace(/^@/, '');
2509
+ const unscopedName = packageName.split('/').at(-1);
2510
+ return `@${scope}/${packageSource.aliasPackageNamePrefix ?? ''}${unscopedName}`;
2511
+ }
2512
+ function singleAppModernPackageSpecifier(packageName, packageSource, useWorkspaceProtocol) {
2513
+ if (useWorkspaceProtocol) return 'workspace:*';
2514
+ if ('install' !== packageSource.strategy || !packageSource.aliasScope) return packageSource.modernPackageVersion;
2515
+ return `npm:${src_modernAliasPackageName(packageName, packageSource)}@${packageSource.modernPackageVersion}`;
2516
+ }
2517
+ const singleAppModernPackages = [
2518
+ '@modern-js/runtime',
2519
+ '@modern-js/app-tools',
2520
+ '@modern-js/tsconfig',
2521
+ '@modern-js/plugin-i18n',
2522
+ '@modern-js/plugin-tanstack',
2523
+ '@modern-js/plugin-bff',
2524
+ '@modern-js/adapter-rstest'
2525
+ ];
2526
+ function createSingleAppPackageSourceEvidence(packageSource, useWorkspaceProtocol) {
2527
+ const strategy = useWorkspaceProtocol ? 'workspace' : 'install';
2528
+ const specifier = useWorkspaceProtocol ? 'workspace:*' : packageSource.modernPackageVersion;
2529
+ const aliases = 'install' === strategy && packageSource.aliasScope ? Object.fromEntries(singleAppModernPackages.map((packageName)=>[
2530
+ packageName,
2531
+ src_modernAliasPackageName(packageName, packageSource)
2532
+ ])) : void 0;
2533
+ return {
2534
+ schemaVersion: 1,
2535
+ preset: 'presetUltramodern',
2536
+ strategy,
2537
+ modernPackages: {
2538
+ specifier,
2539
+ packages: singleAppModernPackages,
2540
+ ...packageSource.registry ? {
2541
+ registry: packageSource.registry
2542
+ } : {},
2543
+ ...aliases ? {
2544
+ aliases
2545
+ } : {}
2546
+ }
2547
+ };
2548
+ }
2549
+ function writeSingleAppPackageSourceEvidence(targetDir, packageSource, useWorkspaceProtocol) {
2550
+ const evidencePath = node_path.join(targetDir, '.modernjs', 'ultramodern-package-source.json');
2551
+ node_fs.mkdirSync(node_path.dirname(evidencePath), {
2552
+ recursive: true
2553
+ });
2554
+ node_fs.writeFileSync(evidencePath, `${JSON.stringify(createSingleAppPackageSourceEvidence(packageSource, useWorkspaceProtocol), null, 2)}\n`);
2555
+ }
2112
2556
  function isDirectoryEmpty(dirPath) {
2113
2557
  if (!node_fs.existsSync(dirPath)) return false;
2114
2558
  try {
@@ -2194,16 +2638,16 @@ async function main() {
2194
2638
  process.exit(1);
2195
2639
  }
2196
2640
  }
2197
- const createPackageJson = node_path.resolve(src_dirname, '..', 'package.json');
2198
- const createPackage = JSON.parse(node_fs.readFileSync(createPackageJson, 'utf-8'));
2641
+ const createPackage = readCreatePackageJson();
2199
2642
  const version = createPackage.version || 'latest';
2200
- const generateWorkspace = detectUltramodernWorkspaceFlag();
2643
+ const ultramodernPackageVersion = isBleedingDevCreatePackage(createPackage) ? getBleedingDevFrameworkVersion(createPackage, version) : version;
2644
+ const generateWorkspace = detectUltramodernWorkspaceFlag(createPackage);
2201
2645
  if (generateWorkspace) {
2202
2646
  generateUltramodernWorkspace({
2203
2647
  targetDir,
2204
2648
  packageName: generatedPackageName,
2205
2649
  modernVersion: version,
2206
- packageSource: detectUltramodernPackageSource(args, version)
2650
+ packageSource: detectUltramodernPackageSource(args, ultramodernPackageVersion, createPackage)
2207
2651
  });
2208
2652
  const dim = '\x1b[2m\x1b[3m';
2209
2653
  const reset = '\x1b[0m';
@@ -2223,12 +2667,19 @@ async function main() {
2223
2667
  const bffRuntime = detectBffRuntime();
2224
2668
  const enableTailwind = detectTailwindFlag();
2225
2669
  const useWorkspaceProtocol = detectWorkspaceProtocolFlag();
2226
- const dependencyVersion = useWorkspaceProtocol ? 'workspace:*' : version;
2670
+ const packageSource = detectUltramodernPackageSource(args, ultramodernPackageVersion, createPackage);
2227
2671
  const templateManifest = createBuiltinTemplateManifest(version);
2228
2672
  validateTemplateManifest(templateManifest);
2229
2673
  copyTemplate(templateDir, targetDir, {
2230
2674
  packageName: generatedPackageName,
2231
- version: dependencyVersion,
2675
+ version: useWorkspaceProtocol ? 'workspace:*' : packageSource.modernPackageVersion,
2676
+ runtimeVersion: singleAppModernPackageSpecifier('@modern-js/runtime', packageSource, useWorkspaceProtocol),
2677
+ appToolsVersion: singleAppModernPackageSpecifier('@modern-js/app-tools', packageSource, useWorkspaceProtocol),
2678
+ adapterRstestVersion: singleAppModernPackageSpecifier('@modern-js/adapter-rstest', packageSource, useWorkspaceProtocol),
2679
+ tsconfigVersion: singleAppModernPackageSpecifier('@modern-js/tsconfig', packageSource, useWorkspaceProtocol),
2680
+ pluginTanstackVersion: singleAppModernPackageSpecifier('@modern-js/plugin-tanstack', packageSource, useWorkspaceProtocol),
2681
+ pluginBffVersion: singleAppModernPackageSpecifier('@modern-js/plugin-bff', packageSource, useWorkspaceProtocol),
2682
+ pluginI18nVersion: singleAppModernPackageSpecifier('@modern-js/plugin-i18n', packageSource, useWorkspaceProtocol),
2232
2683
  isSubproject,
2233
2684
  routerFramework,
2234
2685
  bffRuntime,
@@ -2238,21 +2689,37 @@ async function main() {
2238
2689
  const targetPackageJson = node_path.join(targetDir, 'package.json');
2239
2690
  const packageJson = JSON.parse(node_fs.readFileSync(targetPackageJson, 'utf-8'));
2240
2691
  packageJson.name = generatedPackageName;
2692
+ packageJson.modernjs = {
2693
+ ...packageJson.modernjs ?? {},
2694
+ preset: 'presetUltramodern',
2695
+ packageSource: {
2696
+ strategy: useWorkspaceProtocol ? 'workspace' : 'install',
2697
+ config: './.modernjs/ultramodern-package-source.json'
2698
+ }
2699
+ };
2241
2700
  if (isSubproject) {
2242
2701
  delete packageJson['lint-staged'];
2243
2702
  delete packageJson['simple-git-hooks'];
2244
2703
  if (packageJson.scripts) {
2245
2704
  delete packageJson.scripts.prepare;
2705
+ delete packageJson.scripts.format;
2706
+ delete packageJson.scripts['format:check'];
2246
2707
  delete packageJson.scripts.lint;
2708
+ delete packageJson.scripts['lint:fix'];
2709
+ delete packageJson.scripts['skills:install'];
2710
+ delete packageJson.scripts['skills:check'];
2247
2711
  }
2248
2712
  if (packageJson.devDependencies) {
2249
2713
  delete packageJson.devDependencies['lint-staged'];
2250
2714
  delete packageJson.devDependencies['simple-git-hooks'];
2251
- delete packageJson.devDependencies['@biomejs/biome'];
2715
+ delete packageJson.devDependencies.oxlint;
2716
+ delete packageJson.devDependencies.oxfmt;
2717
+ delete packageJson.devDependencies.ultracite;
2252
2718
  }
2253
2719
  }
2254
2720
  node_fs.writeFileSync(targetPackageJson, `${JSON.stringify(packageJson, null, 2)}\n`);
2255
2721
  writeTemplateManifestEvidence(targetDir, templateManifest);
2722
+ writeSingleAppPackageSourceEvidence(targetDir, packageSource, useWorkspaceProtocol);
2256
2723
  const dim = '\x1b[2m\x1b[3m';
2257
2724
  const reset = '\x1b[0m';
2258
2725
  console.log(`${i18n.t(localeKeys.message.success)}\n`);
@@ -2268,10 +2735,14 @@ function copyTemplate(src, dest, options) {
2268
2735
  recursive: true
2269
2736
  });
2270
2737
  const excludeInSubproject = [
2738
+ '.agents',
2739
+ '.github',
2271
2740
  '.gitignore.handlebars',
2272
- 'biome.json',
2741
+ 'AGENTS.md',
2273
2742
  '.npmrc',
2274
- '.nvmrc'
2743
+ '.nvmrc',
2744
+ 'oxfmt.config.ts',
2745
+ 'oxlint.config.ts'
2275
2746
  ];
2276
2747
  function copyRecursive(srcDir, destDir) {
2277
2748
  const entries = node_fs.readdirSync(srcDir, {
@@ -2293,6 +2764,13 @@ function copyTemplate(src, dest, options) {
2293
2764
  const rendered = src_renderTemplate(templateContent, {
2294
2765
  packageName: options.packageName,
2295
2766
  version: options.version,
2767
+ runtimeVersion: options.runtimeVersion,
2768
+ appToolsVersion: options.appToolsVersion,
2769
+ adapterRstestVersion: options.adapterRstestVersion,
2770
+ tsconfigVersion: options.tsconfigVersion,
2771
+ pluginTanstackVersion: options.pluginTanstackVersion,
2772
+ pluginBffVersion: options.pluginBffVersion,
2773
+ pluginI18nVersion: options.pluginI18nVersion,
2296
2774
  isSubproject: options.isSubproject,
2297
2775
  isTanstackRouter: 'tanstack' === options.routerFramework,
2298
2776
  enableBff: 'none' !== options.bffRuntime,
@@ -2300,7 +2778,7 @@ function copyTemplate(src, dest, options) {
2300
2778
  useHonoBff: 'hono' === options.bffRuntime,
2301
2779
  bffRuntime: options.bffRuntime,
2302
2780
  enableTailwind: options.enableTailwind,
2303
- routerImportPath: 'tanstack' === options.routerFramework ? 'tanstack-router' : 'router'
2781
+ routerRuntimeImport: 'tanstack' === options.routerFramework ? '@modern-js/plugin-tanstack/runtime' : '@modern-js/runtime/router'
2304
2782
  });
2305
2783
  if (0 === rendered.trim().length) continue;
2306
2784
  destPath = destPath.replace(/\.handlebars$/, '');