@modern-js/main-doc 0.0.0-nightly-20231218170633 → 0.0.0-nightly-20231219170633
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/guides/advanced-features/optimize-bundle.mdx +1 -1
- package/docs/en/guides/advanced-features/ssr/_category_.json +8 -0
- package/docs/en/guides/advanced-features/ssr/cache.mdx +186 -0
- package/docs/en/guides/advanced-features/ssr/index.mdx +22 -0
- package/docs/en/guides/advanced-features/ssr/stream.mdx +236 -0
- package/docs/en/guides/advanced-features/ssr/usage.mdx +341 -0
- package/docs/en/guides/basic-features/css.mdx +2 -13
- package/docs/en/guides/get-started/tech-stack.mdx +1 -1
- package/docs/zh/guides/advanced-features/optimize-bundle.mdx +1 -1
- package/docs/zh/guides/advanced-features/ssr/_category_.json +8 -0
- package/docs/zh/guides/advanced-features/ssr/cache.mdx +189 -0
- package/docs/zh/guides/advanced-features/ssr/index.mdx +22 -0
- package/docs/zh/guides/advanced-features/ssr/stream.mdx +240 -0
- package/docs/zh/guides/advanced-features/{ssr.mdx → ssr/usage.mdx} +7 -225
- package/docs/zh/guides/basic-features/css.mdx +2 -13
- package/docs/zh/guides/basic-features/data/data-write.mdx +1 -1
- package/docs/zh/guides/get-started/tech-stack.mdx +1 -1
- package/package.json +5 -5
@@ -0,0 +1,240 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 2
|
3
|
+
title: 流式渲染
|
4
|
+
---
|
5
|
+
|
6
|
+
# 流式渲染
|
7
|
+
|
8
|
+
## 概述
|
9
|
+
|
10
|
+
流式渲染是一种新的渲染方式,它可以在用户与页面交互时,实时地更新页面内容,从而提高用户体验。
|
11
|
+
|
12
|
+
在传统的渲染方式中,页面的渲染是一次性完成的,而在流式渲染中,页面的渲染是逐步完成的,在用户与页面交互时,逐步加载数据,而不是一次性加载所有数据。
|
13
|
+
|
14
|
+
相比传统渲染:
|
15
|
+
|
16
|
+
- 拥有更快感知速度:流式渲染可以在渲染过程中逐步显示内容能够以最快的速度显示业务首页。
|
17
|
+
- 拥有更好的用户体验:通过流式渲染,用户可以更快地看到页面上的内容,而不需要等待整个页面都渲染完成后才能交互。
|
18
|
+
- 拥有更好的性能控制:流式渲染可以让开发者更好地控制页面加载的优先级和顺序,从而更好地优化性能和用户体验。
|
19
|
+
- 更好的适应性:流式渲染可以更好地适应不同网络速度和设备性能,使得页面在各种环境下都能有更好的表现。
|
20
|
+
|
21
|
+
## 使用
|
22
|
+
|
23
|
+
Modern.js 支持了 React 18 的流式渲染,可以通过如下配置启用:
|
24
|
+
|
25
|
+
```ts title="modern.config.ts"
|
26
|
+
import { defineConfig } from '@modern-js/app-tools';
|
27
|
+
|
28
|
+
export default defineConfig({
|
29
|
+
server: {
|
30
|
+
ssr: {
|
31
|
+
mode: 'stream',
|
32
|
+
},
|
33
|
+
},
|
34
|
+
});
|
35
|
+
```
|
36
|
+
|
37
|
+
Modern.js 的流式渲染基于 React Router 实现,主要涉及 API 有:
|
38
|
+
|
39
|
+
- [`defer`](https://reactrouter.com/en/main/utils/defer):在 Data Loader 中使用,用于支持异步获取数据。
|
40
|
+
- [`Await`](https://reactrouter.com/en/main/components/await):用于渲染 Data Loader 返回的异步数据。
|
41
|
+
- [`useAsyncValue`](https://reactrouter.com/en/main/hooks/use-async-value):用于从最近的父级 `Await` 组件中获取数据。
|
42
|
+
|
43
|
+
### 异步获取数据
|
44
|
+
|
45
|
+
```ts title="page.data.ts"
|
46
|
+
import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
|
47
|
+
|
48
|
+
interface User {
|
49
|
+
name: string;
|
50
|
+
age: number;
|
51
|
+
}
|
52
|
+
|
53
|
+
export interface Data {
|
54
|
+
data: User;
|
55
|
+
}
|
56
|
+
|
57
|
+
export const loader = ({ params }: LoaderFunctionArgs) => {
|
58
|
+
const userId = params.id;
|
59
|
+
|
60
|
+
const user = new Promise<User>(resolve => {
|
61
|
+
setTimeout(() => {
|
62
|
+
resolve({
|
63
|
+
name: `user-${userId}`,
|
64
|
+
age: 18,
|
65
|
+
});
|
66
|
+
}, 200);
|
67
|
+
});
|
68
|
+
|
69
|
+
return defer({ data: user });
|
70
|
+
};
|
71
|
+
```
|
72
|
+
|
73
|
+
`user` 是一个 Promise 类型的对象,表示需要异步获取的数据,通过 `defer` 处理需要异步获取的 `user`。注意,`defer` 必须接收一个对象类型的参数,
|
74
|
+
因此, 传入 `defer` 的参数为:`{ data: user }`
|
75
|
+
|
76
|
+
`defer` 还可以同时接收异步数据和同步数据。例如:
|
77
|
+
|
78
|
+
```ts title="page.data.ts"
|
79
|
+
// 省略部分代码
|
80
|
+
|
81
|
+
export const loader = ({ params }: LoaderFunctionArgs) => {
|
82
|
+
const userId = params.id;
|
83
|
+
|
84
|
+
const user = new Promise<User>(resolve => {
|
85
|
+
setTimeout(() => {
|
86
|
+
resolve({
|
87
|
+
name: `user-${userId}`,
|
88
|
+
age: 18,
|
89
|
+
});
|
90
|
+
}, 200);
|
91
|
+
});
|
92
|
+
|
93
|
+
const otherData = new Promise<string>(resolve => {
|
94
|
+
setTimeout(() => {
|
95
|
+
resolve('some sync data');
|
96
|
+
}, 200);
|
97
|
+
});
|
98
|
+
|
99
|
+
return defer({
|
100
|
+
data: user,
|
101
|
+
other: await otherData,
|
102
|
+
});
|
103
|
+
};
|
104
|
+
```
|
105
|
+
|
106
|
+
`otherData` 前加了 `await`,所以是同步获取的数据,它可以和异步获取的数据 `user` 同时传入 `defer`。
|
107
|
+
|
108
|
+
### 渲染异步数据
|
109
|
+
|
110
|
+
通过 `Await` 组件,可以获取到 Data Loader 中异步返回的数据,然后进行渲染。例如:
|
111
|
+
|
112
|
+
```tsx title="page.tsx"
|
113
|
+
import { Await, useLoaderData } from '@modern-js/runtime/router';
|
114
|
+
import { Suspense } from 'react';
|
115
|
+
import type { Data } from './page.data';
|
116
|
+
|
117
|
+
const Page = () => {
|
118
|
+
const data = useLoaderData() as Data;
|
119
|
+
|
120
|
+
return (
|
121
|
+
<div>
|
122
|
+
User info:
|
123
|
+
<Suspense fallback={<div id="loading">loading user data ...</div>}>
|
124
|
+
<Await resolve={data.data}>
|
125
|
+
{user => {
|
126
|
+
return (
|
127
|
+
<div id="data">
|
128
|
+
name: {user.name}, age: {user.age}
|
129
|
+
</div>
|
130
|
+
);
|
131
|
+
}}
|
132
|
+
</Await>
|
133
|
+
</Suspense>
|
134
|
+
</div>
|
135
|
+
);
|
136
|
+
};
|
137
|
+
|
138
|
+
export default Page;
|
139
|
+
```
|
140
|
+
|
141
|
+
`Await` 需要包裹在 `Suspense` 组件内部,`Await` 的 `resolve` 传入的是 Data Loader 异步获取的数据,当数据获取完成后,
|
142
|
+
通过 [Render Props](https://zh-hans.react.dev/reference/react/cloneElement#passing-data-with-a-render-prop) 模式,渲染获取到的数据。在数据的获取阶段,将展示
|
143
|
+
`Suspense` 组件 `fallback` 属性设置的内容。
|
144
|
+
|
145
|
+
:::warning 注意
|
146
|
+
从 Data Loader 文件导入类型时,需要使用 import type 语法,保证只导入类型信息,这样可以避免 Data Loader 的代码打包到前端产物的 bundle 文件中。
|
147
|
+
|
148
|
+
所以,这里的导入方式为:`import type { Data } from './page.data'`;
|
149
|
+
|
150
|
+
:::
|
151
|
+
|
152
|
+
也可以通过 `useAsyncValue` 获取 Data Loader 返回的异步数据。例如:
|
153
|
+
|
154
|
+
```tsx title='page.tsx'
|
155
|
+
import { useAsyncValue } from '@modern-js/runtime/router';
|
156
|
+
|
157
|
+
// 省略部分代码
|
158
|
+
|
159
|
+
const UserInfo = () => {
|
160
|
+
const user = useAsyncValue();
|
161
|
+
|
162
|
+
return (
|
163
|
+
<div>
|
164
|
+
name: {user.name}, age: {user.age}
|
165
|
+
</div>
|
166
|
+
);
|
167
|
+
};
|
168
|
+
|
169
|
+
const Page = () => {
|
170
|
+
const data = useLoaderData() as Data;
|
171
|
+
|
172
|
+
return (
|
173
|
+
<div>
|
174
|
+
User info:
|
175
|
+
<Suspense fallback={<div id="loading">loading user data ...</div>}>
|
176
|
+
<Await resolve={data.data}>
|
177
|
+
<UserInfo />
|
178
|
+
</Await>
|
179
|
+
</Suspense>
|
180
|
+
</div>
|
181
|
+
);
|
182
|
+
};
|
183
|
+
|
184
|
+
export default Page;
|
185
|
+
```
|
186
|
+
|
187
|
+
### 错误处理
|
188
|
+
|
189
|
+
`Await` 组件的 `errorElement` 属性,可以用来处理当 Data Loader 执行时,或者子组件渲染时抛出的错误。
|
190
|
+
例如,我们故意在 Data Loader 函数中抛出错误:
|
191
|
+
|
192
|
+
```ts title="page.loader.ts"
|
193
|
+
import { defer } from '@modern-js/runtime/router';
|
194
|
+
|
195
|
+
export default () => {
|
196
|
+
const data = new Promise((resolve, reject) => {
|
197
|
+
setTimeout(() => {
|
198
|
+
reject(new Error('error occurs'));
|
199
|
+
}, 200);
|
200
|
+
});
|
201
|
+
|
202
|
+
return defer({ data });
|
203
|
+
};
|
204
|
+
```
|
205
|
+
|
206
|
+
然后通过 `useAsyncError` 获取错误,并将用于渲染错误信息的组件赋值给 `Await` 组件的 `errorElement` 属性:
|
207
|
+
|
208
|
+
```tsx title="page.ts"
|
209
|
+
import { Await, useAsyncError, useLoaderData } from '@modern-js/runtime/router';
|
210
|
+
import { Suspense } from 'react';
|
211
|
+
|
212
|
+
export default function Page() {
|
213
|
+
const data = useLoaderData();
|
214
|
+
|
215
|
+
return (
|
216
|
+
<div>
|
217
|
+
Error page
|
218
|
+
<Suspense fallback={<div>loading ...</div>}>
|
219
|
+
<Await resolve={data.data} errorElement={<ErrorElement />}>
|
220
|
+
{(data: any) => {
|
221
|
+
return <div>never displayed</div>;
|
222
|
+
}}
|
223
|
+
</Await>
|
224
|
+
</Suspense>
|
225
|
+
</div>
|
226
|
+
);
|
227
|
+
}
|
228
|
+
|
229
|
+
function ErrorElement() {
|
230
|
+
const error = useAsyncError() as Error;
|
231
|
+
return <p>Something went wrong! {error.message}</p>;
|
232
|
+
}
|
233
|
+
```
|
234
|
+
|
235
|
+
:::info 补充信息
|
236
|
+
|
237
|
+
1. [Deferred Data](https://reactrouter.com/en/main/guides/deferred)
|
238
|
+
2. [New Suspense SSR Architecture in React 18](https://github.com/reactwg/react-18/discussions/37)
|
239
|
+
|
240
|
+
:::
|
@@ -1,10 +1,9 @@
|
|
1
1
|
---
|
2
|
-
sidebar_position:
|
2
|
+
sidebar_position: 1
|
3
|
+
title: 基础使用
|
3
4
|
---
|
4
5
|
|
5
|
-
#
|
6
|
-
|
7
|
-
在 Modern.js 中,SSR 也是开箱即用的。开发者无需为 SSR 编写复杂的服务端逻辑,也无需关心 SSR 的运维,或是创建单独的服务。Modern.js 拥有完备的 SSR 降级策略,保证页面能够安全运行。
|
6
|
+
# 基础使用
|
8
7
|
|
9
8
|
启用 SSR 非常简单,只需要设置 [`server.ssr`](/configure/app/server/ssr) 为 `true` 即可:
|
10
9
|
|
@@ -139,6 +138,10 @@ CSR 中这类问题不易被发觉,因此从 CSR 切换到 SSR 时,如果不
|
|
139
138
|
|
140
139
|
## Serverless Pre-render
|
141
140
|
|
141
|
+
:::warning
|
142
|
+
x.43.0+ 已废弃,请使用 [SSR Cache](guides/advanced-features/ssr/cache) 替代
|
143
|
+
:::
|
144
|
+
|
142
145
|
Modern.js 提供 Serverless Pre-rendering (SPR) 这一特性来提升 SSR 性能。
|
143
146
|
|
144
147
|
SPR 利用预渲染与缓存技术,为 SSR 页面提供静态 Web 的响应性能。它让 SSR 应用拥有静态 Web 页面的响应速度与稳定性,同时还能保持数据的动态更新。
|
@@ -324,224 +327,3 @@ export const loader = () => {
|
|
324
327
|
需要注意的是,此时获取到的是 HTML 请求的请求头,不一定适用于接口请求,因此**千万不能**透传所有请求头。并且,一些后端接口,或是通用网关,会根据请求头中的信息做校验,全量透传容易出现各种难以排查的问题,推荐**按需透传**。
|
325
328
|
|
326
329
|
如果实在需要透传所有请求头,请务必过滤 `host` 字段。
|
327
|
-
|
328
|
-
## 流式渲染
|
329
|
-
|
330
|
-
Modern.js 支持了 React 18 的流式渲染,可以通过如下配置启用:
|
331
|
-
|
332
|
-
```ts title="modern.config.ts"
|
333
|
-
import { defineConfig } from '@modern-js/app-tools';
|
334
|
-
|
335
|
-
export default defineConfig({
|
336
|
-
server: {
|
337
|
-
ssr: {
|
338
|
-
mode: 'stream',
|
339
|
-
},
|
340
|
-
},
|
341
|
-
});
|
342
|
-
```
|
343
|
-
|
344
|
-
Modern.js 的流式渲染基于 React Router 实现,主要涉及 API 有:
|
345
|
-
|
346
|
-
- [`defer`](https://reactrouter.com/en/main/utils/defer):在 Data Loader 中使用,用于支持异步获取数据。
|
347
|
-
- [`Await`](https://reactrouter.com/en/main/components/await):用于渲染 Data Loader 返回的异步数据。
|
348
|
-
- [`useAsyncValue`](https://reactrouter.com/en/main/hooks/use-async-value):用于从最近的父级 `Await` 组件中获取数据。
|
349
|
-
|
350
|
-
### 异步获取数据
|
351
|
-
|
352
|
-
```ts title="page.data.ts"
|
353
|
-
import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
|
354
|
-
|
355
|
-
interface User {
|
356
|
-
name: string;
|
357
|
-
age: number;
|
358
|
-
}
|
359
|
-
|
360
|
-
export interface Data {
|
361
|
-
data: User;
|
362
|
-
}
|
363
|
-
|
364
|
-
export const loader = ({ params }: LoaderFunctionArgs) => {
|
365
|
-
const userId = params.id;
|
366
|
-
|
367
|
-
const user = new Promise<User>(resolve => {
|
368
|
-
setTimeout(() => {
|
369
|
-
resolve({
|
370
|
-
name: `user-${userId}`,
|
371
|
-
age: 18,
|
372
|
-
});
|
373
|
-
}, 200);
|
374
|
-
});
|
375
|
-
|
376
|
-
return defer({ data: user });
|
377
|
-
};
|
378
|
-
```
|
379
|
-
|
380
|
-
`user` 是一个 Promise 类型的对象,表示需要异步获取的数据,通过 `defer` 处理需要异步获取的 `user`。注意,`defer` 必须接收一个对象类型的参数,
|
381
|
-
因此, 传入 `defer` 的参数为:`{ data: user }`
|
382
|
-
|
383
|
-
`defer` 还可以同时接收异步数据和同步数据。例如:
|
384
|
-
|
385
|
-
```ts title="page.data.ts"
|
386
|
-
// 省略部分代码
|
387
|
-
|
388
|
-
export const loader = ({ params }: LoaderFunctionArgs) => {
|
389
|
-
const userId = params.id;
|
390
|
-
|
391
|
-
const user = new Promise<User>(resolve => {
|
392
|
-
setTimeout(() => {
|
393
|
-
resolve({
|
394
|
-
name: `user-${userId}`,
|
395
|
-
age: 18,
|
396
|
-
});
|
397
|
-
}, 200);
|
398
|
-
});
|
399
|
-
|
400
|
-
const otherData = new Promise<string>(resolve => {
|
401
|
-
setTimeout(() => {
|
402
|
-
resolve('some sync data');
|
403
|
-
}, 200);
|
404
|
-
});
|
405
|
-
|
406
|
-
return defer({
|
407
|
-
data: user,
|
408
|
-
other: await otherData,
|
409
|
-
});
|
410
|
-
};
|
411
|
-
```
|
412
|
-
|
413
|
-
`otherData` 前加了 `await`,所以是同步获取的数据,它可以和异步获取的数据 `user` 同时传入 `defer`。
|
414
|
-
|
415
|
-
### 渲染异步数据
|
416
|
-
|
417
|
-
通过 `Await` 组件,可以获取到 Data Loader 中异步返回的数据,然后进行渲染。例如:
|
418
|
-
|
419
|
-
```tsx title="page.tsx"
|
420
|
-
import { Await, useLoaderData } from '@modern-js/runtime/router';
|
421
|
-
import { Suspense } from 'react';
|
422
|
-
import type { Data } from './page.data';
|
423
|
-
|
424
|
-
const Page = () => {
|
425
|
-
const data = useLoaderData() as Data;
|
426
|
-
|
427
|
-
return (
|
428
|
-
<div>
|
429
|
-
User info:
|
430
|
-
<Suspense fallback={<div id="loading">loading user data ...</div>}>
|
431
|
-
<Await resolve={data.data}>
|
432
|
-
{user => {
|
433
|
-
return (
|
434
|
-
<div id="data">
|
435
|
-
name: {user.name}, age: {user.age}
|
436
|
-
</div>
|
437
|
-
);
|
438
|
-
}}
|
439
|
-
</Await>
|
440
|
-
</Suspense>
|
441
|
-
</div>
|
442
|
-
);
|
443
|
-
};
|
444
|
-
|
445
|
-
export default Page;
|
446
|
-
```
|
447
|
-
|
448
|
-
`Await` 需要包裹在 `Suspense` 组件内部,`Await` 的 `resolve` 传入的是 Data Loader 异步获取的数据,当数据获取完成后,
|
449
|
-
通过 [Render Props](https://zh-hans.react.dev/reference/react/cloneElement#passing-data-with-a-render-prop) 模式,渲染获取到的数据。在数据的获取阶段,将展示
|
450
|
-
`Suspense` 组件 `fallback` 属性设置的内容。
|
451
|
-
|
452
|
-
:::warning 注意
|
453
|
-
从 Data Loader 文件导入类型时,需要使用 import type 语法,保证只导入类型信息,这样可以避免 Data Loader 的代码打包到前端产物的 bundle 文件中。
|
454
|
-
|
455
|
-
所以,这里的导入方式为:`import type { Data } from './page.data'`;
|
456
|
-
|
457
|
-
:::
|
458
|
-
|
459
|
-
也可以通过 `useAsyncValue` 获取 Data Loader 返回的异步数据。例如:
|
460
|
-
|
461
|
-
```tsx title='page.tsx'
|
462
|
-
import { useAsyncValue } from '@modern-js/runtime/router';
|
463
|
-
|
464
|
-
// 省略部分代码
|
465
|
-
|
466
|
-
const UserInfo = () => {
|
467
|
-
const user = useAsyncValue();
|
468
|
-
|
469
|
-
return (
|
470
|
-
<div>
|
471
|
-
name: {user.name}, age: {user.age}
|
472
|
-
</div>
|
473
|
-
);
|
474
|
-
};
|
475
|
-
|
476
|
-
const Page = () => {
|
477
|
-
const data = useLoaderData() as Data;
|
478
|
-
|
479
|
-
return (
|
480
|
-
<div>
|
481
|
-
User info:
|
482
|
-
<Suspense fallback={<div id="loading">loading user data ...</div>}>
|
483
|
-
<Await resolve={data.data}>
|
484
|
-
<UserInfo />
|
485
|
-
</Await>
|
486
|
-
</Suspense>
|
487
|
-
</div>
|
488
|
-
);
|
489
|
-
};
|
490
|
-
|
491
|
-
export default Page;
|
492
|
-
```
|
493
|
-
|
494
|
-
### 错误处理
|
495
|
-
|
496
|
-
`Await` 组件的 `errorElement` 属性,可以用来处理当 Data Loader 执行时,或者子组件渲染时抛出的错误。
|
497
|
-
例如,我们故意在 Data Loader 函数中抛出错误:
|
498
|
-
|
499
|
-
```ts title="page.loader.ts"
|
500
|
-
import { defer } from '@modern-js/runtime/router';
|
501
|
-
|
502
|
-
export default () => {
|
503
|
-
const data = new Promise((resolve, reject) => {
|
504
|
-
setTimeout(() => {
|
505
|
-
reject(new Error('error occurs'));
|
506
|
-
}, 200);
|
507
|
-
});
|
508
|
-
|
509
|
-
return defer({ data });
|
510
|
-
};
|
511
|
-
```
|
512
|
-
|
513
|
-
然后通过 `useAsyncError` 获取错误,并将用于渲染错误信息的组件赋值给 `Await` 组件的 `errorElement` 属性:
|
514
|
-
|
515
|
-
```tsx title="page.ts"
|
516
|
-
import { Await, useAsyncError, useLoaderData } from '@modern-js/runtime/router';
|
517
|
-
import { Suspense } from 'react';
|
518
|
-
|
519
|
-
export default function Page() {
|
520
|
-
const data = useLoaderData();
|
521
|
-
|
522
|
-
return (
|
523
|
-
<div>
|
524
|
-
Error page
|
525
|
-
<Suspense fallback={<div>loading ...</div>}>
|
526
|
-
<Await resolve={data.data} errorElement={<ErrorElement />}>
|
527
|
-
{(data: any) => {
|
528
|
-
return <div>never displayed</div>;
|
529
|
-
}}
|
530
|
-
</Await>
|
531
|
-
</Suspense>
|
532
|
-
</div>
|
533
|
-
);
|
534
|
-
}
|
535
|
-
|
536
|
-
function ErrorElement() {
|
537
|
-
const error = useAsyncError() as Error;
|
538
|
-
return <p>Something went wrong! {error.message}</p>;
|
539
|
-
}
|
540
|
-
```
|
541
|
-
|
542
|
-
:::info 补充信息
|
543
|
-
|
544
|
-
1. [Deferred Data](https://reactrouter.com/en/main/guides/deferred)
|
545
|
-
2. [New Suspense SSR Architecture in React 18](https://github.com/reactwg/react-18/discussions/37)
|
546
|
-
|
547
|
-
:::
|
@@ -22,7 +22,7 @@ Modern.js 内置了 [PostCSS](https://postcss.org/) 来转换 CSS 代码。
|
|
22
22
|
|
23
23
|
## 使用 CSS Modules
|
24
24
|
|
25
|
-
请阅读 [使用 CSS Modules](
|
25
|
+
请阅读 [使用 CSS Modules](/guides/basic-features/css-modules) 章节来了解 CSS Modules 的完整用法。
|
26
26
|
|
27
27
|
## 使用 CSS-in-JS
|
28
28
|
|
@@ -72,18 +72,7 @@ Modern.js 内部集成了 Babel 的 [babel-plugin-styled-components](https://git
|
|
72
72
|
? 请选择功能名称 启用 「Tailwind CSS」 支持
|
73
73
|
```
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
```json title="./package.json"
|
78
|
-
{
|
79
|
-
"dependencies": {
|
80
|
-
"tailwindcss": "^3.0.0"
|
81
|
-
},
|
82
|
-
"devDependencies": {
|
83
|
-
"@modern-js/plugin-tailwindcss": "^2.0.0"
|
84
|
-
}
|
85
|
-
}
|
86
|
-
```
|
75
|
+
成功开启后,你会看到 `package.json` 中新增了 `tailwindcss` 和 `@modern-js/plugin-tailwindcss` 依赖。
|
87
76
|
|
88
77
|
2. 在 `modern.config.ts` 中注册 Tailwind 插件:
|
89
78
|
|
@@ -84,7 +84,7 @@ Modern.js 中提供 Data Action 主要是为了使 UI 和服务器的状态能
|
|
84
84
|

|
85
85
|
|
86
86
|
如果项目中组件共享的数据主要服务端的状态,则无需在项目引入客户端状态管理库,使用 Data Loader 请求数据,通过 [`useRouteLoaderData`](/guides/basic-features/data/data-fetch.md) 在子组件中共享数据,
|
87
|
-
通过 Data
|
87
|
+
通过 Data Action 修改和同步服务端的状态。
|
88
88
|
|
89
89
|
|
90
90
|
|
@@ -97,7 +97,7 @@ Modern.js 支持 [Sass](https://sass-lang.com/)、[Less](https://lesscss.org/)
|
|
97
97
|
|
98
98
|
Modern.js 对 [CSS Modules](https://github.com/css-modules/css-modules) 提供了开箱即用的支持,内部基于 [css-loader](https://www.npmjs.com/package/css-loader) 实现。
|
99
99
|
|
100
|
-
请参考[「使用 CSS Modules」](
|
100
|
+
请参考[「使用 CSS Modules」](/guides/basic-features/css-modules) 来使用。
|
101
101
|
|
102
102
|
---
|
103
103
|
|
package/package.json
CHANGED
@@ -15,17 +15,17 @@
|
|
15
15
|
"modern",
|
16
16
|
"modern.js"
|
17
17
|
],
|
18
|
-
"version": "0.0.0-nightly-
|
18
|
+
"version": "0.0.0-nightly-20231219170633",
|
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": "0.0.0-nightly-
|
25
|
+
"@modern-js/sandpack-react": "0.0.0-nightly-20231219170633"
|
26
26
|
},
|
27
27
|
"peerDependencies": {
|
28
|
-
"@modern-js/builder-doc": "0.0.0-nightly-
|
28
|
+
"@modern-js/builder-doc": "0.0.0-nightly-20231219170633"
|
29
29
|
},
|
30
30
|
"devDependencies": {
|
31
31
|
"classnames": "^2",
|
@@ -39,8 +39,8 @@
|
|
39
39
|
"@rspress/shared": "1.8.3",
|
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": "0.0.0-nightly-20231219170633",
|
43
|
+
"@modern-js/doc-plugin-auto-sidebar": "0.0.0-nightly-20231219170633"
|
44
44
|
},
|
45
45
|
"scripts": {
|
46
46
|
"dev": "rspress dev",
|