@bleedingdev/modern-js-main-doc 3.4.0-ultramodern.9 → 3.5.0-ultramodern.1

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 (40) hide show
  1. package/docs/en/community/blog/v3-release-note.mdx +1 -1
  2. package/docs/en/configure/app/bff/effect.mdx +116 -3
  3. package/docs/en/configure/app/bff/runtime-framework.mdx +4 -2
  4. package/docs/en/configure/app/experiments/source-build.mdx +1 -1
  5. package/docs/en/configure/app/html/template-parameters.mdx +1 -1
  6. package/docs/en/configure/app/output/convert-to-rem.mdx +1 -1
  7. package/docs/en/configure/app/security/check-syntax.mdx +1 -1
  8. package/docs/en/configure/app/tools/html-plugin.mdx +1 -1
  9. package/docs/en/configure/app/tools/ts-checker.mdx +20 -1
  10. package/docs/en/guides/advanced-features/bff/data-platform.mdx +4 -4
  11. package/docs/en/guides/advanced-features/bff/frameworks.mdx +25 -14
  12. package/docs/en/guides/advanced-features/bff/function.mdx +4 -0
  13. package/docs/en/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
  14. package/docs/en/guides/basic-features/debug/using-storybook.mdx +1 -1
  15. package/docs/en/guides/basic-features/static-assets/json-files.mdx +2 -2
  16. package/docs/en/guides/get-started/_meta.json +2 -1
  17. package/docs/en/guides/get-started/ai-coding-agents.mdx +48 -0
  18. package/docs/en/guides/get-started/ultramodern.mdx +113 -23
  19. package/docs/en/guides/upgrade/config.mdx +1 -1
  20. package/docs/en/plugin/introduction.mdx +9 -9
  21. package/docs/zh/community/blog/v3-release-note.mdx +1 -1
  22. package/docs/zh/configure/app/bff/effect.mdx +109 -3
  23. package/docs/zh/configure/app/bff/runtime-framework.mdx +4 -2
  24. package/docs/zh/configure/app/experiments/source-build.mdx +1 -1
  25. package/docs/zh/configure/app/html/template-parameters.mdx +1 -1
  26. package/docs/zh/configure/app/output/convert-to-rem.mdx +1 -1
  27. package/docs/zh/configure/app/security/check-syntax.mdx +1 -1
  28. package/docs/zh/configure/app/tools/html-plugin.mdx +1 -1
  29. package/docs/zh/configure/app/tools/ts-checker.mdx +19 -0
  30. package/docs/zh/guides/advanced-features/bff/data-platform.mdx +2 -2
  31. package/docs/zh/guides/advanced-features/bff/frameworks.mdx +24 -14
  32. package/docs/zh/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
  33. package/docs/zh/guides/basic-features/debug/using-storybook.mdx +1 -1
  34. package/docs/zh/guides/basic-features/static-assets/json-files.mdx +2 -2
  35. package/docs/zh/guides/get-started/_meta.json +2 -1
  36. package/docs/zh/guides/get-started/ai-coding-agents.mdx +48 -0
  37. package/docs/zh/guides/get-started/ultramodern.mdx +92 -19
  38. package/docs/zh/guides/upgrade/config.mdx +1 -1
  39. package/docs/zh/plugin/introduction.mdx +9 -9
  40. package/package.json +2 -2
@@ -7,14 +7,16 @@ sidebar_position: 2
7
7
 
8
8
  This page compares **UltraModern.js 3.0** with the Modern.js 3.x line this fork tracks. The baseline is the current merged Modern.js `release-v3.x` baseline, not a frozen patch-version snapshot.
9
9
 
10
- UltraModern.js 3.0 is our SuperApp framework forked from Modern.js. It keeps compatibility with the Modern.js plugin/runtime mental model where that helps adoption, but it is positioned as a separate framework for Effect-first BFFs, TanStack Router, SSR, Module Federation, and independently deployable Micro Verticals.
10
+ UltraModern.js 3.0 is our SuperApp framework forked from Modern.js. It keeps the Modern.js plugin/runtime mental model where that helps adoption, but it is positioned as a separate framework for Effect HttpApi-first HTTP APIs, TanStack Router, SSR, Module Federation, and independently deployable Micro Verticals.
11
11
 
12
12
  ## Design Principles
13
13
 
14
14
  - Keep deltas explicit and auditable.
15
- - Preserve compatibility with useful Modern.js concepts without presenting UltraModern.js as a preset-only variant.
15
+ - Keep upstream Modern.js merge compatibility explicit: generic Modern.js runtime
16
+ code can remain where it belongs, while UltraModern-generated surfaces stay
17
+ strict.
16
18
  - Add platform-level contracts only where they improve cross-team reliability.
17
- - Keep opt-out switches and explicit compatibility lanes available.
19
+ - Keep escape hatches explicit and outside the generated HTTP API path.
18
20
 
19
21
  ## Compatibility Contract
20
22
 
@@ -24,7 +26,9 @@ UltraModern.js 3.0 keeps:
24
26
  - Existing project structure and command flow.
25
27
  - Progressive adoption path (apps can stay mostly unchanged).
26
28
 
27
- UltraModern.js additions are designed as the default product surface for new SuperApps. Compatibility lanes remain available when they reduce migration risk, but the framework direction is Effect + TanStack + SSR + Micro Verticals.
29
+ UltraModern.js additions are designed as the default product surface for new SuperApps. The framework direction is Effect + TanStack + SSR + Micro Verticals, and generated HTTP API work uses that direction by default instead of preserving parallel raw-handler layouts.
30
+ Existing Modern.js apps can migrate gradually; once an API surface is generated
31
+ or migrated as UltraModern HTTP API, it must use the strict Effect HttpApi path.
28
32
 
29
33
  ## Intentional Differences (v3 line)
30
34
 
