@bleedingdev/modern-js-main-doc 3.9.0-ultramodern.2 → 3.9.0-ultramodern.21
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/components/deploy-command.mdx +1 -0
- package/docs/en/components/hono.mdx +3 -3
- package/docs/en/components/init-app.mdx +1 -5
- package/docs/en/components/prerequisites.mdx +1 -1
- package/docs/en/configure/app/bff/effect.mdx +34 -36
- package/docs/en/configure/app/source/react-compiler.mdx +2 -0
- package/docs/en/guides/advanced-features/bff/data-platform.mdx +2 -2
- package/docs/en/guides/advanced-features/bff/frameworks.mdx +33 -21
- package/docs/en/guides/advanced-features/bff/function.mdx +2 -2
- package/docs/en/guides/advanced-features/bff/operators.mdx +17 -17
- package/docs/en/guides/basic-features/render/ssr-cache.mdx +14 -1
- package/docs/en/guides/get-started/ultramodern.mdx +14 -97
- package/docs/en/plugin/server-plugins/api.mdx +1 -0
- package/docs/zh/components/bff-operator-code.mdx +1 -1
- package/docs/zh/components/deploy-command.mdx +1 -0
- package/docs/zh/components/hono.mdx +3 -3
- package/docs/zh/components/prerequisites.mdx +1 -1
- package/docs/zh/configure/app/bff/effect.mdx +28 -33
- package/docs/zh/configure/app/source/react-compiler.mdx +2 -0
- package/docs/zh/guides/advanced-features/bff/data-platform.mdx +2 -2
- package/docs/zh/guides/advanced-features/bff/frameworks.mdx +31 -20
- package/docs/zh/guides/advanced-features/bff/function.mdx +2 -2
- package/docs/zh/guides/advanced-features/bff/operators.mdx +17 -17
- package/docs/zh/guides/basic-features/render/ssr-cache.mdx +14 -1
- package/docs/zh/guides/get-started/ultramodern.mdx +17 -83
- package/docs/zh/plugin/server-plugins/api.mdx +1 -0
- package/package.json +10 -10
- package/src/sandbox/csr-auth/src/routes/Auth-tsx.txt +10 -6
- package/src/sandbox/csr-auth/src/routes/page-tsx.txt +1 -0
- package/ultramodern-preset/package.json +2 -2
|
@@ -8,6 +8,7 @@ Usage: modern deploy [options]
|
|
|
8
8
|
Options:
|
|
9
9
|
-c --config <config> Specify configuration file path, either relative or absolute
|
|
10
10
|
-s --skip-build Skip the build stage
|
|
11
|
+
--deploy-target <target> Deploy target (node, vercel, netlify, ghPages, cloudflare); overrides deploy.target and MODERNJS_DEPLOY
|
|
11
12
|
-h, --help Display command help
|
|
12
13
|
```
|
|
13
14
|
|
|
@@ -21,7 +21,7 @@ For more details, refer to [useHonoContext](/apis/app/runtime/bff/use-backend-co
|
|
|
21
21
|
When getting cookies in BFF functions, you need to get the request context through `useHonoContext`, then use `c.req.header('cookie')` to get the Cookie string and parse it manually:
|
|
22
22
|
|
|
23
23
|
```ts title="api/lambda/cookies.ts"
|
|
24
|
-
import { Api, Get } from '@modern-js/plugin-bff/
|
|
24
|
+
import { Api, Get } from '@modern-js/plugin-bff/server';
|
|
25
25
|
import { useHonoContext } from '@modern-js/server-runtime';
|
|
26
26
|
|
|
27
27
|
// Helper function to parse Cookie string
|
|
@@ -64,7 +64,7 @@ The `c.req.cookie()` method does not exist in the current version. You need to u
|
|
|
64
64
|
When using Hono as the runtime framework, you can define interfaces through [Api functions](/guides/advanced-features/bff/operators.html):
|
|
65
65
|
|
|
66
66
|
```ts title="api/lambda/user.ts"
|
|
67
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
67
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
68
68
|
import { z } from 'zod';
|
|
69
69
|
|
|
70
70
|
const QuerySchema = z.object({
|
|
@@ -93,7 +93,7 @@ For more details about Api functions and operators, refer to [Creating Extensibl
|
|
|
93
93
|
Hono supports a rich middleware ecosystem, and you can use middleware in BFF functions:
|
|
94
94
|
|
|
95
95
|
```ts title="api/lambda/user.ts"
|
|
96
|
-
import { Api, Get, Middleware } from '@modern-js/plugin-bff/
|
|
96
|
+
import { Api, Get, Middleware } from '@modern-js/plugin-bff/server';
|
|
97
97
|
|
|
98
98
|
export const getUser = Api(
|
|
99
99
|
Get('/user'),
|
|
@@ -71,11 +71,7 @@ Now, the project structure is as follows:
|
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
The default workspace starts shell-only and installs the published BleedingDev
|
|
74
|
-
package aliases
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
pnpm dlx @bleedingdev/modern-js-ultramodern-create my-super-app
|
|
78
|
-
```
|
|
74
|
+
package aliases.
|
|
79
75
|
|
|
80
76
|
From a generated SuperApp workspace, add a business MicroVertical in place:
|
|
81
77
|
|
|
@@ -47,21 +47,33 @@ import EnableBFFCaution from "@site-docs-en/components/enable-bff-caution";
|
|
|
47
47
|
|
|
48
48
|
:::caution Install the Effect peers yourself
|
|
49
49
|
`effect` and `@effect/opentelemetry` are **optional exact peer dependencies** of
|
|
50
|
-
`@modern-js/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
`/effect-server`, `/effect-edge` or `/effect-client`, install the exact cohort:
|
|
50
|
+
`@modern-js/bff-effect`. Install them in the application so its API modules and
|
|
51
|
+
the framework use the same Effect instance. Before setting
|
|
52
|
+
`runtimeFramework: 'effect'` or importing `@modern-js/bff-effect/effect`,
|
|
53
|
+
`/effect-edge` or `/effect-client`, install the exact cohort:
|
|
55
54
|
|
|
56
55
|
```bash
|
|
57
|
-
pnpm add effect@4.0.0-rc.
|
|
56
|
+
pnpm add effect@4.0.0-rc.117 @effect/opentelemetry@4.0.0-rc.117
|
|
58
57
|
```
|
|
59
58
|
|
|
60
59
|
The pin is exact because UltraModern ships Effect as one lockstep cohort. Apps
|
|
61
|
-
using only `runtimeFramework: 'hono'` or
|
|
62
|
-
package.
|
|
60
|
+
using only native `runtimeFramework: 'hono'` or
|
|
61
|
+
`@modern-js/bff-effect/data-platform` need neither package.
|
|
63
62
|
:::
|
|
64
63
|
|
|
64
|
+
Use `bffPlugin` from `@modern-js/plugin-bff-build-extensions` to register the
|
|
65
|
+
Effect runtime. It composes the native BFF plugin. Install
|
|
66
|
+
`@modern-js/bff-effect` and `@modern-js/plugin-bff-extensions` from the same
|
|
67
|
+
framework cohort as application production dependencies, so the adapter remains
|
|
68
|
+
available after development dependencies are removed. The build plugin can be a
|
|
69
|
+
development dependency. See the [runtime configuration example](/guides/advanced-features/bff/frameworks).
|
|
70
|
+
|
|
71
|
+
Native `@modern-js/plugin-bff/server` exports Hono APIs. For Node Effect APIs,
|
|
72
|
+
import framework helpers such as `defineEffectBff` from
|
|
73
|
+
`@modern-js/bff-effect/effect` and namespaces from the corresponding `effect/*`
|
|
74
|
+
modules. Worker handlers and worker request context use
|
|
75
|
+
`@modern-js/bff-effect/effect-edge`.
|
|
76
|
+
|
|
65
77
|
Generated UltraModern workspaces use this runtime as the only generated HTTP API
|
|
66
78
|
path. The API contract lives at `shared/api.ts`, the server runtime lives at
|
|
67
79
|
`api/index.ts`, clients live under `src/api/*-client.ts`, and generated checks
|
|
@@ -173,7 +185,6 @@ export default defineConfig({
|
|
|
173
185
|
endpoint: '/_data/batch',
|
|
174
186
|
maxBatchSize: 16,
|
|
175
187
|
maxBatchBytes: 64 * 1024,
|
|
176
|
-
flushIntervalMs: 8,
|
|
177
188
|
maxConcurrency: 4,
|
|
178
189
|
requestTimeoutMs: 10000,
|
|
179
190
|
allowedMethods: ['GET'],
|
|
@@ -207,9 +218,9 @@ export default defineConfig({
|
|
|
207
218
|
});
|
|
208
219
|
```
|
|
209
220
|
|
|
210
|
-
`
|
|
221
|
+
`maxConcurrency` and `requestTimeoutMs` control the server batch gateway. Native `HttpApiClient` calls send individual requests; they do not automatically batch requests.
|
|
211
222
|
|
|
212
|
-
|
|
223
|
+
Import a shared `HttpApi` contract and pass it to `HttpApiClient.make` or `makeEffectHttpApiClient`. The client is fully type-inferred; `defineEffectBff` exposes server handlers and does not contain a client.
|
|
213
224
|
|
|
214
225
|
## Effect cohort
|
|
215
226
|
|
|
@@ -218,14 +229,10 @@ through `pnpm-workspace.yaml` overrides. For the current UltraModern cohort,
|
|
|
218
229
|
generated apps use:
|
|
219
230
|
|
|
220
231
|
```yaml
|
|
221
|
-
trustPolicyExclude:
|
|
222
|
-
- 'effect@4.0.0-rc.112'
|
|
223
|
-
- '@effect/opentelemetry@4.0.0-rc.112'
|
|
224
|
-
|
|
225
232
|
overrides:
|
|
226
|
-
'@effect/opentelemetry': 4.0.0-rc.
|
|
227
|
-
'@effect/vitest': 4.0.0-rc.
|
|
228
|
-
effect: 4.0.0-rc.
|
|
233
|
+
'@effect/opentelemetry': 4.0.0-rc.117
|
|
234
|
+
'@effect/vitest': 4.0.0-rc.117
|
|
235
|
+
effect: 4.0.0-rc.117
|
|
229
236
|
```
|
|
230
237
|
|
|
231
238
|
Do not add a different direct `effect` version in an app package. A mismatched
|
|
@@ -233,10 +240,7 @@ Effect prerelease can fail while building layers or HTTP middleware because runt
|
|
|
233
240
|
services come from different package instances. The strict 24-hour release-age
|
|
234
241
|
gate applies to installed packages; the current cohort has no Effect age
|
|
235
242
|
exemption, and override-only `@effect/vitest` is not an installed approval
|
|
236
|
-
target.
|
|
237
|
-
its exact `effect` and `@effect/opentelemetry` exceptions cover their
|
|
238
|
-
trusted-publisher to provenance metadata transition and are not release-age
|
|
239
|
-
approvals.
|
|
243
|
+
target.
|
|
240
244
|
|
|
241
245
|
## Contract tests
|
|
242
246
|
|
|
@@ -244,7 +248,7 @@ Strict Effect APIs should test the declared `HttpApi` contract, not a raw
|
|
|
244
248
|
request handler. Edge-compatible tests can use the framework helper:
|
|
245
249
|
|
|
246
250
|
```ts
|
|
247
|
-
import { createEffectBffTestHandler } from '@modern-js/
|
|
251
|
+
import { createEffectBffTestHandler } from '@modern-js/bff-effect/effect-edge';
|
|
248
252
|
import apiModule from '../api/index';
|
|
249
253
|
|
|
250
254
|
const testApi = await createEffectBffTestHandler({
|
|
@@ -259,12 +263,9 @@ If you manually compose an Effect web handler in a low-level proof, provide the
|
|
|
259
263
|
platform services explicitly:
|
|
260
264
|
|
|
261
265
|
```ts
|
|
262
|
-
import
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
HttpServer,
|
|
266
|
-
Layer,
|
|
267
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
266
|
+
import * as Layer from 'effect/Layer';
|
|
267
|
+
import { HttpRouter, HttpServer } from 'effect/unstable/http';
|
|
268
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
268
269
|
|
|
269
270
|
const handler = HttpRouter.toWebHandler(
|
|
270
271
|
HttpApiBuilder.layer(api).pipe(
|
|
@@ -284,13 +285,10 @@ current Effect v4 beta cohort, `HttpRouter.middleware(...)` returns a `Layer`
|
|
|
284
285
|
directly:
|
|
285
286
|
|
|
286
287
|
```ts
|
|
287
|
-
import
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
HttpRouter,
|
|
292
|
-
Layer,
|
|
293
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
288
|
+
import * as Effect from 'effect/Effect';
|
|
289
|
+
import * as Layer from 'effect/Layer';
|
|
290
|
+
import { HttpMiddleware, HttpRouter } from 'effect/unstable/http';
|
|
291
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
294
292
|
|
|
295
293
|
const corsLayer = HttpRouter.middleware(
|
|
296
294
|
Effect.succeed(
|
|
@@ -11,6 +11,8 @@ Whether to enable [React Compiler](https://react.dev/learn/react-compiler). Reac
|
|
|
11
11
|
|
|
12
12
|
Modern.js implements this capability based on the Rust-based React Compiler built into Rspack's `builtin:swc-loader` (equivalent to setting SWC's `jsc.transform.reactCompiler`), reusing Rspack's built-in SWC transform chain without introducing Babel.
|
|
13
13
|
|
|
14
|
+
The compiler only runs for browser environments (`output.target: 'web'`). Server environments (`node`, the `web-worker` SSR worker and BFF code) render once per request and gain nothing from memoization, so they are never compiled.
|
|
15
|
+
|
|
14
16
|
:::tip
|
|
15
17
|
This option is disabled by default. It must be enabled explicitly for any React version, including React 19.
|
|
16
18
|
:::
|
|
@@ -17,7 +17,7 @@ Modern.js Effect API runtime now supports a request-envelope based data platform
|
|
|
17
17
|
|
|
18
18
|
## Runtime contract helpers
|
|
19
19
|
|
|
20
|
-
Use `@modern-js/
|
|
20
|
+
Use `@modern-js/bff-effect/data-platform` helpers to build and validate contracts:
|
|
21
21
|
|
|
22
22
|
```ts
|
|
23
23
|
import {
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
validateHydrationEnvelope,
|
|
31
31
|
createInvalidationEvent,
|
|
32
32
|
shouldApplyInvalidation,
|
|
33
|
-
} from '@modern-js/
|
|
33
|
+
} from '@modern-js/bff-effect/data-platform';
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Effect runtime validation
|
|
@@ -5,10 +5,10 @@ title: Runtime Framework
|
|
|
5
5
|
|
|
6
6
|
# Runtime Framework
|
|
7
7
|
|
|
8
|
-
Modern.js
|
|
8
|
+
Modern.js and the UltraModern BFF extension provide two runtime frameworks:
|
|
9
9
|
|
|
10
|
-
- `
|
|
11
|
-
- `
|
|
10
|
+
- `hono` is the native plugin default and uses file-convention handlers from `api/lambda/**`.
|
|
11
|
+
- `effect` is the UltraModern extension default and uses [Effect HttpApi](https://effect.website/) from `api/index`.
|
|
12
12
|
|
|
13
13
|
`effect` and `hono` are strict runtime modes. There is no automatic fallback between them.
|
|
14
14
|
|
|
@@ -19,12 +19,18 @@ Generated UltraModern workspaces use strict Effect APIs: author HTTP APIs in
|
|
|
19
19
|
|
|
20
20
|
## Switch to Effect runtime
|
|
21
21
|
|
|
22
|
+
Use the fork build plugin below. It includes the native BFF plugin and registers
|
|
23
|
+
the Effect adapter. The application needs `@modern-js/bff-effect` and
|
|
24
|
+
`@modern-js/plugin-bff-extensions` as production dependencies from the same
|
|
25
|
+
framework cohort. Install the exact Effect peers described in
|
|
26
|
+
[`bff.effect`](/configure/app/bff/effect).
|
|
27
|
+
|
|
22
28
|
```ts title="modern.config.ts"
|
|
23
|
-
import { bffPlugin } from '@modern-js/plugin-bff';
|
|
24
|
-
import { defineConfig } from '@modern-js/app-tools';
|
|
29
|
+
import { bffPlugin } from '@modern-js/plugin-bff-build-extensions';
|
|
30
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
|
25
31
|
|
|
26
32
|
export default defineConfig({
|
|
27
|
-
plugins: [bffPlugin()],
|
|
33
|
+
plugins: [appTools(), bffPlugin()],
|
|
28
34
|
bff: {
|
|
29
35
|
runtimeFramework: 'effect',
|
|
30
36
|
effect: {
|
|
@@ -46,7 +52,7 @@ import {
|
|
|
46
52
|
HttpApiEndpoint,
|
|
47
53
|
HttpApiGroup,
|
|
48
54
|
Schema,
|
|
49
|
-
} from '@modern-js/
|
|
55
|
+
} from '@modern-js/bff-effect/effect-client';
|
|
50
56
|
|
|
51
57
|
export const bffApi = HttpApi.make('MyApi').add(
|
|
52
58
|
HttpApiGroup.make('hello').add(
|
|
@@ -60,14 +66,12 @@ export const bffApi = HttpApi.make('MyApi').add(
|
|
|
60
66
|
Implement your Effect API entry at `api/index.ts`:
|
|
61
67
|
|
|
62
68
|
```ts title="api/index.ts"
|
|
63
|
-
import {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
ServiceMap,
|
|
70
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
69
|
+
import { defineEffectBff } from '@modern-js/bff-effect/effect';
|
|
70
|
+
import * as Context from 'effect/Context';
|
|
71
|
+
import * as Effect from 'effect/Effect';
|
|
72
|
+
import * as Layer from 'effect/Layer';
|
|
73
|
+
import * as Schema from 'effect/Schema';
|
|
74
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
71
75
|
import { bffApi } from '../shared/api';
|
|
72
76
|
|
|
73
77
|
class GreetingUnavailableError extends Schema.TaggedError<GreetingUnavailableError>()(
|
|
@@ -77,7 +81,7 @@ class GreetingUnavailableError extends Schema.TaggedError<GreetingUnavailableErr
|
|
|
77
81
|
},
|
|
78
82
|
) {}
|
|
79
83
|
|
|
80
|
-
class GreetingService extends
|
|
84
|
+
class GreetingService extends Context.Service<GreetingService>()('GreetingService', {
|
|
81
85
|
make: Effect.succeed({
|
|
82
86
|
hello: Effect.fn('GreetingService.hello')(function* () {
|
|
83
87
|
if (Date.now() < 0) {
|
|
@@ -112,19 +116,27 @@ const layer = HttpApiBuilder.layer(bffApi).pipe(
|
|
|
112
116
|
export default defineEffectBff({ api: bffApi, layer });
|
|
113
117
|
```
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
Create a native, fully inferred client from the shared contract:
|
|
116
120
|
|
|
117
121
|
```ts title="src/routes/page.tsx"
|
|
118
|
-
import
|
|
122
|
+
import { Effect, makeEffectHttpApiClient } from '@modern-js/bff-effect/effect-client';
|
|
123
|
+
import { bffApi } from '../../shared/api';
|
|
119
124
|
|
|
120
|
-
const response = await
|
|
125
|
+
const response = await Effect.runPromise(
|
|
126
|
+
makeEffectHttpApiClient(bffApi, { baseUrl: '/api' }).pipe(
|
|
127
|
+
Effect.flatMap(client => client.hello.ping({})),
|
|
128
|
+
),
|
|
129
|
+
);
|
|
121
130
|
```
|
|
122
131
|
|
|
123
|
-
|
|
132
|
+
Requests, responses, and declared errors are inferred from `bffApi`. No client generation or server-entry import is needed.
|
|
124
133
|
|
|
125
134
|
For UltraModern, Effect `HttpApi` plus Effect BFF is the single blessed authored HTTP path. Use `HttpApi` endpoints with `query`, `params`, `payload`, `success`, and declared errors such as `HttpApiSchema.status(...)`; implement them with `HttpApiBuilder.group(...).handle(...)` and `HttpApiBuilder.layer(...).pipe(Layer.provide(...))`, then default-export the entry as `defineEffectBff({ api, layer })`. See `packages/server/bff-effect/tests/effect-edge-runtime.test.ts` for the live runtime shape.
|
|
126
135
|
|
|
127
|
-
Hono
|
|
136
|
+
Native Hono applications import operators from `@modern-js/plugin-bff/server`.
|
|
137
|
+
UltraModern-generated applications keep their strict Effect API model. Worker
|
|
138
|
+
handlers use `@modern-js/bff-effect/effect-edge`, including its worker request
|
|
139
|
+
context exports; Node handlers use the Effect entry shown above.
|
|
128
140
|
|
|
129
141
|
import Hono from '@site-docs-en/components/hono';
|
|
130
142
|
|
|
@@ -191,7 +191,7 @@ Parameters following the dynamic path are an object called `RequestOption`, whic
|
|
|
191
191
|
In a standard function without dynamic routes, `RequestOption` can be obtained from the first parameter, for example:
|
|
192
192
|
|
|
193
193
|
```ts title="api/lambda/hello.ts"
|
|
194
|
-
import type { RequestOption } from '@modern-js/plugin-bff/
|
|
194
|
+
import type { RequestOption } from '@modern-js/plugin-bff/server';
|
|
195
195
|
|
|
196
196
|
export async function post({
|
|
197
197
|
query,
|
|
@@ -204,7 +204,7 @@ export async function post({
|
|
|
204
204
|
Custom types can also be used here:
|
|
205
205
|
|
|
206
206
|
```ts title="api/lambda/hello.ts"
|
|
207
|
-
import type { RequestOption } from '@modern-js/plugin-bff/
|
|
207
|
+
import type { RequestOption } from '@modern-js/plugin-bff/server';
|
|
208
208
|
|
|
209
209
|
type IQuery = {
|
|
210
210
|
// some types
|
|
@@ -36,7 +36,7 @@ import BFFOperatorCode from '@site-docs/components/bff-operator-code';
|
|
|
36
36
|
<BFFOperatorCode>
|
|
37
37
|
|
|
38
38
|
```typescript title="api/lambda/user.ts"
|
|
39
|
-
import { Api, Post, Query, Data } from '@modern-js/plugin-bff/
|
|
39
|
+
import { Api, Post, Query, Data } from '@modern-js/plugin-bff/server';
|
|
40
40
|
import { z } from 'zod';
|
|
41
41
|
|
|
42
42
|
const UserSchema = z.object({
|
|
@@ -89,7 +89,7 @@ As shown in the example below, you can specify the route and HTTP Method through
|
|
|
89
89
|
<BFFOperatorCode>
|
|
90
90
|
|
|
91
91
|
```typescript title="api/lambda/user.ts"
|
|
92
|
-
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/
|
|
92
|
+
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/server';
|
|
93
93
|
|
|
94
94
|
// Specify the interface route, Modern.js sets `bff.prefix` to `/api` by default,
|
|
95
95
|
// so the interface route is `/api/user`, and the HTTP Method is GET.
|
|
@@ -107,7 +107,7 @@ When the route is not specified, the interface route is defined according to the
|
|
|
107
107
|
<BFFOperatorCode>
|
|
108
108
|
|
|
109
109
|
```typescript title="api/lambda/user.ts"
|
|
110
|
-
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/
|
|
110
|
+
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/server';
|
|
111
111
|
|
|
112
112
|
// No interface route specified, according to file convention and function name, the interface is api/user, HTTP Method is get.
|
|
113
113
|
export const get = Api(Query(UserSchema), async ({ query }) => query);
|
|
@@ -144,7 +144,7 @@ Using the `Query` function, you can define the type of query. After using the `Q
|
|
|
144
144
|
|
|
145
145
|
```typescript title="api/lambda/user.ts"
|
|
146
146
|
// Server-side code
|
|
147
|
-
import { Api, Query } from '@modern-js/plugin-bff/
|
|
147
|
+
import { Api, Query } from '@modern-js/plugin-bff/server';
|
|
148
148
|
import { z } from 'zod';
|
|
149
149
|
|
|
150
150
|
const UserSchema = z.object({
|
|
@@ -176,7 +176,7 @@ URL query parameters are strings by default. If you need numeric types, you need
|
|
|
176
176
|
<BFFOperatorCode>
|
|
177
177
|
|
|
178
178
|
```typescript title="api/lambda/user.ts"
|
|
179
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
179
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
180
180
|
import { z } from 'zod';
|
|
181
181
|
|
|
182
182
|
const QuerySchema = z.object({
|
|
@@ -216,7 +216,7 @@ If you use the Data function, you must follow the HTTP protocol. When the HTTP M
|
|
|
216
216
|
<BFFOperatorCode>
|
|
217
217
|
|
|
218
218
|
```typescript title="api/lambda/user.ts"
|
|
219
|
-
import { Api, Data } from '@modern-js/plugin-bff/
|
|
219
|
+
import { Api, Data } from '@modern-js/plugin-bff/server';
|
|
220
220
|
import { z } from 'zod';
|
|
221
221
|
|
|
222
222
|
const DataSchema = z.object({
|
|
@@ -249,7 +249,7 @@ Route parameters can implement dynamic routes and get parameters from the path.
|
|
|
249
249
|
<BFFOperatorCode>
|
|
250
250
|
|
|
251
251
|
```typescript
|
|
252
|
-
import { Api, Get, Params } from '@modern-js/plugin-bff/
|
|
252
|
+
import { Api, Get, Params } from '@modern-js/plugin-bff/server';
|
|
253
253
|
import { z } from 'zod';
|
|
254
254
|
|
|
255
255
|
const UserSchema = z.object({
|
|
@@ -274,7 +274,7 @@ You can define the request headers required by the interface through the `Header
|
|
|
274
274
|
<BFFOperatorCode>
|
|
275
275
|
|
|
276
276
|
```typescript
|
|
277
|
-
import { Api, Headers } from '@modern-js/plugin-bff/
|
|
277
|
+
import { Api, Headers } from '@modern-js/plugin-bff/server';
|
|
278
278
|
import { z } from 'zod';
|
|
279
279
|
|
|
280
280
|
const headerSchema = z.object({
|
|
@@ -336,7 +336,7 @@ The `Middleware` operator can be configured multiple times, and the execution or
|
|
|
336
336
|
<BFFOperatorCode>
|
|
337
337
|
|
|
338
338
|
```typescript
|
|
339
|
-
import { Api, Query, Middleware } from '@modern-js/plugin-bff/
|
|
339
|
+
import { Api, Query, Middleware } from '@modern-js/plugin-bff/server';
|
|
340
340
|
import { z } from 'zod';
|
|
341
341
|
|
|
342
342
|
const UserSchema = z.object({
|
|
@@ -376,7 +376,7 @@ The `Pipe` operator can be configured multiple times. The execution order of fun
|
|
|
376
376
|
<BFFOperatorCode>
|
|
377
377
|
|
|
378
378
|
```typescript
|
|
379
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
379
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
380
380
|
import { z } from 'zod';
|
|
381
381
|
|
|
382
382
|
const UserSchema = z.object({
|
|
@@ -408,7 +408,7 @@ Also,
|
|
|
408
408
|
<BFFOperatorCode>
|
|
409
409
|
|
|
410
410
|
```typescript
|
|
411
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
411
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
412
412
|
import { z } from 'zod';
|
|
413
413
|
|
|
414
414
|
const UserSchema = z.object({
|
|
@@ -443,7 +443,7 @@ If you need to do more custom operations on the response, you can pass a functio
|
|
|
443
443
|
<BFFOperatorCode>
|
|
444
444
|
|
|
445
445
|
```typescript
|
|
446
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
446
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
447
447
|
import { z } from 'zod';
|
|
448
448
|
|
|
449
449
|
const UserSchema = z.object({
|
|
@@ -487,7 +487,7 @@ You can specify the status code returned by the interface through the `HttpCode(
|
|
|
487
487
|
<BFFOperatorCode>
|
|
488
488
|
|
|
489
489
|
```typescript
|
|
490
|
-
import { Api, Query, Data, HttpCode } from '@modern-js/plugin-bff/
|
|
490
|
+
import { Api, Query, Data, HttpCode } from '@modern-js/plugin-bff/server';
|
|
491
491
|
import { z } from 'zod';
|
|
492
492
|
|
|
493
493
|
const UserSchema = z.object({
|
|
@@ -523,7 +523,7 @@ Supports setting response headers through the `SetHeaders(headers: Record<string
|
|
|
523
523
|
<BFFOperatorCode>
|
|
524
524
|
|
|
525
525
|
```typescript
|
|
526
|
-
import { Api, Get, SetHeaders } from '@modern-js/plugin-bff/
|
|
526
|
+
import { Api, Get, SetHeaders } from '@modern-js/plugin-bff/server';
|
|
527
527
|
|
|
528
528
|
export default Api(
|
|
529
529
|
Get('/hello'),
|
|
@@ -543,7 +543,7 @@ Supports redirecting the interface through `Redirect(url: string)`:
|
|
|
543
543
|
<BFFOperatorCode>
|
|
544
544
|
|
|
545
545
|
```typescript
|
|
546
|
-
import { Api, Get, Redirect } from '@modern-js/plugin-bff/
|
|
546
|
+
import { Api, Get, Redirect } from '@modern-js/plugin-bff/server';
|
|
547
547
|
|
|
548
548
|
export default Api(
|
|
549
549
|
Get('/hello'),
|
|
@@ -561,7 +561,7 @@ As mentioned above, through operators, you can get `query`, `data`, `params`, et
|
|
|
561
561
|
<BFFOperatorCode>
|
|
562
562
|
|
|
563
563
|
```typescript title="api/lambda/user.ts"
|
|
564
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
564
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
565
565
|
import { useHonoContext } from '@modern-js/server-runtime';
|
|
566
566
|
import { z } from 'zod';
|
|
567
567
|
|
|
@@ -610,7 +610,7 @@ In frontend development, some server interfaces (such as some configuration inte
|
|
|
610
610
|
<BFFOperatorCode>
|
|
611
611
|
|
|
612
612
|
```typescript
|
|
613
|
-
import { Api, SetHeaders } from '@modern-js/plugin-bff/
|
|
613
|
+
import { Api, SetHeaders } from '@modern-js/plugin-bff/server';
|
|
614
614
|
|
|
615
615
|
export const get = Api(
|
|
616
616
|
// Cache will only take effect when using integrated calls or fetch for requests
|
|
@@ -35,7 +35,7 @@ export interface CacheControl {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
Here, `customKey` is the custom cache key. By default,
|
|
38
|
+
Here, `customKey` is the custom cache key. By default, the cache key is derived from the request's origin, normalized pathname (trailing slash removed), and query string. When `customKey` is set, it fully replaces the default key: the `customKey` callback receives the normalized pathname (not the `CacheOptionProvider`'s `req`) and is responsible for the whole partition (e.g. by tenant, host, or query) — it must not embed raw cookies or other credentials into the returned key.
|
|
39
39
|
|
|
40
40
|
**Function Type**
|
|
41
41
|
|
|
@@ -106,6 +106,19 @@ export const cacheOption: CacheOption = {
|
|
|
106
106
|
|
|
107
107
|
The above `/home` and `/about` are patterns, meaning `/home/abc` will also match. You can use regex in these patterns, such as `/home/.+`.
|
|
108
108
|
|
|
109
|
+
### Cache Policy
|
|
110
|
+
|
|
111
|
+
The following policy is enforced automatically and cannot be overridden by the returned `CacheControl`:
|
|
112
|
+
|
|
113
|
+
- Only `GET` requests are cached.
|
|
114
|
+
- A request carrying a `Cookie` or `Authorization` header skips the cache unless `customKey` is set, since a custom key is treated as an explicit partitioning contract.
|
|
115
|
+
- A request with `Cache-Control: private`, `no-cache`, or `no-store` skips the cache.
|
|
116
|
+
- A response is only stored when it is `200`, has no `private`/`no-cache`/`no-store` in `Cache-Control`, has no `Set-Cookie`, and has no nonempty `Vary` header; otherwise any existing cache entry for that key is deleted instead of being written.
|
|
117
|
+
- If a `stale` revalidation produces a response that is no longer cacheable (for example, it became per-user), that already-served stale response is unaffected, but the cache entry is evicted so subsequent requests no longer hit it.
|
|
118
|
+
- A `CacheOptionProvider` returning `false` still disables caching entirely for that request, independent of the policy above.
|
|
119
|
+
|
|
120
|
+
Cache keys are namespaced (`__ssr__cache:v2:...`). Older un-namespaced entries — including ones already stored in a custom `Container` — are never read back; they simply age out under the container's own eviction/TTL. There is no global cache flush.
|
|
121
|
+
|
|
109
122
|
### Cache Container
|
|
110
123
|
|
|
111
124
|
By default, the server uses memory for caching. Typically, services are deployed in a Serverless container, creating a new process for each access, making it impossible to use the previous cache.
|