@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.
- package/docs/en/community/blog/v3-release-note.mdx +1 -1
- package/docs/en/configure/app/bff/effect.mdx +116 -3
- package/docs/en/configure/app/bff/runtime-framework.mdx +4 -2
- package/docs/en/configure/app/experiments/source-build.mdx +1 -1
- package/docs/en/configure/app/html/template-parameters.mdx +1 -1
- package/docs/en/configure/app/output/convert-to-rem.mdx +1 -1
- package/docs/en/configure/app/security/check-syntax.mdx +1 -1
- package/docs/en/configure/app/tools/html-plugin.mdx +1 -1
- package/docs/en/configure/app/tools/ts-checker.mdx +20 -1
- package/docs/en/guides/advanced-features/bff/data-platform.mdx +4 -4
- package/docs/en/guides/advanced-features/bff/frameworks.mdx +25 -14
- package/docs/en/guides/advanced-features/bff/function.mdx +4 -0
- package/docs/en/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
- package/docs/en/guides/basic-features/debug/using-storybook.mdx +1 -1
- package/docs/en/guides/basic-features/static-assets/json-files.mdx +2 -2
- package/docs/en/guides/get-started/_meta.json +2 -1
- package/docs/en/guides/get-started/ai-coding-agents.mdx +48 -0
- package/docs/en/guides/get-started/ultramodern.mdx +113 -23
- package/docs/en/guides/upgrade/config.mdx +1 -1
- package/docs/en/plugin/introduction.mdx +9 -9
- package/docs/zh/community/blog/v3-release-note.mdx +1 -1
- package/docs/zh/configure/app/bff/effect.mdx +109 -3
- package/docs/zh/configure/app/bff/runtime-framework.mdx +4 -2
- package/docs/zh/configure/app/experiments/source-build.mdx +1 -1
- package/docs/zh/configure/app/html/template-parameters.mdx +1 -1
- package/docs/zh/configure/app/output/convert-to-rem.mdx +1 -1
- package/docs/zh/configure/app/security/check-syntax.mdx +1 -1
- package/docs/zh/configure/app/tools/html-plugin.mdx +1 -1
- package/docs/zh/configure/app/tools/ts-checker.mdx +19 -0
- package/docs/zh/guides/advanced-features/bff/data-platform.mdx +2 -2
- package/docs/zh/guides/advanced-features/bff/frameworks.mdx +24 -14
- package/docs/zh/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
- package/docs/zh/guides/basic-features/debug/using-storybook.mdx +1 -1
- package/docs/zh/guides/basic-features/static-assets/json-files.mdx +2 -2
- package/docs/zh/guides/get-started/_meta.json +2 -1
- package/docs/zh/guides/get-started/ai-coding-agents.mdx +48 -0
- package/docs/zh/guides/get-started/ultramodern.mdx +92 -19
- package/docs/zh/guides/upgrade/config.mdx +1 -1
- package/docs/zh/plugin/introduction.mdx +9 -9
- 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
|
|
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
|
-
-
|
|
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
|
|
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.
|
|
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 |
|
|
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
|
|
50
|
-
|
|
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
|
|
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
|
|
57
|
-
2.
|
|
58
|
-
3. Treat
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
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.
|
|
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,
|
|
186
|
-
|
|
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
|
-
`
|
|
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
|
|
243
|
-
|
|
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,
|
|
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/
|
|
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/
|
|
135
|
-
| [Source Build Plugin](https://github.com/
|
|
136
|
-
| [Check Syntax Plugin](https://github.com/
|
|
137
|
-
| [CSS Minimizer Plugin](https://github.com/
|
|
138
|
-
| [Rem Plugin](https://github.com/
|
|
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/
|
|
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/
|
|
147
|
-
- [YAML Plugin](https://github.com/
|
|
148
|
-
- [TOML Plugin](https://github.com/
|
|
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/
|
|
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>/
|
|
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/
|
|
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
|
-
生成的 `
|
|
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/
|
|
24
|
+
- 设置为 `'effect'` 时,仅从 `api/index` 运行 BFF(Effect HttpApi 运行时)。
|
|
25
25
|
- 设置为 `'hono'` 时,仅从 `api/lambda/**` 的文件约定处理函数运行 BFF。
|
|
26
26
|
|
|
27
27
|
两种运行时之间没有隐式回退,应用需要显式选择其一。
|
|
28
|
-
生成的 UltraModern
|
|
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/
|
|
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/
|
|
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
|
|
|
@@ -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/
|
|
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/
|
|
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/
|
|
62
|
+
使用生成的 Effect 客户端(`@api/index`)时,Modern.js 会在同源请求中自动附加序列化的 envelope 请求头(`x-modernjs-data-envelope`)。
|
|
63
63
|
|
|
64
|
-
生成客户端由 loader 物化。请在浏览器或会被客户端打包的代码中通过 `@api/
|
|
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/
|
|
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/
|
|
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
|
|
54
|
+
export const bffApi = HttpApi.make('MyApi').add(
|
|
45
55
|
HttpApiGroup.make('hello').add(
|
|
46
|
-
HttpApiEndpoint.get('ping', '/
|
|
56
|
+
HttpApiEndpoint.get('ping', '/ping', {
|
|
47
57
|
success: Schema.String,
|
|
48
58
|
}),
|
|
49
59
|
),
|
|
50
60
|
);
|
|
51
61
|
```
|
|
52
62
|
|
|
53
|
-
然后在 `api/
|
|
63
|
+
然后在 `api/index.ts` 中实现 Effect BFF 入口:
|
|
54
64
|
|
|
55
|
-
```ts title="api/
|
|
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 {
|
|
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(
|
|
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(
|
|
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:
|
|
115
|
+
export default defineEffectBff({ api: bffApi, layer });
|
|
106
116
|
```
|
|
107
117
|
|
|
108
|
-
在浏览器代码中通过 `@api/
|
|
118
|
+
在浏览器代码中通过 `@api/index` 调用接口:
|
|
109
119
|
|
|
110
120
|
```ts title="src/routes/page.tsx"
|
|
111
|
-
import
|
|
121
|
+
import api from '@api/index';
|
|
112
122
|
|
|
113
|
-
const response = await
|
|
123
|
+
const response = await api.client.hello.ping({});
|
|
114
124
|
```
|
|
115
125
|
|
|
116
|
-
`
|
|
126
|
+
`api.client.*` 由 BFF loader 针对 `@api/index` 导入物化生成。不要直接导入 `api/index` 并期望在服务端代码、脚本或测试中运行 `client`;直接导入入口时拿到的是服务端运行时定义,其中的 `client` 只是类型占位。
|
|
117
127
|
|
|
118
128
|
import Hono from '@site-docs/components/hono';
|
|
119
129
|
|