@@ -33,7 +37,7 @@ UltraModern.js additions are designed as the default product surface for new Sup
33
37
  | Build diagnostics | RsDoctor is generally opt-in | Adds a first-class `performance.rsdoctor` config surface (opt-in; the earlier default-on behavior and diagnostics contract artifact were reverted) |
34
38
  | Output and static serving | Precompression behavior is app-defined | Enables `output.precompress` by default and serves `.br` / `.gz` variants via `Accept-Encoding` negotiation |
35
39
  | BFF runtime and contracts | Standard BFF runtime/client generation | Adds `requestId`-aware producer isolation, fail-fast initialization checks, and operation/trace correlation headers |
36
- | BFF runtime choices | Hono runtime path only in Modern.js 3.0 baseline (no built-in Effect runtime path) | Sets Effect as default runtime, enforces strict runtime split (`effect` -> `api/effect`, `hono` -> `api/lambda`), and adds Effect-Schema-first contracts plus MF failure-injection reliability coverage |
40
+ | BFF runtime choices | Standard request-handler oriented BFF paths | Uses Effect `HttpApi` as the only generated HTTP API path (`api/index.ts`, `shared/api.ts`, `src/api/*`) and rejects raw handlers, manual parsing, manual `Response` construction, and Hono server imports in generated workspaces |
37
41
  | Telemetry standardization | Observability wiring is often app-specific | Adds framework-level telemetry pipeline with OTLP/VictoriaMetrics exporters, redaction, batching, and backpressure controls |
38
42
  | App-level MF SSR handshake | No dedicated super-app app-level stability contract focus | Adds `server.ssr.moduleFederationAppSSR` plus integration-tested env/config handshake |
39
43
  | MF vertical loading reliability | Retry/fallback patterns are often implemented per app | Adds deterministic timeout/network/contract-error reliability matrix and distributed OTEL continuity tests |
@@ -46,16 +50,19 @@ UltraModern.js additions are designed as the default product surface for new Sup
46
50
 
47
51
  - We do not hide the fork behind legacy Modern.js branding.
48
52
  - We do not optimize for generic Modern.js defaults when they conflict with SuperApp reliability.
49
- - We keep both runtime modes (`effect`, `hono`) as explicit choices and avoid implicit fallback between them.
50
- - We avoid incompatible API changes unless there is a hard reliability requirement.
53
+ - We do not delete generic Modern.js Hono/file-convention runtime support just
54
+ to enforce UltraModern policy; the enforcement lives in UltraModern
55
+ generator, config, checks, and generated workspaces.
56
+ - Generated UltraModern API work uses the Effect runtime only; raw Hono/function handlers are not part of the generated API architecture.
57
+ - We make incompatible scaffold changes when they remove architecture drift.
51
58
 
52
59
  ## Migration Guide
53
60
 
54
- For teams already on Modern.js 3.0 or an older BleedingDev UltraModern scaffold, the adoption path remains compatibility-aware: keep the pieces that reduce risk, move toward MV-first / TanStack-first / Effect-first defaults, and keep fallback lanes explicit while you adopt UltraModern.js 3.0 as a separate framework.
61
+ For teams already on Modern.js 3.0 or an older BleedingDev UltraModern scaffold, the adoption path is to move API work onto the strict Effect HttpApi surface instead of preserving older raw handler layouts.
55
62
 
56
- 1. Keep existing React Router apps running as-is. TanStack Router is the preferred path for new scaffolds and incremental route adoption, but the React Router lane remains supported while teams move on their own schedule.
57
- 2. Prefer `bff.runtimeFramework: 'effect'` for new BFF work, with the entry implemented at `api/effect/index.ts`. If your app already uses Hono handlers under `api/lambda/**`, keep `bff.runtimeFramework: 'hono'` until you are ready to move them; Hono remains a supported compatibility lane.
58
- 3. Treat the baseline contracts as progressive defaults, not a forced cutover. `MODERN_BASELINE_ENABLE_MF_SSR`, `MODERN_BASELINE_ENABLE_BFF_REQUEST_ID`, and `MODERN_BASELINE_ENABLE_TELEMETRY_EXPORTERS` already let each app opt out while it converges on the preferred stack.
63
+ 1. Keep existing Modern.js apps running as-is while they are outside the generated UltraModern surface. TanStack Router is the preferred path for new scaffolds and incremental route adoption, but route migration can happen on the team's schedule.
64
+ 2. Use `bff.runtimeFramework: 'effect'` with `bff.effect.strictEffectApproach: true` for API work. Entries live at `api/index.ts`, contracts live at `shared/api.ts`, clients live under `src/api/*`, and request/response/error shapes come from Effect `Schema` plus `HttpApi`.
65
+ 3. Treat raw handlers, `api/lambda/**`, manual `Response` construction, and manual request parsing as migration defects in generated or migrated UltraModern workspaces.
59
66
  4. The public preset now ships with explicit release and certification gates. Generated workspaces include `.github/workflows/ultramodern-workspace-gates.yml`, so `pnpm check` and `pnpm build` stay part of the local adoption contract from day one while CI runs the primitive gates as parallel matrix jobs.
60
67
 
61
68
  For an older generated workspace, migrate by treating the published cohort as
@@ -71,14 +78,90 @@ mise exec -- pnpm check
71
78
  mise exec -- pnpm build
