@modern-js/main-doc 2.50.0 → 2.52.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/unstable_middleware.mdx +30 -4
- package/docs/en/guides/advanced-features/web-server.mdx +3 -3
- package/docs/en/guides/basic-features/data/data-fetch.mdx +28 -0
- package/docs/en/guides/basic-features/deploy.mdx +286 -0
- package/docs/zh/apis/app/runtime/web-server/unstable_middleware.mdx +30 -4
- package/docs/zh/guides/advanced-features/web-server.mdx +3 -3
- package/docs/zh/guides/basic-features/data/data-fetch.mdx +27 -2
- package/docs/zh/guides/basic-features/deploy.mdx +281 -0
- package/package.json +5 -5
@@ -12,7 +12,7 @@ UnstableMiddleware will replace [Middleware](/apis/app/runtime/web-server/middle
|
|
12
12
|
```ts title="server/index.ts"
|
13
13
|
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
14
14
|
|
15
|
-
export const
|
15
|
+
export const unstableMiddleware: UnstableMiddleware[] = [];
|
16
16
|
```
|
17
17
|
|
18
18
|
## Types
|
@@ -74,7 +74,7 @@ const time: UnstableMiddleware = async (c, next) => {
|
|
74
74
|
console.log(`${end - start}`);
|
75
75
|
};
|
76
76
|
|
77
|
-
export const
|
77
|
+
export const unstableMiddleware: UnstableMiddleware[] = [time];
|
78
78
|
```
|
79
79
|
|
80
80
|
### Injecting Server Data for DataLoader Consumption
|
@@ -101,7 +101,7 @@ const setPayload: UnstableMiddleware = async (
|
|
101
101
|
await next();
|
102
102
|
};
|
103
103
|
|
104
|
-
export const
|
104
|
+
export const unstableMiddleware: UnstableMiddleware[] = [setPayload];
|
105
105
|
```
|
106
106
|
|
107
107
|
```ts title="src/routes/page.data.ts"
|
@@ -130,5 +130,31 @@ const auth: UnstableMiddleware = async (c, next) => {
|
|
130
130
|
await next();
|
131
131
|
};
|
132
132
|
|
133
|
-
export const
|
133
|
+
export const unstableMiddleware: UnstableMiddleware[] = [auth];
|
134
|
+
```
|
135
|
+
|
136
|
+
### Modify Response
|
137
|
+
|
138
|
+
```ts
|
139
|
+
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
140
|
+
|
141
|
+
const modifier: UnstableMiddleware = async (c, next) => {
|
142
|
+
await next();
|
143
|
+
|
144
|
+
const { response } = c;
|
145
|
+
|
146
|
+
const text = await response.text();
|
147
|
+
|
148
|
+
const newText = text.replace('<html>', `<html lang="${language}">`);
|
149
|
+
|
150
|
+
const newheaders = response.headers;
|
151
|
+
newheaders.set('x-custom-value', 'modern');
|
152
|
+
|
153
|
+
c.response = c.body(newText, {
|
154
|
+
status: response.status,
|
155
|
+
headers: newheaders,
|
156
|
+
});
|
157
|
+
};
|
158
|
+
|
159
|
+
export const unstableMiddleware: UnstableMiddleware[] = [modifier];
|
134
160
|
```
|
@@ -87,9 +87,9 @@ It is recommended to use [UnstableMiddleware](/guides/advanced-features/web-serv
|
|
87
87
|
Modern.js provides a set of APIs by default for projects to use:
|
88
88
|
|
89
89
|
```ts
|
90
|
-
import {
|
90
|
+
import { Middleware } from '@modern-js/runtime/server';
|
91
91
|
|
92
|
-
export const middleware:
|
92
|
+
export const middleware: Middleware = (context, next) => {
|
93
93
|
const {
|
94
94
|
source: { req, res },
|
95
95
|
} = context;
|
@@ -110,7 +110,7 @@ Projects should follow these best practices when using Middleware:
|
|
110
110
|
|
111
111
|
**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.**
|
112
112
|
|
113
|
-
###
|
113
|
+
### Unstable Middleware
|
114
114
|
|
115
115
|
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.
|
116
116
|
|
@@ -155,6 +155,8 @@ function loader() {
|
|
155
155
|
|
156
156
|
### Error Handling
|
157
157
|
|
158
|
+
#### Basic Usage
|
159
|
+
|
158
160
|
In the `loader` function, errors can be handled by throwing an `error` or a `response`. When an error is thrown in the `loader` function, Modern.js will stop executing the code in the current `loader` and switch the front-end UI to the defined [`ErrorBoundary`](/guides/basic-features/routes#error-handling) component:
|
159
161
|
|
160
162
|
```tsx
|
@@ -182,6 +184,32 @@ const ErrorBoundary = () => {
|
|
182
184
|
export default ErrorBoundary;
|
183
185
|
```
|
184
186
|
|
187
|
+
#### Practice
|
188
|
+
|
189
|
+
In an SSR project you can control the status code of a page and display the corresponding UI by `throw response` in the data loader, as in the following example, where there is one loader for the entire routing route
|
190
|
+
|
191
|
+
For example, if there is a loader in the entire routing route that throws a response, the status code of the page will be consistent with this `response` and the UI of the page will switch to `ErrorBoundary`.
|
192
|
+
|
193
|
+
```ts
|
194
|
+
// routes/user/profile/page.data.ts
|
195
|
+
export async function loader() {
|
196
|
+
const user = await fetchUser();
|
197
|
+
if(!user){
|
198
|
+
throw new Response('The user was not found', { status: 404 });
|
199
|
+
}
|
200
|
+
return user;
|
201
|
+
}
|
202
|
+
|
203
|
+
// routes/error.tsx
|
204
|
+
import { useRouteError } from '@modern-js/runtime/router';
|
205
|
+
const ErrorBoundary = () => {
|
206
|
+
const error = useRouteError() as { data: string };
|
207
|
+
return <div className="error">{error.data}</div>;
|
208
|
+
};
|
209
|
+
|
210
|
+
export default ErrorBoundary;
|
211
|
+
```
|
212
|
+
|
185
213
|
### Get data from parent component
|
186
214
|
|
187
215
|
In many cases, child components need to access data in the parent component `loader`. You can easily get the data from the parent component using `useRouteLoaderData`:
|
@@ -0,0 +1,286 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 15
|
3
|
+
---
|
4
|
+
|
5
|
+
# Deploy Application
|
6
|
+
|
7
|
+
Currently, Modern.js offers two deployment way:
|
8
|
+
- You can host your application in a container that includes a Node.js environment on your own, which provides flexibility for the deployment of the application.
|
9
|
+
- You can also deploy your application through a platform. Currently, Modern.js supports the [Netlify](https://www.netlify.com/) and [Vercel](https://vercel.com/).
|
10
|
+
|
11
|
+
:::info
|
12
|
+
Currently, Modern.js only supports running in a Node.js environment. Support for more runtime environments will be provided in the future.
|
13
|
+
:::
|
14
|
+
|
15
|
+
|
16
|
+
## Build Deployment Products
|
17
|
+
|
18
|
+
Running the `modern deploy` command will automatically produce deployment products. This process includes optimizing Bundler build products and their dependencies, detecting the current deployment platform, and automatically generating deployment products that can run on that platform.
|
19
|
+
|
20
|
+
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`:
|
21
|
+
|
22
|
+
```bash
|
23
|
+
MODERNJS_DEPLOY=netlify npx modern deploy
|
24
|
+
```
|
25
|
+
|
26
|
+
:::info
|
27
|
+
When deploying on the deployment platforms officially supported by Modern.js, there is no need to specify environment variables.
|
28
|
+
:::
|
29
|
+
|
30
|
+
|
31
|
+
## Node.js
|
32
|
+
|
33
|
+
### Single Repo
|
34
|
+
|
35
|
+
By default, Modern.js outputs builds that can be run in a Node.js environment when no Modern.js-supported deployment platform is detected.
|
36
|
+
|
37
|
+
Use the following command to build the project:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
npx modern deploy
|
41
|
+
```
|
42
|
+
|
43
|
+
When running the `modern deploy` command, Modern.js will generate runnable products and output the following content in terminal:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
Static directory: `.output/static`
|
47
|
+
You can preview this build by `node .output/index`
|
48
|
+
```
|
49
|
+
|
50
|
+
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:
|
51
|
+
|
52
|
+
:::info
|
53
|
+
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:
|
54
|
+
```
|
55
|
+
PORT=3000 node .output/index
|
56
|
+
```
|
57
|
+
:::
|
58
|
+
|
59
|
+
|
60
|
+
### Monorepo
|
61
|
+
|
62
|
+
For Monorepo projects, in addition to building the current project, it is also necessary to build other sub-projects in the repository that the current project depends on.
|
63
|
+
|
64
|
+
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:
|
65
|
+
|
66
|
+
```json title="app/package.json"
|
67
|
+
{
|
68
|
+
"scripts": {
|
69
|
+
"build:packages": "pnpm --filter 'app^...' run build",
|
70
|
+
"deploy": "pnpm run build:packages && modern deploy",
|
71
|
+
}
|
72
|
+
}
|
73
|
+
```
|
74
|
+
|
75
|
+
If you use Rush as your Monorepo management tool, you can add the following commands to your `package.json`:
|
76
|
+
|
77
|
+
```json
|
78
|
+
{
|
79
|
+
"scripts": {
|
80
|
+
"build:packages": "rush rebuild --to-except app",
|
81
|
+
"deploy": "rushx build:packages && modern deploy",
|
82
|
+
}
|
83
|
+
}
|
84
|
+
```
|
85
|
+
|
86
|
+
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 Modern.js server using `node .output/index`.
|
87
|
+
|
88
|
+
## Netlify
|
89
|
+
|
90
|
+
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.
|
91
|
+
|
92
|
+
Depending on the complexity of your project, you can configure it incrementally by this doc.
|
93
|
+
|
94
|
+
### Pure Front-end Project
|
95
|
+
|
96
|
+
Add the `netlify.toml` file to the root directory of the current project:
|
97
|
+
|
98
|
+
```bash
|
99
|
+
.
|
100
|
+
├── src
|
101
|
+
├── modern.config.ts
|
102
|
+
├── netlify.toml
|
103
|
+
└── package.json
|
104
|
+
```
|
105
|
+
|
106
|
+
Add the following content to `netlify.toml`:
|
107
|
+
|
108
|
+
```toml
|
109
|
+
[build]
|
110
|
+
publish = "dist"
|
111
|
+
command = "modern deploy"
|
112
|
+
```
|
113
|
+
|
114
|
+
Now, add a project to the Netlify platform and deploy it!
|
115
|
+
|
116
|
+
### Full Stack Project
|
117
|
+
|
118
|
+
Full-stack projects refer to projects that use Custom Web Server, SSR or BFF. These projects need to be deployed on **Netlify Functions**. Based on the `netlify.toml` file mentioned above, add the following configuration:
|
119
|
+
|
120
|
+
```toml title="netlify.toml"
|
121
|
+
[build]
|
122
|
+
publish = "dist"
|
123
|
+
command = "modern deploy"
|
124
|
+
|
125
|
+
[functions]
|
126
|
+
directory = ".netlify/functions"
|
127
|
+
node_bundler = "none"
|
128
|
+
included_files = [".netlify/functions/**"]
|
129
|
+
|
130
|
+
```
|
131
|
+
|
132
|
+
:::info
|
133
|
+
Currently, Modern.js does not support deployment on Netlify Edge Functions. We will support it in future versions.
|
134
|
+
:::
|
135
|
+
|
136
|
+
|
137
|
+
### Monorepo
|
138
|
+
|
139
|
+
:::info
|
140
|
+
The following guide is mainly for full-stack projects, for pure CSR projects, just follow [Pure Frontend Project](#Pure Frontend Project) to deploy.
|
141
|
+
:::
|
142
|
+
|
143
|
+
For Monorepo projects, in addition to building our current project, you also need to build other sub-projects in the repository that the current project depends on.
|
144
|
+
|
145
|
+
We take a pnpm Monorepo repository as an example and deploy the Monorepo project on Netlify.
|
146
|
+
|
147
|
+
Assuming the directory structure of the Monorepo repository is as follows:
|
148
|
+
|
149
|
+
```
|
150
|
+
.
|
151
|
+
├── packages
|
152
|
+
│ ├── app
|
153
|
+
│ └── app-dep1
|
154
|
+
├── package.json
|
155
|
+
├── pnpm-lock.yaml
|
156
|
+
└── pnpm-workspace.yaml
|
157
|
+
```
|
158
|
+
|
159
|
+
You need to configure Base directory on the netlify platform as `packages/app`:
|
160
|
+
|
161
|
+
<img src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/lmeh7nuptpfnuhd/netlify-monorepo-basedir.png?x-resource-account=public" />
|
162
|
+
|
163
|
+
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:
|
164
|
+
|
165
|
+
```json
|
166
|
+
{
|
167
|
+
"scripts": {
|
168
|
+
"build:packages": "pnpm --filter 'app^...' run build",
|
169
|
+
"deploy": "pnpm run build:packages && modern deploy",
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
```
|
174
|
+
|
175
|
+
Configure the build command in `netlify.toml`:
|
176
|
+
|
177
|
+
```toml
|
178
|
+
[build]
|
179
|
+
publish = "dist"
|
180
|
+
command = "npm run deploy"
|
181
|
+
|
182
|
+
[functions]
|
183
|
+
directory = ".netlify/functions"
|
184
|
+
node_bundler = "none"
|
185
|
+
included_files = [".netlify/functions/**"]
|
186
|
+
```
|
187
|
+
|
188
|
+
Just submit your code and deploy it using the Netlify platform.
|
189
|
+
|
190
|
+
## Vercel
|
191
|
+
|
192
|
+
Vercel is a deployment platform for modern web applications that provides a rich set of features to support deploying static websites, server-side rendered applications, and more. To deploy on Vercel, you usually need to configure the `vercel.json` file, which you can configure incrementally depending on the complexity of your project.
|
193
|
+
|
194
|
+
### Pure Front-end Project
|
195
|
+
|
196
|
+
Add the `vercel.json` file to the root directory of the current project:
|
197
|
+
```bash
|
198
|
+
./
|
199
|
+
├── src
|
200
|
+
├── modern.config.ts
|
201
|
+
├── vercel.json
|
202
|
+
└── package.json
|
203
|
+
```
|
204
|
+
|
205
|
+
Add the following content to `vercel.json`:
|
206
|
+
```json title="vercel.json"
|
207
|
+
{
|
208
|
+
"buildCommand": "modern deploy",
|
209
|
+
"outputDirectory": ".vercel/output"
|
210
|
+
}
|
211
|
+
```
|
212
|
+
|
213
|
+
Commit your project to git, select Framework Preset as `Other` on the Vercel platform and deploy.
|
214
|
+
|
215
|
+
<img src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/lmeh7nuptpfnuhd/vercel-framework-preset.png" />
|
216
|
+
|
217
|
+
### Full Stack Project
|
218
|
+
|
219
|
+
Full-stack projects refer to projects that use Custom Web Server, SSR or BFF. These projects need to be deployed on **Vercel Functions**.
|
220
|
+
|
221
|
+
In addition to configuring `vercel.json` in the same way as a [pure front-end project](#pure-front-end-project), there are two points to note for full-stack projects:
|
222
|
+
|
223
|
+
1. Currently, Modern.js does not support deploying BFF projects on the Vercel platform. We will support it in future versions.
|
224
|
+
2. When deploying on Vercel platform, the default node runtime is `20.x`, it is recommended to choose `18.x` when deploying full-stack projects,
|
225
|
+
see [Serverless Function contains invalid runtime error](https://vercel.com/guides/serverless-function-contains-invalid-runtime-error), you can modify `package.json` to specify the version:
|
226
|
+
```json title="package.json"
|
227
|
+
"engines": {
|
228
|
+
"node": "18.x"
|
229
|
+
}
|
230
|
+
```
|
231
|
+
|
232
|
+
|
233
|
+
### Monorepo
|
234
|
+
|
235
|
+
:::info
|
236
|
+
The following guide is mainly for full-stack projects, for pure CSR projects, just follow [Pure Frontend Project](#pure-front-end-project-1) to deploy.
|
237
|
+
:::
|
238
|
+
|
239
|
+
For Monorepo projects, in addition to building our current project, you also need to build other sub-projects in the repository that the current project depends on.
|
240
|
+
|
241
|
+
We take a pnpm Monorepo repository as an example and deploy the Monorepo project on Vercel.
|
242
|
+
|
243
|
+
Assuming the directory structure of the Monorepo repository is as follows:
|
244
|
+
|
245
|
+
```
|
246
|
+
.
|
247
|
+
├── packages
|
248
|
+
│ ├── app
|
249
|
+
│ └── app-dep1
|
250
|
+
├── package.json
|
251
|
+
├── pnpm-lock.yaml
|
252
|
+
└── pnpm-workspace.yaml
|
253
|
+
```
|
254
|
+
|
255
|
+
First, you need to configure the **Root Directory** as `packages/app` on the Vercel platform:
|
256
|
+
|
257
|
+
<img src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/lmeh7nuptpfnuhd/vercel-root-directory.png" />
|
258
|
+
|
259
|
+
Specify Node.js runtime as `18.x`:
|
260
|
+
|
261
|
+
```json title="package.json"
|
262
|
+
"engines": {
|
263
|
+
"node": "18.x"
|
264
|
+
}
|
265
|
+
````
|
266
|
+
|
267
|
+
Add the following script to `packages/app/package.json` to run `build` command of the other repositories in the workspace before run the `deploy` command for the `app` repository:
|
268
|
+
|
269
|
+
```json
|
270
|
+
{
|
271
|
+
"scripts": {
|
272
|
+
"build:packages": "pnpm --filter 'app^...' run build",
|
273
|
+
"deploy": "pnpm run build:packages && modern deploy",
|
274
|
+
}
|
275
|
+
}
|
276
|
+
```
|
277
|
+
|
278
|
+
Add the following content to the `packages/app/vercel.json` file:
|
279
|
+
```json title="vercel.json"
|
280
|
+
{
|
281
|
+
"buildCommand": "npm run deploy",
|
282
|
+
"outputDirectory": ".vercel/output"
|
283
|
+
}
|
284
|
+
```
|
285
|
+
|
286
|
+
Just submit your code and deploy it using the Vercel platform.
|
@@ -11,7 +11,7 @@ title: Unstable Middleware
|
|
11
11
|
```ts title="server/index.ts"
|
12
12
|
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
13
13
|
|
14
|
-
export const
|
14
|
+
export const unstableMiddleware: UnstableMiddleware[] = [];
|
15
15
|
```
|
16
16
|
|
17
17
|
## 类型
|
@@ -73,7 +73,7 @@ const time: UnstableMiddleware = async (c, next) => {
|
|
73
73
|
console.log(`${end - start}`);
|
74
74
|
};
|
75
75
|
|
76
|
-
export const
|
76
|
+
export const unstableMiddleware: UnstableMiddleware[] = [time];
|
77
77
|
```
|
78
78
|
|
79
79
|
### 注入服务端数据,供页面 dataLoader 消费
|
@@ -100,7 +100,7 @@ const setPayload: UnstableMiddleware = async (
|
|
100
100
|
await next();
|
101
101
|
};
|
102
102
|
|
103
|
-
export const
|
103
|
+
export const unstableMiddleware: UnstableMiddleware[] = [setPayload];
|
104
104
|
```
|
105
105
|
|
106
106
|
```ts title="src/routes/page.data.ts"
|
@@ -129,5 +129,31 @@ const auth: UnstableMiddleware = async (c, next) => {
|
|
129
129
|
await next();
|
130
130
|
};
|
131
131
|
|
132
|
-
export const
|
132
|
+
export const unstableMiddleware: UnstableMiddleware[] = [auth];
|
133
|
+
```
|
134
|
+
|
135
|
+
### 修改响应体
|
136
|
+
|
137
|
+
```ts
|
138
|
+
import { UnstableMiddleware } from '@modern-js/runtime/server';
|
139
|
+
|
140
|
+
const modifier: UnstableMiddleware = async (c, next) => {
|
141
|
+
await next();
|
142
|
+
|
143
|
+
const { response } = c;
|
144
|
+
|
145
|
+
const text = await response.text();
|
146
|
+
|
147
|
+
const newText = text.replace('<html>', `<html lang="${language}">`);
|
148
|
+
|
149
|
+
const newheaders = response.headers;
|
150
|
+
newheaders.set('x-custom-value', 'modern');
|
151
|
+
|
152
|
+
c.response = c.body(newText, {
|
153
|
+
status: response.status,
|
154
|
+
headers: newheaders,
|
155
|
+
});
|
156
|
+
};
|
157
|
+
|
158
|
+
export const unstableMiddleware: UnstableMiddleware[] = [modifier];
|
133
159
|
```
|
@@ -85,9 +85,9 @@ export const afterRender: AfterRenderHook = (ctx, next) => {
|
|
85
85
|
Modern.js 默认提供了一套 API 供项目使用:
|
86
86
|
|
87
87
|
```ts
|
88
|
-
import {
|
88
|
+
import { Middleware } from '@modern-js/runtime/server';
|
89
89
|
|
90
|
-
export const middleware:
|
90
|
+
export const middleware: Middleware = (context, next) => {
|
91
91
|
const {
|
92
92
|
source: { req, res },
|
93
93
|
} = context;
|
@@ -108,7 +108,7 @@ export const middleware: Middlewre = (context, next) => {
|
|
108
108
|
|
109
109
|
**总的来说,CSR 项目中,使用 Hook 基本能满足简单场景的所有需求。SSR 项目中,可以使用 Middleware 做更复杂的 Node 扩展。**
|
110
110
|
|
111
|
-
###
|
111
|
+
### Unstable Middleware
|
112
112
|
|
113
113
|
Modern.js 将提供新 Middleware 为 Web Server 添加前置中间件,支持在处理页面的前后执行自定义逻辑。
|
114
114
|
|
@@ -155,6 +155,8 @@ export async function loader() {
|
|
155
155
|
|
156
156
|
### 错误处理
|
157
157
|
|
158
|
+
#### 基本用法
|
159
|
+
|
158
160
|
在 `loader` 函数中,可以通过 `throw error` 或者 `throw response` 的方式处理错误,当 `loader` 函数中有错误被抛出时,Modern.js 会停止执行当前 `loader` 中的代码,并将前端 UI 切换到定义的 [`ErrorBoundary`](/guides/basic-features/routes#错误处理) 组件:
|
159
161
|
|
160
162
|
```tsx
|
@@ -182,6 +184,31 @@ const ErrorBoundary = () => {
|
|
182
184
|
export default ErrorBoundary;
|
183
185
|
```
|
184
186
|
|
187
|
+
#### 实践
|
188
|
+
|
189
|
+
在 SSR 项目中你可以通过在 data loader 中 `throw response` 的方式,控制页面的状态码,展示对应的 UI,如以下示例,整条路由路线中有一个 loader
|
190
|
+
throw response,页面的状态码将与这个 `response` 保持一致,页面的 UI 也会切换为 `ErrorBoundary`:
|
191
|
+
|
192
|
+
```ts
|
193
|
+
// routes/user/profile/page.data.ts
|
194
|
+
export async function loader() {
|
195
|
+
const user = await fetchUser();
|
196
|
+
if(!user){
|
197
|
+
throw new Response('The user was not found', { status: 404 });
|
198
|
+
}
|
199
|
+
return user;
|
200
|
+
}
|
201
|
+
|
202
|
+
// routes/error.tsx
|
203
|
+
import { useRouteError } from '@modern-js/runtime/router';
|
204
|
+
const ErrorBoundary = () => {
|
205
|
+
const error = useRouteError() as { data: string };
|
206
|
+
return <div className="error">{error.data}</div>;
|
207
|
+
};
|
208
|
+
|
209
|
+
export default ErrorBoundary;
|
210
|
+
```
|
211
|
+
|
185
212
|
### 获取上层组件的数据
|
186
213
|
|
187
214
|
很多场景下,子组件需要获取到祖先组件 `loader` 中的数据,你可以通过 `useRouteLoaderData` 方便地获取到祖先组件的数据:
|
@@ -385,8 +412,6 @@ export const loader = () => {}
|
|
385
412
|
```
|
386
413
|
|
387
414
|
|
388
|
-
|
389
|
-
|
390
415
|
### 错误用法
|
391
416
|
|
392
417
|
1. `loader` 中只能返回可序列化的数据,在 SSR 环境下,`loader` 函数的返回值会被序列化为 JSON 字符串,然后在客户端被反序列化为对象。因此,`loader` 函数中不能返回不可序列化的数据(如函数)。
|
@@ -0,0 +1,281 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 15
|
3
|
+
---
|
4
|
+
|
5
|
+
# 部署应用
|
6
|
+
|
7
|
+
目前,Modern.js 提供了两种部署方式:
|
8
|
+
|
9
|
+
- 你可以将应用自行托管在包含 Node.js 环境的容器中,这为应用提供了部署的灵活性。
|
10
|
+
- 你也可以通过平台部署应用,目前 Modern.js 官方支持了 [Netlify](https://www.netlify.com/) 和 [Vercel](https://vercel.com/) 平台。
|
11
|
+
|
12
|
+
:::info
|
13
|
+
目前 Modern.js 仅支持在 Node.js 环境中运行,未来将提供更多运行时环境的支持。
|
14
|
+
:::
|
15
|
+
|
16
|
+
|
17
|
+
## 构建部署产物
|
18
|
+
|
19
|
+
执行 `modern deploy` 命令将自动输出部署产物。此过程包括优化 Bundler 构建产物及产物依赖,检测当前部署平台,并自动生成可以在该平台运行的产物。
|
20
|
+
如果你希望在本地生成并测试特定部署平台的产物,可以通过设置环境变量来指定平台:
|
21
|
+
|
22
|
+
```bash
|
23
|
+
MODERNJS_DEPLOY=netlify npx modern deploy
|
24
|
+
```
|
25
|
+
|
26
|
+
:::info
|
27
|
+
在 Modern.js 官方支持的部署平台中部署时,无需指定环境变量。
|
28
|
+
:::
|
29
|
+
|
30
|
+
|
31
|
+
## Node.js
|
32
|
+
|
33
|
+
### 单仓库项目
|
34
|
+
|
35
|
+
默认情况下,如果未检测到 Modern.js 支持的部署平台,Modern.js 将生成可以在 Node.js 环境下运行的部署产物。
|
36
|
+
|
37
|
+
你可以使用以下命令构建项目:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
npx modern deploy
|
41
|
+
```
|
42
|
+
|
43
|
+
当执行 `modern deploy` 命令时,Modern.js 将生成可执行的部署产物,并在控制台输出以下内容:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
Static directory: `.output/static`
|
47
|
+
You can preview this build by `node .output/index`
|
48
|
+
```
|
49
|
+
|
50
|
+
现在,你可以通过执行 `node .output/index` 命令来运行服务器。在 `.output/static` 目录中,存放了页面运行所需的静态资源,你可以选择将这些资源上传到 CDN 以提高访问速度。
|
51
|
+
|
52
|
+
:::info
|
53
|
+
默认情况下,运行 Modern.js 服务器时会监听 8080 端口,如果你想修改监听的端口,可以指定 `PORT` 环境变量:
|
54
|
+
|
55
|
+
```
|
56
|
+
PORT=3000 node .output/index
|
57
|
+
```
|
58
|
+
:::
|
59
|
+
|
60
|
+
|
61
|
+
### Monorepo
|
62
|
+
|
63
|
+
对于 Monorepo 项目,除了需要构建当前的项目外,还需要构建当前项目依赖的仓库中其他子项目。
|
64
|
+
|
65
|
+
假设当前项目的 `package.json` 中的 name 为 `app`,以 pnpm 作为 Monorepo 管理工具为例,你可以在项目 `package.json` 中添加以下命令用于构建:
|
66
|
+
|
67
|
+
```json title="app/package.json"
|
68
|
+
{
|
69
|
+
"scripts": {
|
70
|
+
"build:packages": "pnpm --filter 'app^...' run build",
|
71
|
+
"deploy": "pnpm run build:packages && modern deploy",
|
72
|
+
}
|
73
|
+
}
|
74
|
+
```
|
75
|
+
|
76
|
+
如果你使用 rush 作为 Monorepo 管理工具,可以在 `package.json` 中添加以下命令:
|
77
|
+
|
78
|
+
```json
|
79
|
+
{
|
80
|
+
"scripts": {
|
81
|
+
"build:packages": "rush rebuild --to-except app",
|
82
|
+
"deploy": "rushx build:packages && modern deploy",
|
83
|
+
}
|
84
|
+
}
|
85
|
+
```
|
86
|
+
|
87
|
+
构建完成后,框架会将项目中所有的依赖生成在 `.output/node_modules` 目录下。你同样可以使用 `node .output/index` 运行 Modern.js 服务器。
|
88
|
+
|
89
|
+
## Netlify
|
90
|
+
|
91
|
+
Netlify 是一个流行的 Web 开发平台,专为构建、发布和维护现代 Web 项目而设计。在 Netlify 上部署,通常需要配置 `netlify.toml` 文件,你可以根据项目复杂度,渐进地配置该文件。
|
92
|
+
|
93
|
+
### 纯前端项目
|
94
|
+
|
95
|
+
在当前项目的根目录添加 `netlify.toml` 文件:
|
96
|
+
|
97
|
+
```bash
|
98
|
+
./
|
99
|
+
├── src
|
100
|
+
├── modern.config.ts
|
101
|
+
├── netlify.toml
|
102
|
+
└── package.json
|
103
|
+
```
|
104
|
+
|
105
|
+
在 `netlify.toml` 中添加以下内容:
|
106
|
+
```toml
|
107
|
+
[build]
|
108
|
+
publish = "dist"
|
109
|
+
command = "modern deploy"
|
110
|
+
```
|
111
|
+
|
112
|
+
在 Netlify 平台上添加项目,部署即可。
|
113
|
+
|
114
|
+
### 全栈项目
|
115
|
+
|
116
|
+
全栈项目是指使用了自定义 Web Server、SSR、BFF 的项目,这些项目需要部署在 **Netlify Functions** 上。你需要基于上述的 `netlify.toml` 文件,添加以下配置:
|
117
|
+
|
118
|
+
```toml title="netlify.toml"
|
119
|
+
[build]
|
120
|
+
publish = "dist"
|
121
|
+
command = "modern deploy"
|
122
|
+
|
123
|
+
[functions]
|
124
|
+
directory = ".netlify/functions"
|
125
|
+
node_bundler = "none"
|
126
|
+
included_files = [".netlify/functions/**"]
|
127
|
+
|
128
|
+
```
|
129
|
+
|
130
|
+
:::info
|
131
|
+
目前 Modern.js 还不支持在 Netlify Edge Functions 进行部署,我们将在后续的版本中支持。
|
132
|
+
:::
|
133
|
+
|
134
|
+
|
135
|
+
### Monorepo 项目
|
136
|
+
|
137
|
+
:::info
|
138
|
+
以下指南主要针对于全栈项目,对于纯 CSR 的项目,只需要按照[纯前端项目](#纯前端项目)部署即可。
|
139
|
+
:::
|
140
|
+
|
141
|
+
对于 Monorepo 项目,除了需要构建当前的项目外,还需要构建当前项目依赖的仓库中其他子项目。这里以一个 pnpm Monorepo 仓库为例,在 Netlify 上对 Monorepo 项目进行部署。
|
142
|
+
|
143
|
+
假设 Monorepo 仓库目录结构如下:
|
144
|
+
|
145
|
+
```
|
146
|
+
.
|
147
|
+
├── packages
|
148
|
+
│ ├── app
|
149
|
+
│ └── app-dep1
|
150
|
+
├── package.json
|
151
|
+
├── pnpm-lock.yaml
|
152
|
+
└── pnpm-workspace.yaml
|
153
|
+
```
|
154
|
+
|
155
|
+
你需要在 Netlify 平台上配置 **Base directory** 为 `packages/app`:
|
156
|
+
|
157
|
+
<img src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/lmeh7nuptpfnuhd/netlify-monorepo-basedir.png?x-resource-account=public" />
|
158
|
+
|
159
|
+
在 `packages/app/package.json` 中添加以下 script,在执行 `app` 仓库的部署命令之前,先执行 workspace 中其他仓库的构建:
|
160
|
+
|
161
|
+
```json
|
162
|
+
{
|
163
|
+
"scripts": {
|
164
|
+
"build:packages": "pnpm --filter 'app^...' run build",
|
165
|
+
"deploy": "pnpm run build:packages && modern deploy",
|
166
|
+
}
|
167
|
+
}
|
168
|
+
```
|
169
|
+
|
170
|
+
在 `netlify.toml` 配置构建命令:
|
171
|
+
|
172
|
+
```toml
|
173
|
+
[build]
|
174
|
+
publish = "dist"
|
175
|
+
command = "npm run deploy"
|
176
|
+
|
177
|
+
[functions]
|
178
|
+
directory = ".netlify/functions"
|
179
|
+
node_bundler = "none"
|
180
|
+
included_files = [".netlify/functions/**"]
|
181
|
+
```
|
182
|
+
|
183
|
+
提交你的代码,使用 Netlify 平台部署即可。
|
184
|
+
|
185
|
+
## Vercel
|
186
|
+
|
187
|
+
Vercel 是一个面向现代 Web 应用的部署平台,它提供了丰富的功能,支持部署静态网站,服务端渲染应用等。在 Vercel 上部署,通常需要配置 `vercel.json` 文件,你可以根据项目复杂度,渐进地配置该文件。
|
188
|
+
|
189
|
+
### 纯前端项目
|
190
|
+
|
191
|
+
在当前项目的根目录添加 `vercel.json` 文件:
|
192
|
+
```bash
|
193
|
+
./
|
194
|
+
├── src
|
195
|
+
├── modern.config.ts
|
196
|
+
├── vercel.json
|
197
|
+
└── package.json
|
198
|
+
```
|
199
|
+
|
200
|
+
在 `vercel.json` 中添加以下内容:
|
201
|
+
```json title="vercel.json"
|
202
|
+
{
|
203
|
+
"buildCommand": "modern deploy",
|
204
|
+
"outputDirectory": ".vercel/output"
|
205
|
+
}
|
206
|
+
```
|
207
|
+
|
208
|
+
提交你的项目到 git,在 Vercel 平台上选择 Frmeworkwork Preset 为 `Other`,部署即可。
|
209
|
+
|
210
|
+
<img src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/lmeh7nuptpfnuhd/vercel-framework-preset.png" />
|
211
|
+
|
212
|
+
### 全栈项目
|
213
|
+
|
214
|
+
全栈项目是指使用了自定义 Web Server、SSR、BFF 的项目,这些项目需要部署在 **Vercel Functions** 上。
|
215
|
+
|
216
|
+
全栈项目除了按照[纯前端项目](#纯前端项目)的方式配置 `vercel.json` 外,有两点需要注意:
|
217
|
+
|
218
|
+
1. 当前,Modern.js 还不支持在 Vercel 平台上部署 BFF 项目,我们将在后续的版本中支持。
|
219
|
+
2. Vercel 平台部署时,默认 node 运行时为 `20.x`,部署全栈项目时建议选择 `18.x`,具体原因详见[Serverless Function contains invalid runtime error](https://vercel.com/guides/serverless-function-contains-invalid-runtime-error),你可以修改 `package.json` 指定版本:
|
220
|
+
```json title="package.json"
|
221
|
+
"engines": {
|
222
|
+
"node": "18.x"
|
223
|
+
}
|
224
|
+
```
|
225
|
+
|
226
|
+
|
227
|
+
### Monorepo 项目
|
228
|
+
|
229
|
+
:::info
|
230
|
+
以下指南主要针对于全栈项目,对于纯 CSR 的项目,只需要按照[纯前端项目](#纯前端项目-1)部署即可。
|
231
|
+
:::
|
232
|
+
|
233
|
+
对于 Monorepo 项目,除了需要构建当前的项目外,还需要构建当前项目依赖的仓库中其他子项目。这里以一个 pnpm Monorepo 仓库为例,在 Vercel 上对 Monorepo 项目进行部署。
|
234
|
+
|
235
|
+
假设 Monorepo 仓库目录结构如下:
|
236
|
+
|
237
|
+
```
|
238
|
+
.
|
239
|
+
├── packages
|
240
|
+
│ ├── app
|
241
|
+
│ └── app-dep1
|
242
|
+
├── package.json
|
243
|
+
├── pnpm-lock.yaml
|
244
|
+
└── pnpm-workspace.yaml
|
245
|
+
```
|
246
|
+
|
247
|
+
首先,你需要在 Vercel 平台上配置 **Root Directory** 为 `packages/app`:
|
248
|
+
|
249
|
+
<img src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/lmeh7nuptpfnuhd/vercel-root-directory.png" />
|
250
|
+
|
251
|
+
将 Node.js 运行时设置为 `18.x`:
|
252
|
+
```json title="package.json"
|
253
|
+
"engines": {
|
254
|
+
"node": "18.x"
|
255
|
+
},
|
256
|
+
```
|
257
|
+
|
258
|
+
在 `packages/app/package.json` 中添加以下 script,在执行 `app` 仓库的部署命令之前,先执行 workspace 中其他仓库的构建:
|
259
|
+
|
260
|
+
```json
|
261
|
+
{
|
262
|
+
"scripts": {
|
263
|
+
"build:packages": "pnpm --filter 'app^...' run build",
|
264
|
+
"deploy": "pnpm run build:packages && modern deploy",
|
265
|
+
}
|
266
|
+
}
|
267
|
+
```
|
268
|
+
|
269
|
+
在 `packages/app/vercel.json` 文件中添加以下内容:
|
270
|
+
```json title="vercel.json"
|
271
|
+
{
|
272
|
+
"buildCommand": "npm run deploy",
|
273
|
+
"outputDirectory": ".vercel/output"
|
274
|
+
}
|
275
|
+
```
|
276
|
+
|
277
|
+
提交你的代码,使用 Vercel 平台部署即可。
|
278
|
+
|
279
|
+
|
280
|
+
|
281
|
+
|
package/package.json
CHANGED
@@ -15,17 +15,17 @@
|
|
15
15
|
"modern",
|
16
16
|
"modern.js"
|
17
17
|
],
|
18
|
-
"version": "2.
|
18
|
+
"version": "2.52.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.52.0"
|
26
26
|
},
|
27
27
|
"peerDependencies": {
|
28
|
-
"@modern-js/builder-doc": "^2.
|
28
|
+
"@modern-js/builder-doc": "^2.52.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.52.0",
|
43
|
+
"@modern-js/doc-plugin-auto-sidebar": "2.52.0"
|
44
44
|
},
|
45
45
|
"scripts": {
|
46
46
|
"dev": "rspress dev",
|