@modern-js/main-doc 2.49.4 → 2.51.0
Sign up to get free protection for your applications and to get access to all the features.
- package/docs/en/apis/app/runtime/web-server/middleware.mdx +7 -1
- package/docs/en/apis/app/runtime/web-server/unstable_middleware.mdx +134 -0
- package/docs/en/guides/advanced-features/web-server.mdx +41 -5
- package/docs/en/guides/basic-features/deploy.mdx +176 -0
- package/docs/zh/apis/app/runtime/web-server/middleware.mdx +7 -0
- package/docs/zh/apis/app/runtime/web-server/unstable_middleware.mdx +133 -0
- package/docs/zh/guides/advanced-features/web-server.mdx +35 -2
- package/docs/zh/guides/basic-features/deploy.mdx +177 -0
- package/package.json +5 -5
@@ -1,10 +1,17 @@
|
|
1
1
|
---
|
2
2
|
title: Middleware
|
3
3
|
---
|
4
|
+
|
4
5
|
# Middleware
|
5
6
|
|
6
7
|
Used to extend the built-in Web Server of Modern.js, unlike [Hook](/apis/app/runtime/web-server/hook), Middleware can directly operate Node's origin request and response, and can be extended using the framework plugin.
|
7
8
|
|
9
|
+
:::note
|
10
|
+
In the next major release, Modern.js will use new middleware to replace this approach.
|
11
|
+
|
12
|
+
It is recommended to use [UnstableMiddleware](/apis/app/runtime/web-server/unstable_middleware) to handle page requests.
|
13
|
+
:::
|
14
|
+
|
8
15
|
:::note
|
9
16
|
For more detail, see [Extend Web Server](/guides/advanced-features/web-server).
|
10
17
|
|
@@ -125,7 +132,6 @@ export const middleware: SomeType = (ctx, next) => {
|
|
125
132
|
|
126
133
|
By default, the framework extension capability of Web Server is turned off after installing the framework extension plugin. If you want to use the framework extension, you can turn it on through ['server.enableFrameworkExt'](/configure/app/server/enable-framework-ext.html).
|
127
134
|
|
128
|
-
|
129
135
|
:::info
|
130
136
|
The type name exported by the framework extension may not 'Middleware', but is named by the framework extension plugin.
|
131
137
|
:::
|
@@ -0,0 +1,134 @@
|
|
1
|
+
---
|
2
|
+
title: Unstable Middleware
|
3
|
+
---
|
4
|
+
|
5
|
+
# Unstable Middleware
|
6
|
+
|
7
|
+
Used to extend the built-in Web Server in Modern.js.
|
8
|
+
UnstableMiddleware will replace [Middleware](/apis/app/runtime/web-server/middleware) in the future.
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
```ts title="server/index.ts"
|
13
|
+
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
14
|
+
|
15
|
+
export const unstableMiddlewares: UnstableMiddleware[] = [];
|
16
|
+
```
|
17
|
+
|
18
|
+
## Types
|
19
|
+
|
20
|
+
**UnstableMiddleware**
|
21
|
+
|
22
|
+
```ts
|
23
|
+
type UnstableMiddleware<
|
24
|
+
V extends Record<string, unknown> = Record<string, unknown>,
|
25
|
+
> = (
|
26
|
+
c: UnstableMiddlewareContext<V>,
|
27
|
+
next: UnstableNext,
|
28
|
+
) => Promise<void | Response>;
|
29
|
+
```
|
30
|
+
|
31
|
+
**UnstableMiddlewareContext**
|
32
|
+
|
33
|
+
```ts
|
34
|
+
type Body = ReadableStream | ArrayBuffer | string | null;
|
35
|
+
|
36
|
+
type UnstableMiddlewareContext<
|
37
|
+
V extends Record<string, unknown> = Record<string, unknown>,
|
38
|
+
> = {
|
39
|
+
request: Request;
|
40
|
+
response: Response;
|
41
|
+
get: Get<V>;
|
42
|
+
set: Set<V>;
|
43
|
+
header: (name: string, value: string, options?: { append?: boolean }) => void;
|
44
|
+
status: (code: number) => void;
|
45
|
+
redirect: (location: string, status?: number) => Response;
|
46
|
+
body: (data: Body, init?: ResponseInit) => Response;
|
47
|
+
html: (
|
48
|
+
data: string | Promise<string>,
|
49
|
+
init?: ResponseInit,
|
50
|
+
) => Response | Promise<Response>;
|
51
|
+
};
|
52
|
+
```
|
53
|
+
|
54
|
+
**UnstableNext**
|
55
|
+
|
56
|
+
```ts
|
57
|
+
type UnstableNext = () => Promise<void>;
|
58
|
+
```
|
59
|
+
|
60
|
+
## Examples
|
61
|
+
|
62
|
+
### Web Server Timing
|
63
|
+
|
64
|
+
```ts
|
65
|
+
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
66
|
+
|
67
|
+
const time: UnstableMiddleware = async (c, next) => {
|
68
|
+
const start = Date.now();
|
69
|
+
|
70
|
+
await next();
|
71
|
+
|
72
|
+
const end = Date.now();
|
73
|
+
|
74
|
+
console.log(`${end - start}`);
|
75
|
+
};
|
76
|
+
|
77
|
+
export const unstableMiddlewares: UnstableMiddleware = [time];
|
78
|
+
```
|
79
|
+
|
80
|
+
### Injecting Server Data for DataLoader Consumption
|
81
|
+
|
82
|
+
```ts title="shared/index.ts"
|
83
|
+
export type Vars = {
|
84
|
+
message: string;
|
85
|
+
};
|
86
|
+
```
|
87
|
+
|
88
|
+
```ts title="server/index.ts"
|
89
|
+
import {
|
90
|
+
UnstableMiddleware,
|
91
|
+
UnstableMiddlewareContext,
|
92
|
+
} from '@modern-js/runtime/server';
|
93
|
+
import type { Vars } from '../shared/index';
|
94
|
+
|
95
|
+
const setPayload: UnstableMiddleware = async (
|
96
|
+
c: UnstableMiddlewareContext<Vars>,
|
97
|
+
next,
|
98
|
+
) => {
|
99
|
+
c.set('message', 'facker');
|
100
|
+
|
101
|
+
await next();
|
102
|
+
};
|
103
|
+
|
104
|
+
export const unstableMiddlewares: UnstableMiddleware = [setPayload];
|
105
|
+
```
|
106
|
+
|
107
|
+
```ts title="src/routes/page.data.ts"
|
108
|
+
import type { Payload } from '../../shared/index';
|
109
|
+
import { LoaderFunctionArgs } from '@modern-js/runtime/router';
|
110
|
+
|
111
|
+
export const loader = async ({ context }: LoaderFunctionArgs<Vars>) => {
|
112
|
+
const message = context?.get('message');
|
113
|
+
|
114
|
+
// ...
|
115
|
+
};
|
116
|
+
```
|
117
|
+
|
118
|
+
### Redirect
|
119
|
+
|
120
|
+
```ts
|
121
|
+
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
122
|
+
|
123
|
+
const auth: UnstableMiddleware = async (c, next) => {
|
124
|
+
const user = getUser(c.request);
|
125
|
+
|
126
|
+
if (!user) {
|
127
|
+
return c.redirect('/login');
|
128
|
+
}
|
129
|
+
|
130
|
+
await next();
|
131
|
+
};
|
132
|
+
|
133
|
+
export const unstableMiddlewares: UnstableMiddleware = [auth];
|
134
|
+
```
|
@@ -50,15 +50,18 @@ The Hook provided by Modern.js is used to control the built-in logic in the Web
|
|
50
50
|
Currently, two Hooks are provided: `AfterMatch` and `AfterRender`, which can be used to modify the rendering results. It can be written in `server/index.ts` as follows:
|
51
51
|
|
52
52
|
```ts
|
53
|
-
import type {
|
53
|
+
import type {
|
54
|
+
AfterMatchHook,
|
55
|
+
AfterRenderHook,
|
56
|
+
} from '@modern-js/runtime/server';
|
54
57
|
|
55
58
|
export const afterMatch: AfterMatchHook = (ctx, next) => {
|
56
59
|
next();
|
57
|
-
}
|
60
|
+
};
|
58
61
|
|
59
62
|
export const afterRender: AfterRenderHook = (ctx, next) => {
|
60
63
|
next();
|
61
|
-
}
|
64
|
+
};
|
62
65
|
```
|
63
66
|
|
64
67
|
Projects should follow these best practices when using Hook:
|
@@ -75,12 +78,18 @@ For more detail, see [Hook](/apis/app/runtime/web-server/hook).
|
|
75
78
|
|
76
79
|
For some projects, there may be more requirements at the server level, Modern.js provides Middleware to add pre-middleware for Web Server. It can only run in a Node environment, so if the project is deployed to another environment, such as a Worker environment, Middleware cannot be used.
|
77
80
|
|
81
|
+
:::note
|
82
|
+
In the next major release, Modern.js will use new middleware to replace this approach.
|
83
|
+
|
84
|
+
It is recommended to use [UnstableMiddleware](/guides/advanced-features/web-server.html#unstablemiddleware) to handle page requests.
|
85
|
+
:::
|
86
|
+
|
78
87
|
Modern.js provides a set of APIs by default for projects to use:
|
79
88
|
|
80
89
|
```ts
|
81
|
-
import {
|
90
|
+
import { Middleware } from '@modern-js/runtime/server';
|
82
91
|
|
83
|
-
export const middleware:
|
92
|
+
export const middleware: Middleware = (context, next) => {
|
84
93
|
const { source: { req, res } } = context;
|
85
94
|
console.log(req.url);
|
86
95
|
next();
|
@@ -99,6 +108,33 @@ Projects should follow these best practices when using Middleware:
|
|
99
108
|
|
100
109
|
**In general, in CSR projects, using Hook can basically meet all the needs of simple scenarios. In SSR projects, Middleware can be used for more complex Node extensions.**
|
101
110
|
|
111
|
+
### UnstableMiddleware
|
112
|
+
|
113
|
+
Modern.js will provide new Middleware to add pre-processing middleware to the Web Server, supporting the execution of custom logic before and after handling the page.
|
114
|
+
|
115
|
+
```ts title="server/index.ts"
|
116
|
+
import {
|
117
|
+
UnstableMiddleware,
|
118
|
+
UnstableMiddlewareContext,
|
119
|
+
} from '@modern-js/runtime/server';
|
120
|
+
|
121
|
+
const time: UnstableMiddleware = async (c: UnstableMiddlewareContext, next) => {
|
122
|
+
const start = Date.now();
|
123
|
+
|
124
|
+
await next();
|
125
|
+
|
126
|
+
const end = Date.now();
|
127
|
+
|
128
|
+
console.log(`dur=${end - start}`);
|
129
|
+
};
|
130
|
+
|
131
|
+
export const unstableMiddleware: UnstableMiddleware[] = [time];
|
132
|
+
```
|
133
|
+
|
134
|
+
:::note
|
135
|
+
For detailed API and more usage, please refer to [UnstableMiddleware](/apis/app/runtime/web-server/unstable_middleware)
|
136
|
+
:::
|
137
|
+
|
102
138
|
## Managed Page Requests with BFF
|
103
139
|
|
104
140
|
The second way is to use BFF to Managed page rendering. In this way, all requests will first hit the BFF service.
|
@@ -0,0 +1,176 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 15
|
3
|
+
---
|
4
|
+
|
5
|
+
# Deploy
|
6
|
+
|
7
|
+
Currently, Modern.js can run in the node.js environment, you can host it yourself. At the same time, Modern.js officially supports deployment on the Netlify platform.
|
8
|
+
|
9
|
+
:::info
|
10
|
+
Currently Modern.js only supports running in node.js environments, support for other runtime environments will be provided in a later version.
|
11
|
+
:::
|
12
|
+
|
13
|
+
|
14
|
+
## Commands to build products
|
15
|
+
|
16
|
+
Running the `modern deploy` command will automatically build the output file for the production environment. This process includes optimizing the output file and its dependencies, and detecting the current deployment platform and automatically generating a product that will run on that platform.
|
17
|
+
|
18
|
+
If you want to generate and test the output locally for a specific deployment platform, you can specify the platform by setting the environment variable: `modern deploy`:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
MODERNJS_DEPLOY=netlify npx modern deploy
|
22
|
+
```
|
23
|
+
|
24
|
+
:::info
|
25
|
+
When deploying on the deployment platforms officially supported by Modern.js, there is no need to specify environment variables.
|
26
|
+
:::
|
27
|
+
|
28
|
+
|
29
|
+
## Node.js
|
30
|
+
|
31
|
+
### Single Repo
|
32
|
+
|
33
|
+
By default, Modern.js outputs builds that can be run in a Node.js environment when no Modern.js-supported deployment platform is detected.
|
34
|
+
|
35
|
+
Use the following command to build the project:
|
36
|
+
```bash
|
37
|
+
npx modern deploy
|
38
|
+
```
|
39
|
+
|
40
|
+
When running the `modern deploy` command, Modern.js will generate runnable products and output the following content:
|
41
|
+
|
42
|
+
```bash
|
43
|
+
Static directory: `.output/static`
|
44
|
+
You can preview this build by `node .output/index`
|
45
|
+
```
|
46
|
+
|
47
|
+
At this point, you can run the entire server by `node .output/index`, and the static resources required for the page are in the `.output/static` directory. You can upload these static resources to a CDN yourself:
|
48
|
+
|
49
|
+
:::info
|
50
|
+
By default, when running Modern.js Server, it listens on port 8080. If you want to change the listening port, you can specify the `PORT` environment variable:
|
51
|
+
```
|
52
|
+
PORT=3000 node .output/index
|
53
|
+
```
|
54
|
+
:::
|
55
|
+
|
56
|
+
|
57
|
+
### Monorepo
|
58
|
+
|
59
|
+
For the Monorepo project, in addition to building our current project, we also need to build other repositories that the current project depends on.
|
60
|
+
|
61
|
+
We assume that the name in the `package.json` of the current project is `app`. Taking pnpm as an example of a monorepo management tool, you can add the following command to the `package.json` of the current project to build products for the current project:
|
62
|
+
|
63
|
+
```json title="app/package.json"
|
64
|
+
{
|
65
|
+
"scripts": {
|
66
|
+
"deploy": "modern deploy",
|
67
|
+
"deploy:app": "pnpm --filter 'app^...' run build && pnpm --filter=app run deploy",
|
68
|
+
}
|
69
|
+
}
|
70
|
+
```
|
71
|
+
|
72
|
+
If you use rush to manage repositories, you can add the following command in `package.json`:
|
73
|
+
|
74
|
+
```json
|
75
|
+
{
|
76
|
+
"scripts": {
|
77
|
+
"deploy": "modern deploy",
|
78
|
+
"deploy:app": "rush rebuild --to-except app && rushx deploy",
|
79
|
+
}
|
80
|
+
}
|
81
|
+
```
|
82
|
+
|
83
|
+
After the build is completed, Modern.js will generate all dependencies in the `.output/node_modules` directory of the project. Similarly, you can run the entire server using `node .output/index`.
|
84
|
+
|
85
|
+
## Netlify
|
86
|
+
|
87
|
+
Netlify is a popular web development platform designed for building, deploying, and maintaining modern web projects. Deploying on Netlify mainly requires configuring the `netlify.toml` file.
|
88
|
+
|
89
|
+
Depending on the complexity of your project, you can configure it incrementally by this doc.
|
90
|
+
|
91
|
+
### Pure Front-end Project
|
92
|
+
|
93
|
+
Add the `netlify.toml` file to the root directory of the current project:
|
94
|
+
|
95
|
+
```bash
|
96
|
+
./
|
97
|
+
├── src/
|
98
|
+
├── modern.config.ts
|
99
|
+
├── netlify.toml
|
100
|
+
├── package.json
|
101
|
+
```
|
102
|
+
|
103
|
+
Add the following content to `netlify.toml`:
|
104
|
+
```toml
|
105
|
+
[build]
|
106
|
+
publish = "dist"
|
107
|
+
command = "npm run deploy"
|
108
|
+
```
|
109
|
+
|
110
|
+
Add a project to the Netlify platform and deploy it!
|
111
|
+
|
112
|
+
### Full Stack Project
|
113
|
+
|
114
|
+
Full-stack projects refer to projects that use custom servers, SSR, and BFF. These projects need to be deployed on Netlify Functions. Based on the `netlify.toml` file mentioned above,
|
115
|
+
add the following configuration:
|
116
|
+
|
117
|
+
```toml title="netlify.toml"
|
118
|
+
[build]
|
119
|
+
publish = "dist"
|
120
|
+
command = "npm run deploy"
|
121
|
+
|
122
|
+
[functions]
|
123
|
+
directory = ".netlify/functions"
|
124
|
+
node_bundler = "none"
|
125
|
+
included_files = [".netlify/functions/**"]
|
126
|
+
|
127
|
+
```
|
128
|
+
|
129
|
+
:::info
|
130
|
+
Currently, Modern.js does not support deployment on Netlify Edge Functions. We will support it in future versions.
|
131
|
+
:::
|
132
|
+
|
133
|
+
|
134
|
+
### Monorepo
|
135
|
+
|
136
|
+
For Monorepo projects, in addition to building our current project, we also need to build the dependencies of the current project from other repositories.
|
137
|
+
We take a pnpm monorepo repository as an example and deploy the Monorepo project on Netlify.
|
138
|
+
|
139
|
+
Suppose we have the following Monorepo repository:
|
140
|
+
|
141
|
+
```
|
142
|
+
./
|
143
|
+
├── packages/
|
144
|
+
│ ├── app/
|
145
|
+
│ └── app-dep1
|
146
|
+
├── package.json
|
147
|
+
├── pnpm-lock.yaml
|
148
|
+
└── pnpm-workspace.yaml
|
149
|
+
```
|
150
|
+
|
151
|
+
We need to configure Base directory on the netlify platform as `packages/app`:
|
152
|
+
|
153
|
+
<img src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/lmeh7nuptpfnuhd/netlify-monorepo-basedir.png?x-resource-account=public" />
|
154
|
+
|
155
|
+
Add the following script in `packages/app/package.json`, before executing the deployment command of the `app` repository, first execute the build of other repositories in the workspace:
|
156
|
+
|
157
|
+
```json
|
158
|
+
"scripts": {
|
159
|
+
"deploy:app": "pnpm --filter 'app^...' run build && pnpm --filter=app run deploy",
|
160
|
+
}
|
161
|
+
```
|
162
|
+
|
163
|
+
Configure the build command in `netlify.toml`:
|
164
|
+
|
165
|
+
```toml
|
166
|
+
[build]
|
167
|
+
publish = "dist"
|
168
|
+
command = "npm run deploy:app"
|
169
|
+
|
170
|
+
[functions]
|
171
|
+
directory = ".netlify/functions"
|
172
|
+
node_bundler = "none"
|
173
|
+
included_files = [".netlify/functions/**"]
|
174
|
+
```
|
175
|
+
|
176
|
+
Just submit your code and deploy it using the Netlify platform.
|
@@ -1,10 +1,17 @@
|
|
1
1
|
---
|
2
2
|
title: Middleware
|
3
3
|
---
|
4
|
+
|
4
5
|
# Middleware
|
5
6
|
|
6
7
|
用于拓展 Modern.js 内置的 Web Server,与 [Hook](/apis/app/runtime/web-server/hook) 不同的是,Middleware 可以直接操作 Node 原生的请求、响应对象,并且可以使用框架拓展。
|
7
8
|
|
9
|
+
:::note
|
10
|
+
在下一个大版本,Modern.js 将会使用新 Middleware 来替代该写法。
|
11
|
+
|
12
|
+
推荐使用 [UnstableMiddleware](/apis/app/runtime/web-server/unstable_middleware) 处理页面请求。
|
13
|
+
:::
|
14
|
+
|
8
15
|
:::note
|
9
16
|
更多内容可以查看[自定义 Web Server](/guides/advanced-features/web-server)。
|
10
17
|
:::
|
@@ -0,0 +1,133 @@
|
|
1
|
+
---
|
2
|
+
title: Unstable Middleware
|
3
|
+
---
|
4
|
+
|
5
|
+
# Unstable Middleware
|
6
|
+
|
7
|
+
用于拓展 Modern.js 内置的 Web Server。 未来 UnstableMiddleware 将替代 [Middleware](/apis/app/runtime/web-server/middleware)
|
8
|
+
|
9
|
+
## 使用
|
10
|
+
|
11
|
+
```ts title="server/index.ts"
|
12
|
+
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
13
|
+
|
14
|
+
export const unstableMiddlewares: UnstableMiddleware = [];
|
15
|
+
```
|
16
|
+
|
17
|
+
## 类型
|
18
|
+
|
19
|
+
**UnstableMiddleware**
|
20
|
+
|
21
|
+
```ts
|
22
|
+
type UnstableMiddleware<
|
23
|
+
V extends Record<string, unknown> = Record<string, unknown>,
|
24
|
+
> = (
|
25
|
+
c: UnstableMiddlewareContext<V>,
|
26
|
+
next: UnstableNext,
|
27
|
+
) => Promise<void | Response>;
|
28
|
+
```
|
29
|
+
|
30
|
+
**UnstableMiddlewareContext**
|
31
|
+
|
32
|
+
```ts
|
33
|
+
type Body = ReadableStream | ArrayBuffer | string | null;
|
34
|
+
|
35
|
+
type UnstableMiddlewareContext<
|
36
|
+
V extends Record<string, unknown> = Record<string, unknown>,
|
37
|
+
> = {
|
38
|
+
request: Request;
|
39
|
+
response: Response;
|
40
|
+
get: Get<V>;
|
41
|
+
set: Set<V>;
|
42
|
+
header: (name: string, value: string, options?: { append?: boolean }) => void;
|
43
|
+
status: (code: number) => void;
|
44
|
+
redirect: (location: string, status?: number) => Response;
|
45
|
+
body: (data: Body, init?: ResponseInit) => Response;
|
46
|
+
html: (
|
47
|
+
data: string | Promise<string>,
|
48
|
+
init?: ResponseInit,
|
49
|
+
) => Response | Promise<Response>;
|
50
|
+
};
|
51
|
+
```
|
52
|
+
|
53
|
+
**UnstableNext**
|
54
|
+
|
55
|
+
```ts
|
56
|
+
type UnstableNext = () => Promise<void>;
|
57
|
+
```
|
58
|
+
|
59
|
+
## 用例
|
60
|
+
|
61
|
+
### web server 耗时打点
|
62
|
+
|
63
|
+
```ts
|
64
|
+
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
65
|
+
|
66
|
+
const time: UnstableMiddleware = async (c, next) => {
|
67
|
+
const start = Date.now();
|
68
|
+
|
69
|
+
await next();
|
70
|
+
|
71
|
+
const end = Date.now();
|
72
|
+
|
73
|
+
console.log(`${end - start}`);
|
74
|
+
};
|
75
|
+
|
76
|
+
export const unstableMiddlewares: UnstableMiddleware = [time];
|
77
|
+
```
|
78
|
+
|
79
|
+
### 注入服务端数据,供页面 dataLoader 消费
|
80
|
+
|
81
|
+
```ts title="shared/index.ts"
|
82
|
+
export type Vars = {
|
83
|
+
message: string;
|
84
|
+
};
|
85
|
+
```
|
86
|
+
|
87
|
+
```ts title="server/index.ts"
|
88
|
+
import {
|
89
|
+
UnstableMiddleware,
|
90
|
+
UnstableMiddlewareContext,
|
91
|
+
} from '@modern-js/runtime/server';
|
92
|
+
import type { Vars } from '../shared/index';
|
93
|
+
|
94
|
+
const setPayload: UnstableMiddleware = async (
|
95
|
+
c: UnstableMiddlewareContext<Vars>,
|
96
|
+
next,
|
97
|
+
) => {
|
98
|
+
c.set('message', 'facker');
|
99
|
+
|
100
|
+
await next();
|
101
|
+
};
|
102
|
+
|
103
|
+
export const unstableMiddlewares: UnstableMiddleware = [setPayload];
|
104
|
+
```
|
105
|
+
|
106
|
+
```ts title="src/routes/page.data.ts"
|
107
|
+
import type { Payload } from '../../shared/index';
|
108
|
+
import { LoaderFunctionArgs } from '@modern-js/runtime/router';
|
109
|
+
|
110
|
+
export const loader = async ({ context }: LoaderFunctionArgs<Vars>) => {
|
111
|
+
const message = context?.get('message');
|
112
|
+
|
113
|
+
// ...
|
114
|
+
};
|
115
|
+
```
|
116
|
+
|
117
|
+
### 重定向
|
118
|
+
|
119
|
+
```ts
|
120
|
+
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
121
|
+
|
122
|
+
const auth: UnstableMiddleware = async (c, next) => {
|
123
|
+
const user = getUser(c.request);
|
124
|
+
|
125
|
+
if (!user) {
|
126
|
+
return c.redirect('/login');
|
127
|
+
}
|
128
|
+
|
129
|
+
await next();
|
130
|
+
};
|
131
|
+
|
132
|
+
export const unstableMiddlewares: UnstableMiddleware = [auth];
|
133
|
+
```
|
@@ -76,12 +76,18 @@ export const afterRender: AfterRenderHook = (ctx, next) => {
|
|
76
76
|
|
77
77
|
对于某些项目,可能在服务端有更多的需求,Modern.js 提供了 Middleware 为 Web Server 添加前置中间件。它只能运行在 Node 环境下,因此如果项目被部署到其他环境中,如 Worker 环境,则不可以使用 Middleware。
|
78
78
|
|
79
|
+
:::note
|
80
|
+
下一个大版本,Modern.js 将会使用新 Middleware 来替代该写法。
|
81
|
+
|
82
|
+
推荐使用 [UnstableMiddleware](/guides/advanced-features/web-server.html#unstablemiddleware) 处理页面请求。
|
83
|
+
:::
|
84
|
+
|
79
85
|
Modern.js 默认提供了一套 API 供项目使用:
|
80
86
|
|
81
87
|
```ts
|
82
|
-
import {
|
88
|
+
import { Middleware } from '@modern-js/runtime/server';
|
83
89
|
|
84
|
-
export const middleware:
|
90
|
+
export const middleware: Middleware = (context, next) => {
|
85
91
|
const {
|
86
92
|
source: { req, res },
|
87
93
|
} = context;
|
@@ -102,6 +108,33 @@ export const middleware: Middlewre = (context, next) => {
|
|
102
108
|
|
103
109
|
**总的来说,CSR 项目中,使用 Hook 基本能满足简单场景的所有需求。SSR 项目中,可以使用 Middleware 做更复杂的 Node 扩展。**
|
104
110
|
|
111
|
+
### UnstableMiddleware
|
112
|
+
|
113
|
+
Modern.js 将提供新 Middleware 为 Web Server 添加前置中间件,支持在处理页面的前后执行自定义逻辑。
|
114
|
+
|
115
|
+
```ts title="server/index.ts"
|
116
|
+
import {
|
117
|
+
UnstableMiddleware,
|
118
|
+
UnstableMiddlewareContext,
|
119
|
+
} from '@modern-js/runtime/server';
|
120
|
+
|
121
|
+
const time: UnstableMiddleware = async (c: UnstableMiddlewareContext, next) => {
|
122
|
+
const start = Date.now();
|
123
|
+
|
124
|
+
await next();
|
125
|
+
|
126
|
+
const end = Date.now();
|
127
|
+
|
128
|
+
console.log(`dur=${end - start}`);
|
129
|
+
};
|
130
|
+
|
131
|
+
export const unstableMiddleware: UnstableMiddleware[] = [time];
|
132
|
+
```
|
133
|
+
|
134
|
+
:::note
|
135
|
+
详细 API 和更多用法查看 [UnstableMiddleware](/apis/app/runtime/web-server/unstable_middleware)
|
136
|
+
:::
|
137
|
+
|
105
138
|
## 通过 BFF 托管页面请求
|
106
139
|
|
107
140
|
第二种方式,是利用 BFF 来托管页面渲染,这种方式下,所有的请求都会先打到 BFF 的服务。
|
@@ -0,0 +1,177 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 15
|
3
|
+
---
|
4
|
+
|
5
|
+
# 部署
|
6
|
+
|
7
|
+
目前 Modern.js 支持在 node.js 环境下运行,你可以自行托管,同时,Modern.js 官方支持在 Netlify 平台上部署。
|
8
|
+
|
9
|
+
:::info
|
10
|
+
当前仅支持在 node.js 环境运行,对其他运行时环境的支持将在后续版本中提供。
|
11
|
+
:::
|
12
|
+
|
13
|
+
|
14
|
+
## 构建产物的命令
|
15
|
+
|
16
|
+
执行 `modern deploy` 命令将自动构建适用于生产环境的输出文件。此过程包括优化输出文件及其依赖,并检测当前部署平台,自动生成可以在该平台运行的产物。
|
17
|
+
如果你希望在本地生成并测试特定部署平台的产物,可以通过设置环境变量来指定平台:
|
18
|
+
|
19
|
+
```bash
|
20
|
+
MODERNJS_DEPLOY=netlify npx modern deploy
|
21
|
+
```
|
22
|
+
|
23
|
+
:::info
|
24
|
+
在 Modern.js 官方支持的部署平台中部署时,无需指定环境变量。
|
25
|
+
:::
|
26
|
+
|
27
|
+
|
28
|
+
## Node.js
|
29
|
+
|
30
|
+
### 单仓库项目
|
31
|
+
|
32
|
+
默认情况下,当未检测到 Modern.js 支持的部署平台时,Modern.js 会输出可以在 Node.js 环境下运行的构建产物。
|
33
|
+
|
34
|
+
使用以下命令构建项目:
|
35
|
+
```bash
|
36
|
+
npx modern deploy
|
37
|
+
```
|
38
|
+
|
39
|
+
当执行 `modern deploy` 命令时,Modern.js 会产出可运行的生产环境产物,并输出以下内容:
|
40
|
+
|
41
|
+
```bash
|
42
|
+
Static directory: `.output/static`
|
43
|
+
You can preview this build by `node .output/index`
|
44
|
+
```
|
45
|
+
|
46
|
+
此时,你可以通过 `node .output/index` 运行整个 server,在 `.output/static` 目录下是页面所需的静态资源,你可以将这些静态资源自行上传至 CDN。
|
47
|
+
|
48
|
+
:::info
|
49
|
+
默认情况下,运行 Modern.js Server 时会监听 8080 端口,如果你想修改监听的端口,可以指定 `PORT` 环境变量:
|
50
|
+
```
|
51
|
+
PORT=3000 node .output/index
|
52
|
+
```
|
53
|
+
:::
|
54
|
+
|
55
|
+
|
56
|
+
### Monorepo
|
57
|
+
|
58
|
+
对于 Monorepo 项目,除了需要构建我们当前的项目外,还需要构建当前项目的依赖的其他仓库。
|
59
|
+
|
60
|
+
假设当前项目的 `package.json` 中的 name 为 `app`,以 pnpm 作为 monorepo 管理工具为例,你可以在当前项目的 `package.json` 添加以下命令用于构建当前项目的产物:
|
61
|
+
|
62
|
+
```json title="app/package.json"
|
63
|
+
{
|
64
|
+
"scripts": {
|
65
|
+
"deploy": "modern deploy",
|
66
|
+
"deploy:app": "pnpm --filter 'app^...' run build && pnpm --filter=app run deploy",
|
67
|
+
}
|
68
|
+
}
|
69
|
+
```
|
70
|
+
|
71
|
+
如果你使用 rush 管理仓库,可以在 `package.json` 中添加以下命令:
|
72
|
+
|
73
|
+
```json
|
74
|
+
{
|
75
|
+
"scripts": {
|
76
|
+
"deploy": "modern deploy",
|
77
|
+
"deploy:app": "rush rebuild --to-except app && rushx deploy",
|
78
|
+
}
|
79
|
+
}
|
80
|
+
```
|
81
|
+
|
82
|
+
当构建完成后,Modern.js 会将项目中所有的依赖生成在 `.output/node_modules` 目录下。同样的,你可以使用 `node .output/index` 运行整个 Server。
|
83
|
+
|
84
|
+
## Netlify
|
85
|
+
|
86
|
+
Netlify 是一个流行的 web 开发平台,专为构建、发布和维护现代 web 项目而设计,在 Netlify 上部署,主要需要配置 `netlify.toml` 文件,
|
87
|
+
根据你的项目复杂度,可以渐进配置。
|
88
|
+
|
89
|
+
### 纯前端项目
|
90
|
+
|
91
|
+
在当前项目的根目录添加 `netlify.toml` 文件:
|
92
|
+
|
93
|
+
```bash
|
94
|
+
./
|
95
|
+
├── src/
|
96
|
+
├── modern.config.ts
|
97
|
+
├── netlify.toml
|
98
|
+
├── package.json
|
99
|
+
```
|
100
|
+
|
101
|
+
在 `netlify.toml` 中添加以下内容:
|
102
|
+
```toml
|
103
|
+
[build]
|
104
|
+
publish = "dist"
|
105
|
+
command = "npm run deploy"
|
106
|
+
```
|
107
|
+
|
108
|
+
在 Netlify 平台上添加项目,部署即可。
|
109
|
+
|
110
|
+
### 全栈项目
|
111
|
+
|
112
|
+
全栈项目是指使用了 自定义 Server,SSR,BFF 的项目,这些项目需要部署在 Netlify Functions 上。基于上述的 `netlify.toml` 文件,
|
113
|
+
添加以下配置:
|
114
|
+
|
115
|
+
```toml title="netlify.toml"
|
116
|
+
[build]
|
117
|
+
publish = "dist"
|
118
|
+
command = "npm run deploy"
|
119
|
+
|
120
|
+
[functions]
|
121
|
+
directory = ".netlify/functions"
|
122
|
+
node_bundler = "none"
|
123
|
+
included_files = [".netlify/functions/**"]
|
124
|
+
|
125
|
+
```
|
126
|
+
|
127
|
+
:::info
|
128
|
+
目前 Modern.js 还不支持在 Netlify Edge Functions 进行部署,我们将在后续的版本中支持。
|
129
|
+
:::
|
130
|
+
|
131
|
+
|
132
|
+
### Monorepo 项目
|
133
|
+
|
134
|
+
对于 Monorepo 项目,除了需要构建我们当前的项目外,还需要构建当前项目的依赖的其他仓库。我们以一个 pnpm monorepo 仓库为例,
|
135
|
+
在 Netlify 上对 Monorepo 项目进行部署。
|
136
|
+
|
137
|
+
假设我们有以下 Monorepo 仓库:
|
138
|
+
|
139
|
+
```
|
140
|
+
./
|
141
|
+
├── packages/
|
142
|
+
│ ├── app/
|
143
|
+
│ └── app-dep1
|
144
|
+
├── package.json
|
145
|
+
├── pnpm-lock.yaml
|
146
|
+
└── pnpm-workspace.yaml
|
147
|
+
```
|
148
|
+
|
149
|
+
我们需要在 netlify 平台上配置 Base directory 为 `packages/app`:
|
150
|
+
|
151
|
+
<img src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/lmeh7nuptpfnuhd/netlify-monorepo-basedir.png?x-resource-account=public" />
|
152
|
+
|
153
|
+
在 `packages/app/package.json` 中添加以下 script,在执行 `app` 仓库的部署命令之前,先执行 workspace 中其他仓库的构建:
|
154
|
+
|
155
|
+
```json
|
156
|
+
"scripts": {
|
157
|
+
"deploy:app": "pnpm --filter 'app^...' run build && pnpm --filter=app run deploy",
|
158
|
+
}
|
159
|
+
```
|
160
|
+
|
161
|
+
在 `netlify.toml` 配置构建命令:
|
162
|
+
|
163
|
+
```toml
|
164
|
+
[build]
|
165
|
+
publish = "dist"
|
166
|
+
command = "npm run deploy:app"
|
167
|
+
|
168
|
+
[functions]
|
169
|
+
directory = ".netlify/functions"
|
170
|
+
node_bundler = "none"
|
171
|
+
included_files = [".netlify/functions/**"]
|
172
|
+
```
|
173
|
+
|
174
|
+
提交你的代码,使用 Netlify 平台部署即可。
|
175
|
+
|
176
|
+
|
177
|
+
|
package/package.json
CHANGED
@@ -15,17 +15,17 @@
|
|
15
15
|
"modern",
|
16
16
|
"modern.js"
|
17
17
|
],
|
18
|
-
"version": "2.
|
18
|
+
"version": "2.51.0",
|
19
19
|
"publishConfig": {
|
20
20
|
"registry": "https://registry.npmjs.org/",
|
21
21
|
"access": "public",
|
22
22
|
"provenance": true
|
23
23
|
},
|
24
24
|
"dependencies": {
|
25
|
-
"@modern-js/sandpack-react": "2.
|
25
|
+
"@modern-js/sandpack-react": "2.51.0"
|
26
26
|
},
|
27
27
|
"peerDependencies": {
|
28
|
-
"@modern-js/builder-doc": "^2.
|
28
|
+
"@modern-js/builder-doc": "^2.51.0"
|
29
29
|
},
|
30
30
|
"devDependencies": {
|
31
31
|
"classnames": "^2",
|
@@ -39,8 +39,8 @@
|
|
39
39
|
"@rspress/shared": "1.18.2",
|
40
40
|
"@types/node": "^16",
|
41
41
|
"@types/fs-extra": "9.0.13",
|
42
|
-
"@modern-js/doc
|
43
|
-
"@modern-js/
|
42
|
+
"@modern-js/builder-doc": "2.51.0",
|
43
|
+
"@modern-js/doc-plugin-auto-sidebar": "2.51.0"
|
44
44
|
},
|
45
45
|
"scripts": {
|
46
46
|
"dev": "rspress dev",
|