72
79
  ```
73
80
 
81
+ Strict generated API migration requires `3.5.0-ultramodern.1` or newer.
82
+ `3.4.0-ultramodern.20` and earlier cohorts do not include this full direct
83
+ `api/index.ts` generator, generated `.mts` checks, strict Oxlint boundary rule
84
+ set, Effect cohort overrides, and strict Effect migration command. Agents that
85
+ cannot install that BleedingDev cohort yet should use the local Modern.js
86
+ workspace for migration validation; otherwise pin `3.5.0-ultramodern.1` or
87
+ newer with `--ultramodern-package-version`.
88
+
89
+ Before hand-editing package aliases or generated metadata, run the framework
90
+ migration command from the target workspace:
91
+
92
+ ```bash
93
+ pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.1 ultramodern \
94
+ migrate-strict-effect --version 3.5.0-ultramodern.1
95
+ pnpm api:check
96
+ pnpm contract:check
97
+ ```
98
+
99
+ The command updates `.modernjs/ultramodern.json`, root
100
+ `modernjs.packageSource`, generated Modern package aliases, direct topology API
101
+ metadata, and the pnpm lockfile. Remaining failures are source migration work:
102
+ move code to `shared/api.ts`, `api/index.ts`, and `src/api/*-client.ts`, then
103
+ delete `api/effect`, `api/lambda`, `shared/effect`, and `src/effect`.
104
+
105
+ Generated strict Effect workspaces pin the compatible Effect cohort with pnpm
106
+ overrides: `effect@4.0.0-beta.89` and `@effect/vitest@4.0.0-beta.89`. Do not
107
+ add app-local direct Effect versions that disagree with those overrides.
108
+
109
+ Gradual migration means old, unmigrated Modern.js apps can keep their existing
110
+ runtime until they are converted. Once a surface is generated or migrated as
111
+ UltraModern HTTP API, it uses Effect HttpApi only; do not keep Hono, lambda
112
+ handlers, or raw request handlers inside that UltraModern API surface.
113
+
114
+ When migrating a generated workspace that already has nested Effect API files, make the
115
+ move explicit and do not keep compatibility aliases:
116
+
117
+ 1. Move each vertical server entry from `verticals/<id>/api/effect/index.ts` to
118
+ `verticals/<id>/api/index.ts`.
119
+ 2. Move each shared API contract from `verticals/<id>/shared/effect/api.ts` to
120
+ `verticals/<id>/shared/api.ts`.
121
+ 3. Move generated clients from `verticals/<id>/src/effect/*-client.ts` to
122
+ `verticals/<id>/src/api/*-client.ts`.
123
+ 4. Move shell API aggregates from `apps/shell-super-app/src/effect/*` to
124
+ `apps/shell-super-app/src/api/*`.
125
+ 5. Update imports and package exports to use `./api`, `./api/client`, and
126
+ `@<workspace>/<vertical>/api/client`; remove `./effect/client`,
127
+ `./shared/effect/api`, and shared Effect API packages.
128
+ 6. Update every vertical `modern.config.ts` to use
129
+ `bff.effect.entry: './api/index'` and
130
+ `bff.effect.strictEffectApproach: true`.
131
+ 7. Update topology so API metadata lives directly under `api` with
132
+ `api.bff.strictEffectApproach: true`; do not keep `api.effect`.
133
+ 8. Run `pnpm api:check`,
134
+ `scripts/validate-ultramodern-workspace.mts`, `pnpm check`, and
135
+ `pnpm build`.
136
+
137
+ If a migration fails, fix the owning generated contract, topology, package
138
+ exports, or API module. Do not add app-level aliases, raw request handlers,
139
+ manual `Response` construction, local type casts, or package shims to make the
140
+ old layout pass.
141
+
142
+ Effect RPC, WebSockets, and other transports should be added as explicit
143
+ transport surfaces when needed. They do not make raw request handlers valid
144
+ inside generated HTTP API modules.
145
+
146
+ Strict API tests should exercise the `HttpApi` contract. Use
147
+ `createEffectBffTestHandler` from `@modern-js/plugin-bff/effect-edge` for
148
+ edge-compatible proof tests; if you manually compose a web handler, provide
149
+ `HttpServer.layerServices` beside your API group layer before calling
150
+ `HttpRouter.toWebHandler`.
151
+
152
+ For dynamic origin CORS predicates inside strict Effect HTTP APIs, prefer
153
+ `HttpRouter.middleware(Effect.succeed(HttpMiddleware.cors(...)))`.
154
+ `HttpRouter.middleware(...)` returns a `Layer` directly in the pinned Effect
155
+ cohort; do not read a `.layer` property from it.
156
+
74
157
  Use one package-source strategy per repo. The published BleedingDev create
75
158
  package defaults to `--ultramodern-package-source=install` and records the
76
- exact cohort in `.modernjs/ultramodern-package-source.json`. Keep `--workspace`
77
- only for local monorepo testing against unreleased packages. Release proof and
78
- CI should pin the exact cohort with `--ultramodern-package-version` when a
79
- repo must prove a specific published framework version.
159
+ exact cohort in `.modernjs/ultramodern.json`. Keep `--workspace` only for local
160
+ monorepo testing against unreleased packages. Release proof and CI should pin
161
+ the exact cohort with `--ultramodern-package-version` when a repo must prove a
162
+ specific published framework version.
80
163
 
81
- Older repos with Effect BFF entries and `verbatimModuleSyntax` should update to
164
+ Older repos with nested Effect entries and `verbatimModuleSyntax` should update to
82
165
  the latest BleedingDev cohort instead of adding app-level `"type": "module"`
83
166
  metadata, Module Federation shims, or custom server wrappers. The framework BFF
84
167
  compiler normalizes CommonJS server output while generated app packages keep
@@ -92,11 +175,18 @@ repos by hand-editing generated worker output; upgrade the framework cohort and
92
175
  rerun the generated validation instead.
93
176
 
94
177
  After installing the new cohort, run the generated
95
- `scripts/validate-ultramodern-workspace.mjs` contract check before accepting
178
+ `scripts/validate-ultramodern-workspace.mts` contract check before accepting
96
179
  manual edits. Fix topology, ownership, package-source, local overlay, generated
97
180
  contract, Tailwind prefix, or Module Federation conflicts in the owning files
98
181
  instead of patching generated output by hand.
99
182
 
183
+ Cloudflare D1 bindings are first-class on `deploy.worker.d1Databases`; use that
184
+ config instead of app-local postprocessing when a generated app owns D1
185
+ migrations. Cloudflare public output excludes server-only `api` and `shared`
186
+ directories by default, and generated Modern/Rspack caches are isolated per app
187
+ and build target so local `build` and `cloudflare:build` runs do not share the
188
+ same Rspack cache directory.
189
+
100
190
  ## Human Workflow
101
191
 
102
192
  The public BleedingDev create package has one supported generated product. The
@@ -182,10 +272,10 @@ addUltramodernVertical({
182
272
  ```
183
273
 
184
274
  The public result includes the workspace root, package source, created apps,
185
- created paths, rewritten paths, assigned ports, Module Federation names, Effect
186
- API prefixes, generated contract path, and warnings. MicroVertical dry-run
275
+ created paths, rewritten paths, assigned ports, Module Federation names, API
276
+ prefixes, generated contract path, and warnings. MicroVertical dry-run
187
277
  returns the same shape plus `dryRun`, `selectedPort`, `moduleFederationRemote`,
188
- `effectApiPrefix`, `jsonMutations`, `shellDependencyChanges`, and
278
+ `apiPrefix`, `jsonMutations`, `shellDependencyChanges`, and
189
279
  `generatedContractChanges`; it prints JSON from the CLI and writes no files.
190
280
 
191
281
  CodeSmith consumers can use the adapter subpath:
@@ -239,8 +329,8 @@ non-indexable routes emit no JSON-LD by default. Public route owners can add
239
329
  `jsonLd` beside localized paths and use the generated
240
330
  `src/routes/ultramodern-jsonld.ts` helpers for common schema.org shapes.
241
331
 
242
- The generated contract writes `.modernjs/ultramodern-generated-contract.json`
243
- with a `cssFederation` section:
332
+ The generated contract writes `.modernjs/ultramodern.json` with a
333
+ `cssFederation` section:
244
334
 
245
335
  - `packages/shared-design-tokens` owns the shared token layer and exports `./tokens.css`.
246
336
  - Shell CSS owns only shell base and overlay layers under `[data-app-id="shell-super-app"]`.
@@ -248,7 +338,7 @@ with a `cssFederation` section:
248
338
  - Tailwind CSS v4 is local to each generated app through `@tailwindcss/postcss`; shared base styles must not be duplicated by verticals.
249
339
  - SSR first paint requires shared token CSS and app-owned CSS to be emitted by Modern/Rspack assets. Vertical CSS is loaded through manifest ownership, not copied into shell source.
250
340
 
251
- Version switching must select UI, Effect API, CSS, i18n JSON, and MF manifest evidence from the same vertical build marker. A shell render that only changes the UI marker is not enough.
341
+ Version switching must select UI, API, CSS, i18n JSON, and MF manifest evidence from the same vertical build marker. A shell render that only changes the UI marker is not enough.
252
342
 
253
343
  ### Validation And Deploy
254
344
 
@@ -314,7 +314,7 @@ export default {
314
314
 
315
315
  ### tools.pug
316
316
 
317
- **Change**: This configuration has been deprecated, use Rsbuild's [Pug plugin](https://github.com/rspack-contrib/rsbuild-plugin-pug) to enable support.
317
+ **Change**: This configuration has been deprecated, use Rsbuild's [Pug plugin](https://github.com/rstackjs/rsbuild-plugin-pug) to enable support.
318
318
 
319
319
  **Migration Example**:
320
320
 
@@ -131,21 +131,21 @@ The following are official Rsbuild plugins that are already built into Modern.js
131
131
  | [React Plugin](https://v2.rsbuild.rs/plugins/list/plugin-react) | Provides support for React | - |
132
132
  | [SVGR Plugin](https://v2.rsbuild.rs/plugins/list/plugin-svgr) | Supports converting SVG images into React components | [output.disableSvgr](/configure/app/output/disable-svgr)<br />[output.svgDefaultExport](/configure/app/output/svg-default-export) |
133
133
  | [Assets Retry Plugin](https://github.com/rstackjs/rsbuild-plugin-assets-retry) | Automatically retries requests when static asset loading fails | [output.assetsRetry](/configure/app/output/assets-retry.html) |
134
- | [Type Check Plugin](https://github.com/rspack-contrib/rsbuild-plugin-type-check) | Runs TypeScript type checking in a separate process | [output.disableTsChecker](/configure/app/output/disable-ts-checker.html)<br />[tools.tsChecker](/configure/app/tools/ts-checker.html) |
135
- | [Source Build Plugin](https://github.com/rspack-contrib/rsbuild-plugin-source-build) | For monorepo scenarios, supports referencing source code from other subdirectories and completing builds and hot updates | [experiments.sourceBuild](/configure/app/experiments/source-build.html) |
136
- | [Check Syntax Plugin](https://github.com/rspack-contrib/rsbuild-plugin-check-syntax) | Analyzes the syntax compatibility of the build artifacts to determine if there are any advanced syntax features that cause compatibility issues | [security.checkSyntax](/configure/app/security/check-syntax.html) |
137
- | [CSS Minimizer Plugin](https://github.com/rspack-contrib/rsbuild-plugin-css-minimizer) | Used to customize the CSS compression tool, switch to [cssnano](https://cssnano.co/) or other tools for CSS compression | [tools.minifyCss](/configure/app/tools/minify-css.html) |
138
- | [Rem Plugin](https://github.com/rspack-contrib/rsbuild-plugin-rem) | Implements rem adaptive layout for mobile pages | [output.convertToRem](/configure/app/output/convert-to-rem.html) |
134
+ | [Type Check Plugin](https://github.com/rstackjs/rsbuild-plugin-type-check) | Runs TypeScript type checking in a separate process | [output.disableTsChecker](/configure/app/output/disable-ts-checker.html)<br />[tools.tsChecker](/configure/app/tools/ts-checker.html) |
135
+ | [Source Build Plugin](https://github.com/rstackjs/rsbuild-plugin-source-build) | For monorepo scenarios, supports referencing source code from other subdirectories and completing builds and hot updates | [experiments.sourceBuild](/configure/app/experiments/source-build.html) |
136
+ | [Check Syntax Plugin](https://github.com/rstackjs/rsbuild-plugin-check-syntax) | Analyzes the syntax compatibility of the build artifacts to determine if there are any advanced syntax features that cause compatibility issues | [security.checkSyntax](/configure/app/security/check-syntax.html) |
137
+ | [CSS Minimizer Plugin](https://github.com/rstackjs/rsbuild-plugin-css-minimizer) | Used to customize the CSS compression tool, switch to [cssnano](https://cssnano.co/) or other tools for CSS compression | [tools.minifyCss](/configure/app/tools/minify-css.html) |
138
+ | [Rem Plugin](https://github.com/rstackjs/rsbuild-plugin-rem) | Implements rem adaptive layout for mobile pages | [output.convertToRem](/configure/app/output/convert-to-rem.html) |
139
139
 
140
140
  #### Plugins Not Built-in
141
141
 
142
142
  The following are official Rsbuild plugins that are not built into Modern.js:
143
143
 
144
- - [Image Compress Plugin](https://github.com/rspack-contrib/rsbuild-plugin-image-compress): Compresses image resources used in the project.
144
+ - [Image Compress Plugin](https://github.com/rstackjs/rsbuild-plugin-image-compress): Compresses image resources used in the project.
145
145
  - [Stylus Plugin](https://v2.rsbuild.rs/plugins/list/plugin-stylus): Uses Stylus as the CSS preprocessor.
146
- - [UMD Plugin](https://github.com/rspack-contrib/rsbuild-plugin-umd): Used to build UMD format artifacts.
147
- - [YAML Plugin](https://github.com/rspack-contrib/rsbuild-plugin-yaml): Used to reference YAML files and convert them to JavaScript objects.
148
- - [TOML Plugin](https://github.com/rspack-contrib/rsbuild-plugin-toml): Used to reference TOML files and convert them to JavaScript objects.
146
+ - [UMD Plugin](https://github.com/rstackjs/rsbuild-plugin-umd): Used to build UMD format artifacts.
147
+ - [YAML Plugin](https://github.com/rstackjs/rsbuild-plugin-yaml): Used to reference YAML files and convert them to JavaScript objects.
148
+ - [TOML Plugin](https://github.com/rstackjs/rsbuild-plugin-toml): Used to reference TOML files and convert them to JavaScript objects.
149
149
 
150
150
  import OtherPlugins from '@site-docs-en/components/other-plugins.mdx';
151
151
 
@@ -591,7 +591,7 @@ Modern.js 3.0 新项目默认使用 React 19,最低支持 React 18。
591
591
 
592
592
  #### Storybook Rsbuild
593
593
 
594
- 在 Modern.js 3.0 中,我们基于 [Storybook Rsbuild](https://github.com/rspack-contrib/storybook-rsbuild) 实现了使用 Storybook 构建 Modern.js 应用。
594
+ 在 Modern.js 3.0 中,我们基于 [Storybook Rsbuild](https://github.com/rstackjs/storybook-rsbuild) 实现了使用 Storybook 构建 Modern.js 应用。
595
595
 
596
596
  通过 Storybook Addon,我们将 Modern.js 配置转换合并为 Rsbuild 配置,并通过 Storybook Rsbuild 驱动构建,让 Storybook 调试与开发命令保持配置对齐。
597
597
 
@@ -9,6 +9,7 @@ title: effect
9
9
  ```ts
10
10
  type BffEffectUserConfig = {
11
11
  entry?: string;
12
+ strictEffectApproach?: true;
12
13
  openapi?: boolean | { path?: string };
13
14
  dataPlatform?: {
14
15
  enabled?: boolean;
@@ -44,6 +45,12 @@ import EnableBFFCaution from "@site-docs/components/enable-bff-caution";
44
45
 
45
46
  仅当 `bff.runtimeFramework` 设置为 `'effect'` 时,`bff.effect` 才会生效。
46
47
 
48
+ 生成的 UltraModern workspace 只把这个运行时作为生成 HTTP API 路径。API 契约固定在
49
+ `shared/api.ts`,服务端运行时固定在 `api/index.ts`,客户端固定在
50
+ `src/api/*-client.ts`。生成检查会拒绝 `api/effect`、`api/lambda`、
51
+ `shared/effect`、`src/effect`、Hono server import、原始 request handler、手写
52
+ request parsing,以及 API 模块里的手写 `Response`。
53
+
47
54
  对于 Effect v4,TypeScript 需要使用支持 `exports` 映射的模块解析方式。
48
55
 
49
56
  ```json title="tsconfig.json"
@@ -58,7 +65,7 @@ import EnableBFFCaution from "@site-docs/components/enable-bff-caution";
58
65
  ## bff.effect.entry
59
66
 
60
67
  - **类型:** `string`
61
- - **默认值:** `<apiDirectory>/effect/index`
68
+ - **默认值:** `<apiDirectory>/index`
62
69
 
63
70
  用于指定 Effect HttpApi 运行时入口模块。
64
71
 
@@ -67,12 +74,22 @@ export default defineConfig({
67
74
  bff: {
68
75
  runtimeFramework: 'effect',
69
76
  effect: {
70
- entry: './api/effect/index',
77
+ entry: './api/index',
71
78
  },
72
79
  },
73
80
  });
74
81
  ```
75
82
 
83
+ ## bff.effect.strictEffectApproach
84
+
85
+ - **类型:** `true`
86
+ - **默认值:** `true`
87
+
88
+ Effect BFF 模块必须导出严格 Effect API surface(`defineEffectBff(...)` 或
89
+ `{ api, layer }`),原始 request handler 会被拒绝。生成的 UltraModern 应用会显式
90
+ 写入这个标记,并通过源码检查拒绝生成 API 模块中的 Hono server import、手写
91
+ request parsing 和手写 `Response`。
92
+
76
93
  ## bff.effect.openapi
77
94
 
78
95
  - **类型:** `boolean | { path?: string }`
@@ -173,4 +190,93 @@ export default defineConfig({
173
190
 
174
191
  `batch.flushIntervalMs` 用于控制生成的 Effect 客户端微批处理窗口;`maxConcurrency` 与 `requestTimeoutMs` 由服务端批处理网关用于内部请求分发。
175
192
 
176
- 生成的 `effectBff.client.*` API 只存在于 loader 物化后的 `@api/effect/*` 导入中。直接导入服务端入口(`api/effect/index`)时拿到的是 Effect BFF 定义;其中的 `client` 属性只是占位,并会在访问具体操作时报错。
193
+ 生成的 `api.client.*` API 只存在于 loader 物化后的 `@api/index` 导入中。直接导入服务端入口(`api/index`)时拿到的是 Effect BFF 定义;其中的 `client` 属性只是占位,并会在访问具体操作时报错。
194
+
195
+ ## Effect 版本组
196
+
197
+ UltraModern 生成的 workspace 会通过 `pnpm-workspace.yaml` overrides 锁定与框架兼容的
198
+ Effect 版本组。`3.5.0-ultramodern.1` 使用:
199
+
200
+ ```yaml
201
+ overrides:
202
+ '@effect/vitest': 4.0.0-beta.89
203
+ effect: 4.0.0-beta.89
204
+ ```
205
+
206
+ 不要在应用包里添加不同版本的直接 `effect` 依赖。Effect beta 不一致时,Layer 或 HTTP
207
+ middleware 构建可能因为运行时 service 来自不同包实例而失败。
208
+
209
+ ## 契约测试
210
+
211
+ 严格 Effect API 测试应当测试声明的 `HttpApi` 契约,而不是原始 request handler。
212
+ Edge 兼容测试可以使用框架 helper:
213
+
214
+ ```ts
215
+ import { createEffectBffTestHandler } from '@modern-js/plugin-bff/effect-edge';
216
+ import apiModule from '../api/index';
217
+
218
+ const testApi = await createEffectBffTestHandler({
219
+ module: apiModule,
220
+ prefix: '/api',
221
+ });
222
+
223
+ const response = await testApi.handler(new Request('http://localhost/api/ping'));
224
+ ```
225
+
226
+ 如果低层 proof 必须手动组合 web handler,需要在调用 `HttpRouter.toWebHandler` 前提供
227
+ `HttpServer.layerServices`:
228
+
229
+ ```ts
230
+ import {
231
+ HttpApiBuilder,
232
+ HttpRouter,
233
+ HttpServer,
234
+ Layer,
235
+ } from '@modern-js/plugin-bff/effect-server';
236
+
237
+ const handler = HttpRouter.toWebHandler(
238
+ HttpApiBuilder.layer(api).pipe(
239
+ Layer.provide(apiGroupLayer),
240
+ Layer.provide(HttpServer.layerServices),
241
+ ),
242
+ ).handler;
243
+ ```
244
+
245
+ 优先使用生成 helper,除非测试必须检查底层 Effect router 组合。
246
+
247
+ ## 动态 CORS
248
+
249
+ 需要动态 origin predicate 时,使用 Effect HTTP middleware 作为 Layer。在当前锁定的
250
+ Effect v4 beta 版本组中,`HttpRouter.middleware(...)` 直接返回 `Layer`:
251
+
252
+ ```ts
253
+ import {
254
+ Effect,
255
+ HttpApiBuilder,
256
+ HttpMiddleware,
257
+ HttpRouter,
258
+ Layer,
259
+ } from '@modern-js/plugin-bff/effect-server';
260
+
261
+ const corsLayer = HttpRouter.middleware(
262
+ Effect.succeed(
263
+ HttpMiddleware.cors({
264
+ allowedOrigins: origin =>
265
+ origin.endsWith('.example.com') ? origin : undefined,
266
+ }),
267
+ ),
268
+ );
269
+
270
+ const layer = HttpApiBuilder.layer(api).pipe(
271
+ Layer.provide(apiGroupLayer),
272
+ Layer.provide(corsLayer),
273
+ );
274
+ ```
275
+
276
+ 不要从 `HttpRouter.middleware(...)` 读取 `.layer` 属性。
277
+
278
+ ## 其他传输
279
+
280
+ `strictEffectApproach` 约束生成的 HTTP API 模块。Effect RPC、WebSocket 和其他传输在
281
+ 建模为显式传输 surface、并使用类型化 Effect 程序时仍然有效。它们不让生成的
282
+ UltraModern API 模块中的原始 HTTP request handler 变得有效。
@@ -21,8 +21,10 @@ export default defineConfig({
21
21
  });
22
22
  ```
23
23
 
24
- - 设置为 `'effect'` 时,仅从 `api/effect/index` 运行 BFF(Effect HttpApi 运行时)。
24
+ - 设置为 `'effect'` 时,仅从 `api/index` 运行 BFF(Effect HttpApi 运行时)。
25
25
  - 设置为 `'hono'` 时,仅从 `api/lambda/**` 的文件约定处理函数运行 BFF。
26
26
 
27
27
  两种运行时之间没有隐式回退,应用需要显式选择其一。
28
- 生成的 UltraModern 应用默认使用 Effect 分支;仅在需要兼容运行时时设置 `runtimeFramework: 'hono'`。
28
+ 生成的 UltraModern 应用默认使用严格 Effect API,并设置
29
+ `bff.effect.strictEffectApproach: true`;`hono` 与 `api/lambda/**` 不是生成
30
+ UltraModern HTTP API 的有效路径。
@@ -21,7 +21,7 @@ export default {
21
21
 
22
22
  ### 选项
23
23
 
24
- `experiments.sourceBuild` 底层基于 [@rsbuild/plugin-source-build](https://github.com/rspack-contrib/rsbuild-plugin-source-build?tab=readme-ov-file#options) 实现,你可以传入插件选项,比如:
24
+ `experiments.sourceBuild` 底层基于 [@rsbuild/plugin-source-build](https://github.com/rstackjs/rsbuild-plugin-source-build?tab=readme-ov-file#options) 实现,你可以传入插件选项,比如:
25
25
 
26
26
  ```ts
27
27
  export default {
@@ -30,7 +30,7 @@ type DefaultParameters = {
30
30
  };
31
31
  ```
32
32
 
33
- 定义 HTML 模板中的参数,对应 [html-rspack-plugin](https://github.com/rspack-contrib/html-rspack-plugin) 的 `templateParameters` 配置项。
33
+ 定义 HTML 模板中的参数,对应 [html-rspack-plugin](https://github.com/rstackjs/html-rspack-plugin) 的 `templateParameters` 配置项。
34
34
 
35
35
  import RsbuildConfig from '@site-docs/components/rsbuild-config-tooltip';
36
36
 
@@ -80,5 +80,5 @@ export default {
80
80
  };
81
81
  ```
82
82
 
83
- 详细用法可参考 [rsbuild-plugin-rem](https://github.com/rspack-contrib/rsbuild-plugin-rem)。
83
+ 详细用法可参考 [rsbuild-plugin-rem](https://github.com/rstackjs/rsbuild-plugin-rem)。
84
84
 
@@ -70,4 +70,4 @@ error [Syntax Checker] Find some syntax errors after production build:
70
70
 
71
71
  ### 选项
72
72
 
73
- `security.checkSyntax` 底层基于 `@rsbuild/plugin-check-syntax` 实现,具体选项可参考 [@rsbuild/plugin-check-syntax](https://github.com/rspack-contrib/rsbuild-plugin-check-syntax)。
73
+ `security.checkSyntax` 底层基于 `@rsbuild/plugin-check-syntax` 实现,具体选项可参考 [@rsbuild/plugin-check-syntax](https://github.com/rstackjs/rsbuild-plugin-check-syntax)。
@@ -38,7 +38,7 @@ const defaultOptions = {
38
38
  SSR 应用请勿启用 `minify.removeComments` 配置项,否则会导致 SSR 渲染失败。
39
39
  :::
40
40
 
41
- 通过 `tools.htmlPlugin` 可以修改 [html-rspack-plugin](https://github.com/rspack-contrib/html-rspack-plugin) 的配置项。
41
+ 通过 `tools.htmlPlugin` 可以修改 [html-rspack-plugin](https://github.com/rstackjs/html-rspack-plugin) 的配置项。
42
42
 
43
43
  import RsbuildConfig from '@site-docs/components/rsbuild-config-tooltip';
44
44
 
@@ -43,6 +43,8 @@ const defaultOptions = {
43
43
 
44
44
  ## 示例
45
45
 
46
+ ### Object 类型
47
+
46
48
  当 `tsChecker` 的值为 Object 类型时,会与默认配置进行深层合并。
47
49
 
48
50
  ```ts
@@ -57,6 +59,23 @@ export default {
57
59
  };
58
60
  ```
59
61
 
62
+ ### Function 类型
63
+
64
+ 当 `tsChecker` 的值为函数时,默认配置会作为第一个参数传入。你可以直接修改配置对象,也可以返回一个对象作为最终配置。
65
+
66
+ ```ts
67
+ export default {
68
+ tools: {
69
+ tsChecker(options) {
70
+ options.async = false;
71
+ return options;
72
+ },
73
+ },
74
+ };
75
+ ```
76
+
77
+ > 更多详情请参考 [@rsbuild/plugin-type-check](https://github.com/rstackjs/rsbuild-plugin-type-check)。
78
+
60
79
  ## TypeScript Go 默认开启
61
80
 
62
81
  类型检查默认使用 [TypeScript Go](https://github.com/microsoft/typescript-go)(`tsgo`)。该能力由 [`@rsbuild/plugin-type-check`](https://github.com/rstackjs/rsbuild-plugin-type-check) 底层集成的 [`ts-checker-rspack-plugin`](https://github.com/rstackjs/ts-checker-rspack-plugin) 提供,可以将类型检查耗时减少约 5-10 倍。
@@ -59,9 +59,9 @@ Envelope 校验默认开启,但只有设置 `requireEnvelope` 时才强制要
59
59
 
60
60
  ## Effect 客户端自动行为
61
61
 
62
- 使用生成的 Effect 客户端(`@api/effect/index`)时,Modern.js 会在同源请求中自动附加序列化的 envelope 请求头(`x-modernjs-data-envelope`)。
62
+ 使用生成的 Effect 客户端(`@api/index`)时,Modern.js 会在同源请求中自动附加序列化的 envelope 请求头(`x-modernjs-data-envelope`)。
63
63
 
64
- 生成客户端由 loader 物化。请在浏览器或会被客户端打包的代码中通过 `@api/effect/*` 导入;直接导入服务端入口(`api/effect/index`)时拿到的是 Effect BFF 定义,其中只包含占位的 `client`。
64
+ 生成客户端由 loader 物化。请在浏览器或会被客户端打包的代码中通过 `@api/index` 导入;直接导入服务端入口(`api/index`)时拿到的是 Effect BFF 定义,其中只包含占位的 `client`。
65
65
 
66
66
  Envelope 默认包含:
67
67
 
@@ -7,11 +7,19 @@ title: 运行时框架
7
7
 
8
8
  Modern.js 目前支持两种 BFF 运行时框架:
9
9
 
10
- - `effect`(默认):使用 `api/effect/index` 的 [Effect HttpApi](https://effect.website/) 运行时。
10
+ - `effect`(默认):使用 `api/index` 的 [Effect HttpApi](https://effect.website/) 运行时。
11
11
  - `hono`:使用 `api/lambda/**` 的文件约定 BFF 处理函数。
12
12
 
13
13
  `effect` 与 `hono` 为严格模式,两者之间不会自动回退。
14
14
 
15
+ ::::info
16
+ 本页记录通用 Modern.js 运行时能力。生成的 UltraModern workspace 始终使用
17
+ `effect` 运行时,并设置 `bff.effect.strictEffectApproach: true`。新增或修改生成的
18
+ UltraModern HTTP API 时,先改 `shared/api.ts`,再改 `api/index.ts`;不要在这些
19
+ workspace 中加入 Hono/file-convention handler、原始 request parsing 或手写
20
+ `Response`。
21
+ ::::
22
+
15
23
  ## 切换到 Effect 运行时
16
24
 
17
25
  ```ts title="modern.config.ts"
@@ -23,6 +31,8 @@ export default defineConfig({
23
31
  bff: {
24
32
  runtimeFramework: 'effect',
25
33
  effect: {
34
+ entry: './api/index',
35
+ strictEffectApproach: true,
26
36
  openapi: {
27
37
  path: '/openapi.json',
28
38
  },
@@ -33,7 +43,7 @@ export default defineConfig({
33
43
 
34
44
  先在共享目录中定义 Effect HttpApi 契约(前后端共享类型):
35
45
 
36
- ```ts title="shared/effect/api.ts"
46
+ ```ts title="shared/api.ts"
37
47
  import {
38
48
  HttpApi,
39
49
  HttpApiEndpoint,
@@ -41,18 +51,18 @@ import {
41
51
  Schema,
42
52
  } from '@modern-js/plugin-bff/effect-client';
43
53
 
44
- export const bffEffectApi = HttpApi.make('MyApi').add(
54
+ export const bffApi = HttpApi.make('MyApi').add(
45
55
  HttpApiGroup.make('hello').add(
46
- HttpApiEndpoint.get('ping', '/effect/ping', {
56
+ HttpApiEndpoint.get('ping', '/ping', {
47
57
  success: Schema.String,
48
58
  }),
49
59
  ),
50
60
  );
51
61
  ```
52
62
 
53
- 然后在 `api/effect/index.ts` 中实现 Effect BFF 入口:
63
+ 然后在 `api/index.ts` 中实现 Effect BFF 入口:
54
64
 
55
- ```ts title="api/effect/index.ts"
65
+ ```ts title="api/index.ts"
56
66
  import {
57
67
  Schema,
58
68
  Effect,
@@ -61,7 +71,7 @@ import {
61
71
  Layer,
62
72
  ServiceMap,
63
73
  } from '@modern-js/plugin-bff/effect-server';
64
- import { bffEffectApi } from '../../shared/effect/api';
74
+ import { bffApi } from '../shared/api';
65
75
 
66
76
  class GreetingUnavailableError extends Schema.TaggedError<GreetingUnavailableError>()(
67
77
  'GreetingUnavailableError',
@@ -87,7 +97,7 @@ class GreetingService extends ServiceMap.Service<GreetingService>()('GreetingSer
87
97
  static readonly layer = Layer.effect(this, this.make);
88
98
  }
89
99
 
90
- const group = HttpApiBuilder.group(bffEffectApi, 'hello', handlers =>
100
+ const group = HttpApiBuilder.group(bffApi, 'hello', handlers =>
91
101
  handlers.handle('ping', () =>
92
102
  GreetingService.use(service => service.hello()).pipe(
93
103
  Effect.catchTag('GreetingUnavailableError', error =>
@@ -97,23 +107,23 @@ const group = HttpApiBuilder.group(bffEffectApi, 'hello', handlers =>
97
107
  ),
98
108
  );
99
109
 
100
- const layer = HttpApiBuilder.layer(bffEffectApi).pipe(
110
+ const layer = HttpApiBuilder.layer(bffApi).pipe(
101
111
  Layer.provide(group),
102
112
  Layer.provide(GreetingService.layer),
103
113
  );
104
114
 
105
- export default defineEffectBff({ api: bffEffectApi, layer });
115
+ export default defineEffectBff({ api: bffApi, layer });
106
116
  ```
107
117
 
108
- 在浏览器代码中通过 `@api/effect/index` 调用接口:
118
+ 在浏览器代码中通过 `@api/index` 调用接口:
109
119
 
110
120
  ```ts title="src/routes/page.tsx"
111
- import effectBff from '@api/effect/index';
121
+ import api from '@api/index';
112
122
 
113
- const response = await effectBff.client.hello.ping({});
123
+ const response = await api.client.hello.ping({});
114
124
  ```
115
125
 
116
- `effectBff.client.*` 由 BFF loader 针对 `@api/effect/*` 导入物化生成。不要直接导入 `api/effect/index` 并期望在服务端代码、脚本或测试中运行 `client`;直接导入入口时拿到的是服务端运行时定义,其中的 `client` 只是类型占位。
126
+ `api.client.*` 由 BFF loader 针对 `@api/index` 导入物化生成。不要直接导入 `api/index` 并期望在服务端代码、脚本或测试中运行 `client`;直接导入入口时拿到的是服务端运行时定义,其中的 `client` 只是类型占位。
117
127
 
118
128
  import Hono from '@site-docs/components/hono';
119
129