Skip to content

Commit 3147393

Browse files
committed
feat: server config doc
1 parent 929da3c commit 3147393

File tree

8 files changed

+770
-4
lines changed

8 files changed

+770
-4
lines changed

packages/document/main-doc/docs/en/configure/app/usage.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Modern.js does not support configuring the same configuration item in both `pack
1313

1414
**Runtime configuration** can be configured in the `src/modern.runtime.(ts|js|mjs)` file.
1515

16-
**Server Runtime configuration** can be configured in the `modern.server-runtime.config.(ts|js|mjs)` file in the root path.
16+
**Server Runtime configuration** can be configured in the `server/modern.server.(ts|js|mjs)` file.
1717

1818
## Compile Configuration
1919

packages/document/main-doc/docs/en/guides/advanced-features/_meta.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@
2323
"label": "server-monitor",
2424
"collapsed": true
2525
},
26+
"custom-server",
2627
"web-server"
2728
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
---
2+
sidebar_position: 16
3+
---
4+
5+
# Custom Server
6+
7+
Modern.js encapsulates most server-side capabilities required by projects, typically eliminating the need for server-side development. However, in certain scenarios such as user authentication, request preprocessing, or adding page skeletons, custom server-side logic may still be necessary.
8+
9+
## Custom Server Capabilities
10+
11+
Create the `server/modern.server.ts` file in the project directory, where you can configure **middleware**, **rendering middleware**, and **server plugins** to extend the Server.
12+
13+
The execution order of middleware is: Middleware => PluginMiddleware => RenderMiddleware => PluginRenderMiddleware.
14+
15+
### Basic Configuration
16+
17+
```ts title="server/modern.server.ts"
18+
import { defineServerConfig } from '@modern-js/server-runtime';
19+
20+
export default defineServerConfig({
21+
middlewares: [],
22+
renderMiddlewares: [],
23+
plugins: [],
24+
});
25+
```
26+
27+
28+
### Type Definition
29+
30+
`defineServerConfig` type definition is as follows:
31+
32+
```ts
33+
import type { MiddlewareHandler } from 'hono';
34+
35+
type MiddlewareOrder = 'pre' | 'post' | 'default';
36+
type MiddlewareObj = {
37+
name: string;
38+
path?: string;
39+
method?: 'options' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all';
40+
handler: MiddlewareHandler | MiddlewareHandler[];
41+
before?: Array<MiddlewareObj['name']>;
42+
order?: MiddlewareOrder;
43+
};
44+
type ServerConfig = {
45+
middlewares?: MiddlewareObj[];
46+
renderMiddlewares?: MiddlewareObj[];
47+
plugins?: (ServerPlugin | ServerPluginLegacy)[];
48+
}
49+
```
50+
51+
52+
### Middleware
53+
54+
Middleware supports executing custom logic before and after the **request handling** and **page routing** processes in Modern.js services.
55+
56+
:::note
57+
In the BFF scenario, BFF routing will only go through Middleware when the runtime framework is Hono.
58+
:::
59+
60+
#### Using Posture
61+
62+
```ts title="server/modern.server.ts"
63+
import { defineServerConfig, type MiddlewareHandler } from '@modern-js/server-runtime';
64+
import { getMonitors } from '@modern-js/runtime';
65+
66+
export const handler: MiddlewareHandler = async (c, next) => {
67+
const monitors = getMonitors();
68+
const start = Date.now();
69+
70+
await next();
71+
72+
const end = Date.now();
73+
// Report Duration
74+
monitors.timing('request_timing', end - start);
75+
};
76+
77+
export default defineServerConfig({
78+
middlewares: [
79+
{
80+
name: 'request-timing',
81+
handler,
82+
},
83+
],
84+
});
85+
```
86+
87+
:::warning
88+
You must execute the `next` function to proceed with the subsequent Middleware.
89+
:::
90+
91+
92+
### RenderMiddleware
93+
94+
Modern.js supports adding rendering middleware to the Server, allowing custom logic to be executed before and after handling page routes.
95+
96+
#### Using Posture
97+
98+
```ts title="server/modern.server.ts"
99+
import { defineServerConfig, type MiddlewareHandler } from '@modern-js/server-runtime';
100+
101+
// Inject render performance metrics
102+
const renderTiming: MiddlewareHandler = async (c, next) => {
103+
const start = Date.now();
104+
105+
await next();
106+
107+
const end = Date.now();
108+
c.res.headers.set('server-timing', `render; dur=${end - start}`);
109+
};
110+
111+
// Modify the Response Body
112+
const modifyResBody: MiddlewareHandler = async (c, next) => {
113+
await next();
114+
115+
const { res } = c;
116+
const text = await res.text();
117+
const newText = text.replace('<body>', '<body> <h3>bytedance</h3>');
118+
119+
c.res = c.body(newText, {
120+
status: res.status,
121+
headers: res.headers,
122+
});
123+
};
124+
125+
export default defineServerConfig({
126+
renderMiddlewares: [
127+
{
128+
name: 'render-timing',
129+
handler: renderTiming,
130+
},
131+
{
132+
name: 'modify-res-body',
133+
handler: modifyResBody,
134+
},
135+
],
136+
});
137+
```
138+
139+
140+
### Plugin
141+
142+
Modern.js supports adding the aforementioned middleware and rendering middleware for the Server in custom plugins.
143+
144+
#### Using Posture
145+
146+
147+
```ts title="server/plugins/server.ts"
148+
import type { ServerPluginLegacy } from '@modern-js/server-runtime';
149+
150+
export default (): ServerPluginLegacy => ({
151+
name: 'serverPlugin',
152+
setup(api) {
153+
return {
154+
prepare(serverConfig) {
155+
const { middlewares, renderMiddlewares } = api.useAppContext();
156+
157+
// Inject server-side data for page dataLoader consumption
158+
middlewares?.push({
159+
name: 'server-plugin-middleware',
160+
handler: async (c, next) => {
161+
c.set('message', 'hi modern.js');
162+
await next();
163+
// ...
164+
},
165+
});
166+
167+
// redirect
168+
renderMiddlewares?.push({
169+
name: 'server-plugin-render-middleware',
170+
handler: async (c, next) => {
171+
const user = getUser(c.req);
172+
if (!user) {
173+
return c.redirect('/login');
174+
}
175+
176+
await next();
177+
},
178+
});
179+
return serverConfig;
180+
},
181+
};
182+
},
183+
});
184+
```
185+
186+
187+
```ts title="server/modern.server.ts"
188+
import { defineServerConfig } from '@modern-js/server-runtime';
189+
import serverPlugin from './plugins/serverPlugin';
190+
191+
export default defineServerConfig({
192+
plugins: [serverPlugin()],
193+
});
194+
```
195+
196+
197+
```ts title="src/routes/page.data.ts"
198+
import { useHonoContext } from '@modern-js/server-runtime';
199+
import { defer } from '@modern-js/runtime/router';
200+
201+
export default () => {
202+
const ctx = useHonoContext();
203+
// Consuming Data Injected by the Server-Side
204+
const message = ctx.get('message');
205+
206+
// ...
207+
};
208+
209+
```

0 commit comments

Comments
 (0)