@modern-js/main-doc 2.6.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
1
 
2
- > @modern-js/main-doc@2.6.0 build /github/workspace/packages/toolkit/main-doc
2
+ > @modern-js/main-doc@2.7.0 build /github/workspace/packages/toolkit/main-doc
3
3
  > npx ts-node ./scripts/sync.ts
4
4
 
@@ -26,6 +26,16 @@ If the file ends with `.min.js`, it will not compression.
26
26
 
27
27
  ## More Usage
28
28
 
29
+ In React components, this prefix can be added via [built-in environment variables](/guides/basic-features/env-vars.html#asset_prefix):
30
+
31
+ ```tsx
32
+ export default () => {
33
+ return (
34
+ <img src={`${process.env.ASSET_PREFIX}/upload/banner.png`}></img>
35
+ );
36
+ };
37
+ ```
38
+
29
39
  Whether in [custom HTML](/guides/basic-features/html), or in any HTML file under ['config/public/'](/apis/app/hooks/config/public), you can directly use the HTML tag to refer to the resources in the `config/upload/`:
30
40
 
31
41
  ```html
@@ -9,6 +9,8 @@ sidebar_label: ssr
9
9
 
10
10
  Enalbe SSR configuration.
11
11
 
12
+ ### Boolean Type
13
+
12
14
  When the value type is `boolean`, it indicates whether to enable SSR deployment mode, and `false` is not enabled by default.
13
15
 
14
16
  ```ts title="modern.config.ts"
@@ -18,3 +20,19 @@ export default defineConfig({
18
20
  },
19
21
  });
20
22
  ```
23
+
24
+ ### Object Type
25
+
26
+ When the value type is `Object`, The following properties can be configured:
27
+
28
+ - `mode`:`string = 'string'`, use `renderToString` rendering default. onfigure 'stream' to enable streaming rendering.
29
+ - `forceCSR`:`boolean = false`, forced CSR rendering is disable by default. When configured as `true`, add `?csr=true` in URL to force CSR.
30
+
31
+ ```ts title="modern.config.ts"
32
+ export default defineConfig({
33
+ server: {
34
+ forceCSR: true,
35
+ mode: 'stream',
36
+ },
37
+ });
38
+ ```
@@ -44,8 +44,9 @@ And it provides elegant degradation processing. Once the SSR request fails, it w
44
44
  However, developers still need to pay attention to the fallback of data, such as `null` values or data returns that do not as expect. Avoid React rendering errors or messy rendering results when SSR.
45
45
 
46
46
  :::info
47
- When using Data Loader, data fetching happens before rendering, Modern.js still supports fetching data when the component is rendered. See [Data Fetch](/guides/basic-features/data-fetch).
47
+ 1. When you request the page on client-side page transitions, Modern.js sends an API request to the server, which runs Data Loader function.
48
48
 
49
+ 2. When using Data Loader, data fetching happens before rendering, Modern.js still supports fetching data when the component is rendered. See [Data Fetch](/guides/basic-features/data-fetch).
49
50
  :::
50
51
 
51
52
  ## Keep Rendering Consistent
@@ -288,9 +289,9 @@ In addition, some backend interfaces, or general gateways, will verify according
288
289
 
289
290
  Be sure to filter the `host` field if you really need to pass through all request headers.
290
291
 
291
- ## Stream SSR
292
+ ## Streaming SSR
292
293
 
293
- Modern.js supports streaming rendering in React 18, the default rendering mode can be modified with the following configuration:
294
+ Modern.js supports streaming rendering in React 18. Opt in it with the following configuration:
294
295
 
295
296
  ```json
296
297
  {
@@ -302,7 +303,211 @@ Modern.js supports streaming rendering in React 18, the default rendering mode c
302
303
  }
303
304
  ```
304
305
 
305
- :::note
306
- At present Modern.js built-in data fetch does not support streaming rendering. If app need it, developers can build it according to the demo of React Stream SSR.
306
+ The streaming SSR of Modern.js is implemented based on React Router, and the main APIs involved are:
307
+
308
+ - [`defer`](https://reactrouter.com/en/main/utils/defer): This utility allows you to defer values returned from loaders by passing promises instead of resolved values.
309
+ - [`Await`](https://reactrouter.com/en/main/components/await): Used to render deferred values with automatic error handling.
310
+ - [`useAsyncValue`](https://reactrouter.com/en/main/hooks/use-async-value):Returns the resolved data from the nearest `<Await>` ancestor component.
311
+
312
+
313
+ ### Return async data
314
+
315
+ ```ts title='page.loader.ts'
316
+ import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
317
+
318
+ interface User {
319
+ name: string;
320
+ age: number;
321
+ }
322
+
323
+ export interface Data {
324
+ data: User;
325
+ }
326
+
327
+ export default ({ params }: LoaderFunctionArgs) => {
328
+ const userId = params.id;
329
+
330
+ const user = new Promise<User>(resolve => {
331
+ setTimeout(() => {
332
+ resolve({
333
+ name: `user-${userId}`,
334
+ age: 18,
335
+ });
336
+ }, 200);
337
+ });
338
+
339
+ return defer({ data: user });
340
+ };
341
+
342
+ ```
343
+
344
+ `user` is of `Promise` type, which means the data will be obtained asynchronously. Note that `defer` must accept an object type parameter,
345
+ therefore, the parameter passed to `defer` is `{data: user}`.
346
+
347
+ `defer` can also receive asynchronous data and synchronous data at the same time. For example:
348
+
349
+ ```ts title='page.loader.ts'
350
+
351
+ // skip some codes
352
+
353
+ export default ({ params }: LoaderFunctionArgs) => {
354
+ const userId = params.id;
355
+
356
+ const user = new Promise<User>(resolve => {
357
+ setTimeout(() => {
358
+ resolve({
359
+ name: `user-${userId}`,
360
+ age: 18,
361
+ });
362
+ }, 200);
363
+ });
364
+
365
+ const otherData = new Promise<string>(resolve => {
366
+ setTimeout(() => {
367
+ resolve('some sync data');
368
+ }, 200);
369
+ });
370
+
371
+ return defer({
372
+ data: user,
373
+ other: await otherData
374
+ });
375
+ };
376
+
377
+ ```
378
+
379
+ `await` is added before `otherData`, so the data is obtained synchronously. It can be passed to `defer` with the data `user` at the same time.
380
+
381
+
382
+ ### Render async data
383
+
384
+ Use the `Await` component to render the data returned asynchronously from the Data Loader. For example:
385
+
386
+ ```ts title='page.tsx'
387
+ import { Await, useLoaderData } from '@modern-js/runtime/router';
388
+ import { Suspense } from 'react';
389
+ import type { Data } from './page.loader';
390
+
391
+ const Page = () => {
392
+ const data = useLoaderData() as Data;
393
+
394
+ return (
395
+ <div>
396
+ User info:
397
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
398
+ <Await resolve={data.data}>
399
+ {(user) => {
400
+ return (
401
+ <div id="data">
402
+ name: {user.name}, age: {user.age}
403
+ </div>
404
+ );
405
+ }}
406
+ </Await>
407
+ </Suspense>
408
+ </div>
409
+ );
410
+ };
411
+
412
+ export default Page;
413
+ ```
414
+
415
+ `Await` needs to be wrapped inside the `Suspense` component. The `resolve` of `Await` passes in the data acquired asynchronously by the Data Loader. When the data acquisition is completed,
416
+ the obtained data is rendered through the [Render Props](https://reactjs.org/docs/render-props.html) mode. When the data acquisition is in pending status, the
417
+ content set by the `fallback` property of the `Suspense` component will display.
418
+
419
+
420
+ :::warning Warning
421
+ When importing a type from a Data Loader file, you need to use the `import type` syntax to ensure that only type information is imported, which can prevent the Data Loader code from being packaged into the client bundle.
422
+
423
+ So, here we import like this: `import type { Data } from './page.loader'`;
424
+ :::
425
+
426
+ You can also get the asynchronous data returned by Data Loader through `useAsyncValue`. For example:
427
+
428
+ ```
429
+ ```ts title='page.tsx'
430
+ import { useAsyncValue } from '@modern-js/runtime/router';
431
+
432
+ // skip some codes
433
+
434
+ const UserInfo = () => {
435
+ const user = useAsyncValue();
436
+
437
+ return (
438
+ <div>
439
+ name: {user.name}, age: {user.age}
440
+ </div>
441
+ )
442
+ }
443
+
444
+ const Page = () => {
445
+ const data = useLoaderData() as Data;
446
+
447
+ return (
448
+ <div>
449
+ User info:
450
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
451
+ <Await resolve={data.data}>
452
+ <UserInfo />
453
+ </Await>
454
+ </Suspense>
455
+ </div>
456
+ );
457
+ };
458
+
459
+ export default Page;
460
+ ```
461
+
462
+ ### Error handling
463
+
464
+ The `errorElement` property of the `Await` component can be used to handle errors thrown when the Data Loader executes or when a child component renders.
465
+ For example, we intentionally throw an error in the Data Loader function:
466
+
467
+ ```ts title='page.loader.ts'
468
+ import { defer } from '@modern-js/runtime/router';
469
+
470
+ export default () => {
471
+ const data = new Promise((resolve, reject) => {
472
+ setTimeout(() => {
473
+ reject(new Error('error occurs'));
474
+ }, 200);
475
+ });
476
+
477
+ return defer({ data });
478
+ };
479
+ ```
480
+
481
+ Then use `useAsyncError` to get the error, and assign the component used to render the error to the `errorElement` property of the `Await` component:
482
+
483
+ ```ts title='page.ts'
484
+ import { Await, useAsyncError, useLoaderData } from '@modern-js/runtime/router';
485
+ import { Suspense } from 'react';
486
+
487
+ export default function Page() {
488
+ const data = useLoaderData();
489
+
490
+ return (
491
+ <div>
492
+ Error page
493
+ <Suspense fallback={<div>loading ...</div>}>
494
+ <Await resolve={data.data} errorElement={<ErrorElement />}>
495
+ {(data: any) => {
496
+ return <div>never displayed</div>;
497
+ }}
498
+ </Await>
499
+ </Suspense>
500
+ </div>
501
+ );
502
+ }
503
+
504
+ function ErrorElement() {
505
+ const error = useAsyncError() as Error;
506
+ return <p>Something went wrong! {error.message}</p>;
507
+ }
508
+ ```
307
509
 
510
+ :::info More
511
+ 1. [Deferred Data](https://reactrouter.com/en/main/guides/deferred)
512
+ 2. [New Suspense SSR Architecture in React 18](https://github.com/reactwg/react-18/discussions/37)
308
513
  :::
@@ -2,7 +2,64 @@
2
2
  sidebar_position: 2
3
3
  ---
4
4
 
5
- # Tailwind CSS
5
+ # CSS Solutions
6
+
7
+ Modern.js has built-in multiple CSS solutions, including Less / Sass / Stylus preprocessor, PostCSS, CSS Modules, CSS-in-JS and Tailwind CSS.
8
+
9
+ ## Using Less, Sass and Stylus
10
+
11
+ Modern.js has built-in community popular CSS preprocessors such as Less, Sass.
12
+
13
+ By default, you don't need to configure anything for Less and Sass. If you need to customize loader config, you can configure [tools.less](/configure/app/tools/less), [tools.sass](/configure/app/tools/sass) to set it up.
14
+
15
+ You can also use Stylus in Modern.js, just install the Stylus plugin provided by Modern.js Builder, please refer to [Stylus Plugin](https://modernjs.dev/builder/en/plugins/plugin-stylus.html) for usage.
16
+
17
+ ## Using PostCSS
18
+
19
+ Modern.js has built-in [PostCSS](https://postcss.org/) to transform the CSS code.
20
+
21
+ Please refer to [Modern.js Builder - Using PostCSS](https://modernjs.dev/builder/en/guide/basic/css-usage.html#using-postcss) for detailed usage.
22
+
23
+ ## Using CSS Modules
24
+
25
+ Please read the [Using CSS Modules](https://modernjs.dev/builder/en/guide/basic/css-modules.html) chapter for a complete usage of CSS Modules.
26
+
27
+ ## Using CSS-in-JS
28
+
29
+ CSS-in-JS is a technology that can write CSS styles in JS files.
30
+
31
+ Modern.js integrates the CSS-in-JS library [styled-components](https://styled-components.com/) commonly used in the community, which uses the new feature of JavaScript [Tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) to write CSS styles for components. You can use the [styled-components](https://styled-components.com/) API directly from `@modern-js/runtime/styled`.
32
+
33
+ When you need to write a `div` component with an internal font in red, you can do the following implementation:
34
+
35
+ ```js
36
+ import styled from '@modern-js/runtime/styled';
37
+
38
+ const RedDiv = styled.div`
39
+ color: red;
40
+ `;
41
+ ```
42
+
43
+ When you need to dynamically set the component style according to the `props` of the component, for example, when the attribute `primary` of `props` is `true`, the color of the button is white, and otherwise it is red. The implementation code is as follows:
44
+
45
+ ```js
46
+ import styled from '@modern-js/runtime/styled';
47
+
48
+ const Button = styled.button`
49
+ color: ${props => (props.primary ? 'white' : 'red')};
50
+ font-size: 1em;
51
+ `;
52
+ ```
53
+
54
+ For more usage of styled-components, please refer to [[styled-components official website](https://styled-components.com/) ].
55
+
56
+ Modern.js uses the Babel plugin [babel-plugin-styled-components](https://github.com/styled-components/babel-plugin-styled-components) internally, and the plugin can be configured through [tools.styledComponents](/configure/app/tools/styled-components).
57
+
58
+ :::tip
59
+ If you need to use [styled-jsx](https://www.npmjs.com/package/styled-jsx), [Emotion](https://emotion.sh/) and other CSS-in-JS libraries, you need to install the dependency of the corresponding library first. For specific usage, please refer to the official website of the corresponding library.
60
+ :::
61
+
62
+ ## Using Tailwind CSS
6
63
 
7
64
  [Tailwind CSS](https://tailwindcss.com/) is a CSS framework and design system based on Utility Class, which can quickly add common styles to components, and support flexible extension of theme styles. To use [Tailwind CSS](https://tailwindcss.com/) in the Modern.js, just execute `pnpm run new` in the project root directory and turn it on.
8
65
 
@@ -36,7 +93,7 @@ According to different needs, you can optionally import the CSS files provided b
36
93
 
37
94
  :::
38
95
 
39
- ## Tailwind CSS version
96
+ ### Tailwind CSS version
40
97
 
41
98
  Modern.js supports both Tailwind CSS v2 and v3. The framework will recognize the version of `tailwindcss` in the project `package.json` and apply the corresponding configuration. By default, we install Tailwind CSS v3 for you.
42
99
 
@@ -54,7 +111,7 @@ Both Tailwind CSS v2 and v3 do not support IE 11 browsers. For background, pleas
54
111
 
55
112
  If you use Tailwind CSS on IE 11 browser, some styles may not be available, please pay attention.
56
113
 
57
- ## Theme config
114
+ ### Theme config
58
115
 
59
116
  When you need to customize the [theme](https://tailwindcss.com/docs/theme) configuration of Tailwind CSS, you can modify it in the configuration [`source.designSystem`](/configure/app/source/design-system), for example, add a color theme `primary`:
60
117
 
@@ -8,6 +8,10 @@ Modern.js provides support for environment variables, including built-in environ
8
8
 
9
9
  ## Built-in Environment
10
10
 
11
+ ### ASSET_PREFIX
12
+
13
+ The current path prefix of resource file, which is a **read-only** environment variable.
14
+
11
15
  ### NODE_ENV
12
16
 
13
17
  The current execution environment and is a **read-only** environment variable whose have different values under different execution commands:
@@ -293,7 +293,7 @@ A Utility Class named `custom-text-gray` is implemented in `src/routes/styles/ut
293
293
  ```
294
294
 
295
295
  :::info note
296
- Modern.js integrates with [PostCSS](/guides/css/postcss) and supports modern CSS syntax features such as [custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties).
296
+ Modern.js integrates with [PostCSS](/guides/basic-features/css) and supports modern CSS syntax features such as [custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties).
297
297
 
298
298
  :::
299
299
 
package/package.json CHANGED
@@ -11,13 +11,13 @@
11
11
  "modern",
12
12
  "modern.js"
13
13
  ],
14
- "version": "2.6.0",
14
+ "version": "2.7.0",
15
15
  "publishConfig": {
16
16
  "registry": "https://registry.npmjs.org/",
17
17
  "access": "public"
18
18
  },
19
19
  "peerDependencies": {
20
- "@modern-js/builder-doc": "^2.6.0"
20
+ "@modern-js/builder-doc": "^2.7.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "ts-node": "^10",
@@ -25,7 +25,7 @@
25
25
  "fs-extra": "^10",
26
26
  "@types/node": "^16",
27
27
  "@types/fs-extra": "^9",
28
- "@modern-js/builder-doc": "2.6.0"
28
+ "@modern-js/builder-doc": "2.7.0"
29
29
  },
30
30
  "scripts": {
31
31
  "build": "npx ts-node ./scripts/sync.ts"
@@ -26,13 +26,23 @@ sidebar_position: 4
26
26
 
27
27
  ## 更多用法
28
28
 
29
- 不论是在[自定义 HTML](/guides/basic-features/html) 中,或是在 [`config/public/`](/apis/app/hooks/config/public) 下的任意 HTML 文件中,都可以直接使用 HTML 标签引用 `config/upload/` 目录下的资源:
29
+ 在 React 组件中,可以通过[内置环境变量](/guides/basic-features/env-vars.html#asset_prefix)来添加该前缀:
30
+
31
+ ```tsx
32
+ export default () => {
33
+ return (
34
+ <img src={`${process.env.ASSET_PREFIX}/upload/banner.png`}></img>
35
+ );
36
+ };
37
+ ```
38
+
39
+ 另外,不论是在[自定义 HTML](/guides/basic-features/html) 中,或是在 [`config/public/`](/apis/app/hooks/config/public) 下的任意 HTML 文件中,都可以直接使用 HTML 标签引用 `config/upload/` 目录下的资源:
30
40
 
31
41
  ```html
32
42
  <script src="/upload/index.js"></script>
33
43
  ```
34
44
 
35
- 如果设置了 [`output.assetPrefix`](/configure/app/output/asset-prefix) 前缀,也可以直接使用模板语法添加该前缀:
45
+ 如果设置了 [`dev.assetPrefix`](/configure/app/dev/asset-prefix) 或 [`output.assetPrefix`](/configure/app/output/asset-prefix) 前缀,也可以直接使用模板语法添加该前缀:
36
46
 
37
47
  ```html
38
48
  <script src="<%=assetPrefix %>/upload/index.js"></script>
@@ -4,11 +4,13 @@ sidebar_label: ssr
4
4
 
5
5
  # server.ssr
6
6
 
7
- - **类型:** `boolean`
7
+ - **类型:** `boolean` | `Object`
8
8
  - **默认值:** `false`
9
9
 
10
10
  SSR 开关以及相关设置。
11
11
 
12
+ ### Boolean 类型
13
+
12
14
  当值类型为 `boolean` 时,表示是否开启 SSR 部署模式,默认 `false` 不开启。
13
15
 
14
16
  ```ts title="modern.config.ts"
@@ -18,3 +20,19 @@ export default defineConfig({
18
20
  },
19
21
  });
20
22
  ```
23
+
24
+ ### Object 类型
25
+
26
+ 当值类型为 `Object` 时,可以配置如下属性:
27
+
28
+ - `mode`:`string = 'string'`,默认为使用 `renderToString` 渲染。配置为 'stream' 开启流式渲染。
29
+ - `forceCSR`:`boolean = false`,默认关闭强制 CSR 渲染。配置为 `true` 后,在页面访问时添加 `?csr=true` 即可强制 CSR。
30
+
31
+ ```ts title="modern.config.ts"
32
+ export default defineConfig({
33
+ server: {
34
+ forceCSR: true,
35
+ mode: 'stream',
36
+ },
37
+ });
38
+ ```
@@ -43,10 +43,13 @@ Modern.js 打破传统的 SSR 开发模式,提供了用户无感的 SSR 开发
43
43
  不过,开发者仍然需要关注数据的兜底处理,例如 `null` 值或不符合预期的数据返回。避免在 SSR 时产生 React 渲染错误或是返回凌乱的渲染结果。
44
44
 
45
45
  :::info 补充信息
46
- 使用 Data Loader 时,数据获取发生在渲染前,Modern.js 也仍然支持在组件渲染时获取数据。更多相关内容可以查看[数据获取](/guides/basic-features/data-fetch)。
46
+ 1. 当以客户端路由的方式请求页面时,Modern.js 会发送一个 HTTP 请求,服务端接收到请求后执行页面对应的 Data Loader 函数,然后将执行结果作为请求的响应返回浏览器。
47
47
 
48
+ 2. 使用 Data Loader 时,数据获取发生在渲染前,Modern.js 也仍然支持在组件渲染时获取数据。更多相关内容可以查看[数据获取](/guides/basic-features/data-fetch)。
48
49
  :::
49
50
 
51
+
52
+
50
53
  ## 保持渲染一致
51
54
 
52
55
  有些业务中,通常需要根据当前的运行容器环境特征做不同的 UI 展示,例如 [UA](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) 信息。如果处理不够仔细,此时很有可能出现不符合预期的渲染结果。
@@ -277,7 +280,7 @@ export const loader = () => {
277
280
 
278
281
  ## 流式渲染
279
282
 
280
- Modern.js 支持了 React 18 的流式渲染,可以通过如下配置修改默认的渲染模式:
283
+ Modern.js 支持了 React 18 的流式渲染,可以通过如下配置启用:
281
284
 
282
285
  ```json
283
286
  {
@@ -289,7 +292,210 @@ Modern.js 支持了 React 18 的流式渲染,可以通过如下配置修改默
289
292
  }
290
293
  ```
291
294
 
292
- :::note
293
- 目前 Modern.js 内置的数据获取方式还未支持流式渲染,如迫切需要开发者可以按照 React Stream SSR 的 Demo 自建。
295
+ Modern.js 的流式渲染基于 React Router 实现,主要涉及 API 有:
296
+
297
+ - [`defer`](https://reactrouter.com/en/main/utils/defer):在 Data Loader 中使用,用于支持异步获取数据。
298
+ - [`Await`](https://reactrouter.com/en/main/components/await):用于渲染 Data Loader 返回的异步数据。
299
+ - [`useAsyncValue`](https://reactrouter.com/en/main/hooks/use-async-value):用于从最近的父级 `Await` 组件中获取数据。
300
+
301
+
302
+ ### 异步获取数据
303
+
304
+ ```ts title='page.loader.ts'
305
+ import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
306
+
307
+ interface User {
308
+ name: string;
309
+ age: number;
310
+ }
311
+
312
+ export interface Data {
313
+ data: User;
314
+ }
315
+
316
+ export default ({ params }: LoaderFunctionArgs) => {
317
+ const userId = params.id;
318
+
319
+ const user = new Promise<User>(resolve => {
320
+ setTimeout(() => {
321
+ resolve({
322
+ name: `user-${userId}`,
323
+ age: 18,
324
+ });
325
+ }, 200);
326
+ });
327
+
328
+ return defer({ data: user });
329
+ };
330
+
331
+ ```
332
+
333
+ `user` 是一个 Promise 类型的对象,表示需要异步获取的数据,通过 `defer` 处理需要异步获取的 `user`。注意,`defer` 必须接收一个对象类型的参数,
334
+ 因此, 传入 `defer` 的参数为 `{data: user}`。
335
+
336
+ `defer` 还可以同时接收异步数据和同步数据。例如:
337
+
338
+ ```ts title='page.loader.ts'
339
+
340
+ // 省略部分代码
341
+
342
+ export default ({ params }: LoaderFunctionArgs) => {
343
+ const userId = params.id;
344
+
345
+ const user = new Promise<User>(resolve => {
346
+ setTimeout(() => {
347
+ resolve({
348
+ name: `user-${userId}`,
349
+ age: 18,
350
+ });
351
+ }, 200);
352
+ });
353
+
354
+ const otherData = new Promise<string>(resolve => {
355
+ setTimeout(() => {
356
+ resolve('some sync data');
357
+ }, 200);
358
+ });
359
+
360
+ return defer({
361
+ data: user,
362
+ other: await otherData
363
+ });
364
+ };
365
+
366
+ ```
367
+
368
+ `otherData` 前加了 `await`,所以是同步获取的数据,它可以和异步获取的数据 `user` 同时传入 `defer`。
369
+
370
+
371
+ ### 渲染异步数据
372
+
373
+ 通过 `Await` 组件,可以获取到 Data Loader 中异步返回的数据,然后进行渲染。例如:
374
+
375
+ ```ts title='page.tsx'
376
+ import { Await, useLoaderData } from '@modern-js/runtime/router';
377
+ import { Suspense } from 'react';
378
+ import type { Data } from './page.loader';
379
+
380
+ const Page = () => {
381
+ const data = useLoaderData() as Data;
382
+
383
+ return (
384
+ <div>
385
+ User info:
386
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
387
+ <Await resolve={data.data}>
388
+ {(user) => {
389
+ return (
390
+ <div id="data">
391
+ name: {user.name}, age: {user.age}
392
+ </div>
393
+ );
394
+ }}
395
+ </Await>
396
+ </Suspense>
397
+ </div>
398
+ );
399
+ };
294
400
 
401
+ export default Page;
402
+ ```
403
+
404
+ `Await` 需要包裹在 `Suspense` 组件内部,`Await` 的 `resolve` 传入的是 Data Loader 异步获取的数据,当数据获取完成后,
405
+ 通过 [Render Props](https://reactjs.org/docs/render-props.html) 模式,渲染获取到的数据。在数据的获取阶段,将展示
406
+ `Suspense` 组件 `fallback` 属性设置的内容。
407
+
408
+ :::warning 注意
409
+ 从 Data Loader 文件导入类型时,需要使用 import type 语法,保证只导入类型信息,这样可以避免 Data Loader 的代码打包到前端产物的 bundle 文件中。
410
+
411
+ 所以,这里的导入方式为:`import type { Data } from './page.loader'`;
412
+ :::
413
+
414
+ 也可以通过 `useAsyncValue` 获取 Data Loader 返回的异步数据。例如:
415
+
416
+ ```
417
+ ```ts title='page.tsx'
418
+ import { useAsyncValue } from '@modern-js/runtime/router';
419
+
420
+ // 省略部分代码
421
+
422
+ const UserInfo = () => {
423
+ const user = useAsyncValue();
424
+
425
+ return (
426
+ <div>
427
+ name: {user.name}, age: {user.age}
428
+ </div>
429
+ )
430
+ }
431
+
432
+ const Page = () => {
433
+ const data = useLoaderData() as Data;
434
+
435
+ return (
436
+ <div>
437
+ User info:
438
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
439
+ <Await resolve={data.data}>
440
+ <UserInfo />
441
+ </Await>
442
+ </Suspense>
443
+ </div>
444
+ );
445
+ };
446
+
447
+ export default Page;
448
+ ```
449
+
450
+ ### 错误处理
451
+
452
+ `Await` 组件的 `errorElement` 属性,可以用来处理当 Data Loader 执行时,或者子组件渲染时抛出的错误。
453
+ 例如,我们故意在 Data Loader 函数中抛出错误:
454
+
455
+ ```ts title='page.loader.ts'
456
+ import { defer } from '@modern-js/runtime/router';
457
+
458
+ export default () => {
459
+ const data = new Promise((resolve, reject) => {
460
+ setTimeout(() => {
461
+ reject(new Error('error occurs'));
462
+ }, 200);
463
+ });
464
+
465
+ return defer({ data });
466
+ };
467
+ ```
468
+
469
+ 然后通过 `useAsyncError` 获取错误,并将用于渲染错误信息的组件赋值给 `Await` 组件的 `errorElement` 属性:
470
+
471
+ ```ts title='page.ts'
472
+ import { Await, useAsyncError, useLoaderData } from '@modern-js/runtime/router';
473
+ import { Suspense } from 'react';
474
+
475
+ export default function Page() {
476
+ const data = useLoaderData();
477
+
478
+ return (
479
+ <div>
480
+ Error page
481
+ <Suspense fallback={<div>loading ...</div>}>
482
+ <Await resolve={data.data} errorElement={<ErrorElement />}>
483
+ {(data: any) => {
484
+ return <div>never displayed</div>;
485
+ }}
486
+ </Await>
487
+ </Suspense>
488
+ </div>
489
+ );
490
+ }
491
+
492
+ function ErrorElement() {
493
+ const error = useAsyncError() as Error;
494
+ return <p>Something went wrong! {error.message}</p>;
495
+ }
496
+ ```
497
+
498
+ :::info 补充信息
499
+ 1. [Deferred Data](https://reactrouter.com/en/main/guides/deferred)
500
+ 2. [New Suspense SSR Architecture in React 18](https://github.com/reactwg/react-18/discussions/37)
295
501
  :::
@@ -2,7 +2,64 @@
2
2
  sidebar_position: 2
3
3
  ---
4
4
 
5
- # Tailwind CSS
5
+ # CSS 开发方案
6
+
7
+ Modern.js 内置多种常用的 CSS 开发方案,包括 Less / Sass / Stylus 预处理器、PostCSS、CSS Modules、CSS-in-JS 和 Tailwind CSS。
8
+
9
+ ## 使用 Less、Sass 和 Stylus
10
+
11
+ Modern.js 内置了社区流行的 CSS 预处理器,包括 Less 和 Sass。
12
+
13
+ 默认情况下,你不需要对 Less 和 Sass 进行任何配置。如果你有自定义 loader 配置的需求,可以通过配置 [tools.less](/configure/app/tools/less)、[tools.sass](/configure/app/tools/sass) 来进行设置。
14
+
15
+ 你也可以在 Modern.js 中使用 Stylus,只需要安装 Modern.js Builder 提供的 Stylus 插件即可,使用方式请参考 [Stylus 插件](https://modernjs.dev/builder/plugins/plugin-stylus.html)。
16
+
17
+ ## 使用 PostCSS
18
+
19
+ Modern.js 内置了 [PostCSS](https://postcss.org/) 来转换 CSS 代码。
20
+
21
+ 请阅读 [Modern.js Builder - 使用 PostCSS](https://modernjs.dev/builder/guide/basic/css-usage.html#%E4%BD%BF%E7%94%A8-postcss) 了解更多用法。
22
+
23
+ ## 使用 CSS Modules
24
+
25
+ 请阅读 [使用 CSS Modules](https://modernjs.dev/builder/guide/basic/css-modules.html) 章节来了解 CSS Modules 的完整用法。
26
+
27
+ ## 使用 CSS-in-JS
28
+
29
+ CSS-in-JS 是一种可以将 CSS 样式写在 JS 文件里的技术。
30
+
31
+ Modern.js 集成了社区常用的 CSS-in-JS 实现库 [styled-components](https://styled-components.com/),它使用 JavaScript 的新特性 [Tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) 编写组件的 CSS 样式。可以直接从 `@modern-js/runtime/styled` 引入 [styled-components](https://styled-components.com/) 的 API 进行使用。
32
+
33
+ 当需要编写一个内部字体为红色的 `div` 组件时,可以如下实现:
34
+
35
+ ```js
36
+ import styled from '@modern-js/runtime/styled';
37
+
38
+ const RedDiv = styled.div`
39
+ color: red;
40
+ `;
41
+ ```
42
+
43
+ 当需要根据组件的 `props` 动态设置组件样式时,例如 `props` 的属性 `primary` 为 `true` 时,按钮的颜色为白色,其他情况为红色,实现代码如下:
44
+
45
+ ```js
46
+ import styled from '@modern-js/runtime/styled';
47
+
48
+ const Button = styled.button`
49
+ color: ${props => (props.primary ? 'white' : 'red')};
50
+ font-size: 1em;
51
+ `;
52
+ ```
53
+
54
+ 关于 styled-components 的更多用法,请参考 [styled-components 官网](https://styled-components.com/)。
55
+
56
+ Modern.js 内部集成了 Babel 的 [babel-plugin-styled-components](https://github.com/styled-components/babel-plugin-styled-components) 插件,你可以通过 [tools.styledComponents](/configure/app/tools/styled-components) 对插件进行配置。
57
+
58
+ :::tip 提示
59
+ 如果需要使用 [styled-jsx](https://www.npmjs.com/package/styled-jsx)、[Emotion](https://emotion.sh/) 等其他 CSS-in-JS 库,需要先安装对应库的依赖。具体使用方式请参考对应库的官网。
60
+ :::
61
+
62
+ ## 使用 Tailwind CSS
6
63
 
7
64
  [Tailwind CSS](https://tailwindcss.com/) 是一个以 Utility Class 为基础的 CSS 框架和设计系统,可以快速地为组件添加常用样式,同时支持主题样式的灵活扩展。在 Modern.js 中使用 [Tailwind CSS](https://tailwindcss.com/),只需要在项目根目录下执行 `pnpm run new` 并开启。
8
65
 
@@ -46,7 +103,7 @@ const App = () => (
46
103
 
47
104
  :::
48
105
 
49
- ## Tailwind CSS 版本
106
+ ### Tailwind CSS 版本
50
107
 
51
108
  Modern.js 同时支持 Tailwind CSS v2 和 v3 版本,框架会识别项目 `package.json` 中的 `tailwindcss` 依赖版本,并启用相应的配置。默认情况下,我们会为你安装 Tailwind CSS v3 版本。
52
109
 
@@ -64,7 +121,7 @@ Tailwind CSS v2 和 v3 均不支持 IE 11 浏览器,相关背景请参考:
64
121
 
65
122
  如果你在 IE 11 浏览器上使用 Tailwind CSS,可能会出现部分样式不可用的现象,请谨慎使用。
66
123
 
67
- ## Theme 配置
124
+ ### Theme 配置
68
125
 
69
126
  当需要自定义 Tailwind CSS 的 [theme](https://tailwindcss.com/docs/theme) 配置的时候,可以在配置 [`source.designSystem`](/configure/app/source/design-system) 中修改,例如,颜色主题中增加一个 `primary`:
70
127
 
@@ -8,6 +8,10 @@ Modern.js 提供了对环境变量的支持,包含内置的环境变量和自
8
8
 
9
9
  ## 内置的环境变量
10
10
 
11
+ ### ASSET_PREFIX
12
+
13
+ 表示当前资源文件的路径前缀,是**只读的**的环境变量。
14
+
11
15
  ### NODE_ENV
12
16
 
13
17
  表示当前的执行环境,是**只读的**的环境变量,其值在不同的执行命令下具有不同的值:
@@ -293,7 +293,7 @@ import '../styles/utils.css';
293
293
  ```
294
294
 
295
295
  :::info
296
- Modern.js 集成了 [PostCSS](/guides/css/postcss),支持现代 CSS 语法特性,比如 [custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)。
296
+ Modern.js 集成了 [PostCSS](/guides/basic-features/css),支持现代 CSS 语法特性,比如 [custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)。
297
297
 
298
298
  :::
299
299
 
@@ -1,5 +0,0 @@
1
- {
2
- "label": "CSS Solutions",
3
- "position": 4,
4
- "collapsed": false
5
- }
@@ -1,40 +0,0 @@
1
- ---
2
- sidebar_position: 1
3
- ---
4
-
5
- # CSS-in-JS
6
-
7
- CSS-in-JS is a technology that can write CSS styles in JS files. Modern.js integrates the CSS-in-JS library [styled-components](https://styled-components.com/) commonly used in the community, which uses the new feature of JavaScript [Tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) to write CSS styles for components. You can use the [styled-components](https://styled-components.com/) API directly from `@modern-js/runtime/styled`.
8
-
9
- When you need to write a `div` component with an internal font in red, you can do the following implementation:
10
-
11
- ```js
12
- import styled from '@modern-js/runtime/styled';
13
-
14
- const RedDiv = styled.div`
15
- color: red;
16
- `;
17
- ```
18
-
19
- When you need to dynamically set the component style according to the `props` of the component, for example, when the attribute `primary` of `props` is `true`, the color of the button is white, and otherwise it is red. The implementation code is as follows:
20
-
21
- ```js
22
- import styled from '@modern-js/runtime/styled';
23
-
24
- const Button = styled.button`
25
- color: ${props => (props.primary ? 'white' : 'red')};
26
- font-size: 1em;
27
- `;
28
- ```
29
-
30
- For more usage of styled-components, please refer to [[styled-components official website](https://styled-components.com/) ].
31
-
32
- :::info Additional
33
- Modern.js uses the Babel plugin [babel-plugin-styled-components](https://github.com/styled-components/babel-plugin-styled-components) internally, and the plugin can be configured through [`tools.styled Components`](/configure/app/tools/styled-components).
34
-
35
- :::
36
-
37
- :::tip
38
- If you need to use [styled-jsx](https://www.npmjs.com/package/styled-jsx), [Emotion](https://emotion.sh/) and other CSS-in-JS libraries, you need to install the dependency of the corresponding library first. For specific usage, please refer to the official website of the corresponding library.
39
-
40
- :::
@@ -1,87 +0,0 @@
1
- ---
2
- sidebar_position: 5
3
- ---
4
-
5
- # CSS Modules
6
-
7
- Modern.js out of the box support for [CSS Modules](https://github.com/css-modules/css-modules).
8
-
9
- ## File Suffix Form CSS Modules
10
-
11
- By default, files ending in `.module.(css|scss|sass|less)` are treated as CSS Modules files, for example:
12
-
13
- ```css title="button.module.css"
14
- .redColor {
15
- color: red;
16
- }
17
- ```
18
-
19
- ```js title="Button.jsx"
20
- import styles from './button.module.css';
21
-
22
- export default function Button() {
23
- return (
24
- <button type="button" className={styles.redColor}>
25
- red button
26
- </button>
27
- );
28
- }
29
- ```
30
-
31
- Will eventually be compiled as:
32
-
33
- ```js
34
- <button type="button" className="button_redColor__1-RBg">
35
- red button
36
- </button>
37
- ```
38
-
39
- ## Global CSS Modules
40
-
41
- If you want to remove the `.module` suffix from the filename, you can set [`output.disable CssModuleExtension`](/configure/app/output/disable-css-module-extension).
42
-
43
- After setting, all style files except the style files in the `node_modules/` directory and the file name format of `[name].global.(css|scss|sass|less)` will be processed as CSS Modules.
44
-
45
- If you need global styles at this point, you can solve it by creating a style file with the filename format `[name].global.(css|scss|sass|less)`, for example:
46
-
47
- ```css title="app.global.css"
48
- .bg-blue {
49
- background-color: blue;
50
- }
51
- ```
52
-
53
- ```css title="button.css"
54
- .redColor {
55
- color: red;
56
- }
57
- ```
58
-
59
- ```js title="App.jsx"
60
- import './app.global.css';
61
- import styles from './button.css';
62
-
63
- export default function Button() {
64
- return (
65
- <button type="button" className={`${styles.redColor} bg-blue`}>
66
- button
67
- </button>
68
- );
69
- }
70
- ```
71
-
72
- Will eventually be compiled as:
73
-
74
- ```js
75
- <button type="button" className="button__redColor--JsFYl bg-blue">
76
- button
77
- </button>
78
- ```
79
-
80
- The final effect is as follows:
81
-
82
- ![](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/more-css-modules.png)
83
-
84
- :::tip
85
- When using [babel-plugin-react-css-modules](https://github.com/gajus/babel-plugin-react-css-modules), it is important to note that the configuration option `generateScopedName` of this plugin needs to be the same as [`output.css ModuleLocalIdentName`](/configure/app/output/css-module-local-ident-name).
86
-
87
- :::
@@ -1,17 +0,0 @@
1
- ---
2
- sidebar_position: 4
3
- ---
4
-
5
- # Less and Sass
6
-
7
- [Less](https://lesscss.org/) and [Sass](https://sass-lang.com/) are two commonly used CSS preprocessors that Modern.js built-in support for the Less and Sass compile capabilities.
8
-
9
- ## Customized Configuration
10
-
11
- - If you need to customize the configuration of [less-loader](https://github.com/webpack-contrib/less-loader), please refer to the [tools.less](/configure/app/tools/less).
12
- - If you need to customize the configuration of [sass-loader](https://github.com/webpack-contrib/sass-loader), please refer to the [tools.less](/configure/app/tools/sass).
13
-
14
- :::tip
15
- CSS files pre-compiled by Less and Sass will still undergo Modern.js build-in [PostCSS](https://postcss.org/) conversion, which has good browser compatibility. For related content, please refer to [[PostCSS](/guides/css/postcss)].
16
-
17
- :::
@@ -1,79 +0,0 @@
1
- ---
2
- sidebar_position: 3
3
- ---
4
-
5
- # PostCSS
6
-
7
- [PostCSS](https://postcss.org/) is a tool for converting CSS code with JavaScript tools and plugins. Modern.js built-in PostCSS and integrates common PostCSS plugins such as [Autoprefixer](https://github.com/postcss/autoprefixer) to meet the style development needs of most projects.
8
-
9
- By default, Modern.js compile and transform CSS as follows:
10
-
11
- 1. [Autoprefixer](https://github.com/postcss/autoprefixer) Automatically add the required browser vendor prefix to CSS rules according to the required browser range. Modern.js default supported browser ranges are: `['> 0.01%', 'not dead', 'not op_mini all']`.
12
-
13
- :::info Note
14
- - [Supported browser range: `> 0.01%`] means that the browser market share is greater than 0.01%.
15
- - `Not dead` means excluding browsers that are no longer officially supported and browsers that have not been updated in the past 24 months.
16
- - `not op_mini all` means exclude Opera Mini.
17
-
18
- :::
19
-
20
- :::info Additional
21
- If you need to modify the default browser support range, you can configure `browserslist` in the project's `package.json` file, and set the rule to refer to the use of [Browserslist](https://github.com/browserslist/browserslist). The following is an example:
22
- `json title ="package.json" { "Browserslist": [ "The last 1 versions", "> 1%", "IE 10" ] } `
23
-
24
- :::
25
-
26
- 2. Provide [CSS custom properties](https://www.w3.org/TR/css-variables-1/) support, you can define and use custom variables in CSS, such as:
27
-
28
- ```css
29
- :root {
30
- --main-bg-color: pink;
31
- }
32
-
33
- body {
34
- background-color: var(--main-bg-color);
35
- }
36
- ```
37
-
38
- 3. Provide [CSS Nesting](https://drafts.csswg.org/css-nesting-1/) support, you can use nested writing in CSS, such as:
39
-
40
- ```css
41
- table.colortable td {
42
- text-align: center;
43
- }
44
- table.colortable td.c {
45
- text-transform: uppercase;
46
- }
47
- ```
48
-
49
- It can also be rewritten as CSS nested:
50
-
51
- ```css
52
- table.colortable {
53
- & td {
54
- text-align: center;
55
- &.c {
56
- text-transform: uppercase;
57
- }
58
- }
59
- }
60
- ```
61
-
62
- 4. Fix known [Flexbugs](https://github.com/philipwalton/flexbugs).
63
- 5. Provide compatibility with the following CSS features:
64
- - [`initial` attribute value](https://developer.mozilla.org/en-US/docs/Web/CSS/initial_value)
65
- - [`break-` attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/break-after)
66
- - [`font-variant`](https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant)
67
- - [Media Query Ranges](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#syntax_improvements_in_level_4)
68
-
69
- When you need to modify the PostCSS configuration, you can implement it through the underlying configuration [`tools.postcss`](/configure/app/tools/postcss), here is an example:
70
-
71
- ```ts title="modern.config.ts"
72
- export default defineConfig({
73
- tools: {
74
- postcss: {
75
- plugins: ['autoprefixer', ('postcss-flexbugs-fixes': {})],
76
- },
77
- },
78
- });
79
- ```
@@ -1,5 +0,0 @@
1
- {
2
- "label": "CSS 开发方案",
3
- "position": 5,
4
- "collapsed": false
5
- }
@@ -1,40 +0,0 @@
1
- ---
2
- sidebar_position: 1
3
- ---
4
-
5
- # CSS-in-JS
6
-
7
- CSS-in-JS 是一种可以将 CSS 样式写在 JS 文件里的技术。Modern.js 集成了社区常用的 CSS-in-JS 实现库 [styled-components](https://styled-components.com/),它使用 JavaScript 的新特性 [Tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) 编写组件的 CSS 样式。可以直接从 `@modern-js/runtime/styled` 引入 [styled-components](https://styled-components.com/) 的 API 进行使用。
8
-
9
- 当需要编写一个内部字体为红色的 `div` 组件时,可以如下实现:
10
-
11
- ```js
12
- import styled from '@modern-js/runtime/styled';
13
-
14
- const RedDiv = styled.div`
15
- color: red;
16
- `;
17
- ```
18
-
19
- 当需要根据组件的 `props` 动态设置组件样式时,例如 `props` 的属性 `primary` 为 `true` 时,按钮的颜色为白色,其他情况为红色,实现代码如下:
20
-
21
- ```js
22
- import styled from '@modern-js/runtime/styled';
23
-
24
- const Button = styled.button`
25
- color: ${props => (props.primary ? 'white' : 'red')};
26
- font-size: 1em;
27
- `;
28
- ```
29
-
30
- 关于 styled-components 的更多用法,请参考【[styled-components 官网](https://styled-components.com/)】。
31
-
32
- :::info 补充信息
33
- Modern.js 内部使用了 Babel 插件 [babel-plugin-styled-components](https://github.com/styled-components/babel-plugin-styled-components),可以通过 [`tools.styledComponents`](/configure/app/tools/styled-components) 对插件进行配置。
34
-
35
- :::
36
-
37
- :::tip 提示
38
- 如果需要使用 [styled-jsx](https://www.npmjs.com/package/styled-jsx)、[Emotion](https://emotion.sh/) 等其他 CSS-in-JS 库,需要先安装对应库的依赖。具体使用方式请参考对应库的官网。
39
-
40
- :::
@@ -1,87 +0,0 @@
1
- ---
2
- sidebar_position: 5
3
- ---
4
-
5
- # CSS Modules
6
-
7
- Modern.js 为 [CSS Modules](https://github.com/css-modules/css-modules) 提供了开箱即用的支持。
8
-
9
- ## 文件后缀形式 CSS Modules
10
-
11
- 默认情况下,以 `.module.(css|scss|sass|less)` 结尾的文件会作为 CSS Modules 文件处理,例如:
12
-
13
- ```css title="button.module.css"
14
- .redColor {
15
- color: red;
16
- }
17
- ```
18
-
19
- ```js title="Button.jsx"
20
- import styles from './button.module.css';
21
-
22
- export default function Button() {
23
- return (
24
- <button type="button" className={styles.redColor}>
25
- red button
26
- </button>
27
- );
28
- }
29
- ```
30
-
31
- 最终将被编译为
32
-
33
- ```js
34
- <button type="button" className="button_redColor__1-RBg">
35
- red button
36
- </button>
37
- ```
38
-
39
- ## 全面启用 CSS Modules
40
-
41
- 如果想去掉文件名中 `.module` 后缀,可以设置 [`output.disableCssModuleExtension`](/configure/app/output/disable-css-module-extension)。
42
-
43
- 设置后,除了 `node_modules/` 目录下的样式文件和文件名称格式为 `[name].global.(css|scss|sass|less)` 之外的所有样式文件,都会作为 CSS Modules 处理。
44
-
45
- 如果此时需要全局样式,可以通过创建文件名称格式为 `[name].global.(css|less|scss|sass)` 的样式文件来解决, 例如:
46
-
47
- ```css title="app.global.css"
48
- .bg-blue {
49
- background-color: blue;
50
- }
51
- ```
52
-
53
- ```css title="button.css"
54
- .redColor {
55
- color: red;
56
- }
57
- ```
58
-
59
- ```js title="App.jsx"
60
- import './app.global.css';
61
- import styles from './button.css';
62
-
63
- export default function Button() {
64
- return (
65
- <button type="button" className={`${styles.redColor} bg-blue`}>
66
- button
67
- </button>
68
- );
69
- }
70
- ```
71
-
72
- 最终将被编译为:
73
-
74
- ```js
75
- <button type="button" className="button__redColor--JsFYl bg-blue">
76
- button
77
- </button>
78
- ```
79
-
80
- 最终效果如下:
81
-
82
- ![](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/more-css-modules.png)
83
-
84
- :::tip 提示
85
- 使用 [babel-plugin-react-css-modules](https://github.com/gajus/babel-plugin-react-css-modules) 时需要注意,该插件的配置选项 `generateScopedName` 需要和 [`output.cssModuleLocalIdentName`](/configure/app/output/css-module-local-ident-name) 保持一致。
86
-
87
- :::
@@ -1,17 +0,0 @@
1
- ---
2
- sidebar_position: 4
3
- ---
4
-
5
- # Less 和 Sass
6
-
7
- [Less](https://lesscss.org/) 和 [Sass](https://sass-lang.com/) 是常用的两种 CSS 预处理器,Modern.js 内置了 Less 和 Sass 编译能力的支持。
8
-
9
- ## 自定义配置
10
-
11
- - 如果需要自定义 [less-loader](https://github.com/webpack-contrib/less-loader) 的配置,请参考 [tools.less](/configure/app/tools/less) 配置项。
12
- - 如果需要自定义 [sass-loader](https://github.com/webpack-contrib/sass-loader) 的配置,请参考 [tools.less](/configure/app/tools/sass) 配置项。
13
-
14
- :::tip 提示
15
- 经过 Less 和 Sass 预编译后的 CSS 文件,仍然会经过 Modern.js 内置的 [PostCSS](https://postcss.org/) 的转换,具备良好的浏览器兼容性。相关内容请参考【[PostCSS](/guides/css/postcss)】。
16
-
17
- :::
@@ -1,80 +0,0 @@
1
- ---
2
- sidebar_position: 3
3
- ---
4
-
5
- # PostCSS
6
-
7
- [PostCSS](https://postcss.org/) 是一个用 JavaScript 工具和插件转换 CSS 代码的工具。Modern.js 内置 PostCSS,并集成 [Autoprefixer](https://github.com/postcss/autoprefixer) 等常用的 PostCSS 插件,能够满足大多数项目的样式开发需求。
8
-
9
- 默认情况下,Modern.js 会对 CSS 进行以下编译和转换:
10
-
11
- 1. [Autoprefixer](https://github.com/postcss/autoprefixer) 根据需要支持的浏览器范围,会自动为 CSS 规则添加需要的浏览器厂商前缀。Modern.js 默认支持的浏览器范围为:`['> 0.01%', 'not dead', 'not op_mini all']`。
12
-
13
- :::info 注意
14
-
15
- - 【支持的浏览器范围为:`> 0.01%`】是指浏览器市场份额大于 0.01%。
16
- - `not dead` 是指不包含官方不再支持的浏览器和过去 24 个月没有更新的浏览器。
17
- - `not op_mini all` 是指不包含 Opera Mini。
18
-
19
- :::
20
-
21
- :::info 补充信息
22
- 如果需要修改默认浏览器支持范围,可以在项目的 `package.json` 文件中配置 `browserslist`,设置规则参考 [Browserslist](https://github.com/browserslist/browserslist) 的使用,下面是一个示例:
23
- `json title="package.json" { "browserslist": [ "last 1 version", "> 1%", "IE 10" ] } `
24
-
25
- :::
26
-
27
- 2. 提供 [CSS custom properties](https://www.w3.org/TR/css-variables-1/) 支持,可以在 CSS 中定义和使用自定义变量,如:
28
-
29
- ```css
30
- :root {
31
- --main-bg-color: pink;
32
- }
33
-
34
- body {
35
- background-color: var(--main-bg-color);
36
- }
37
- ```
38
-
39
- 3. 提供 [CSS Nesting](https://drafts.csswg.org/css-nesting-1/) 支持,可以在 CSS 中使用嵌套写法,如:
40
-
41
- ```css
42
- table.colortable td {
43
- text-align: center;
44
- }
45
- table.colortable td.c {
46
- text-transform: uppercase;
47
- }
48
- ```
49
-
50
- 也可以改写成 CSS 嵌套写法:
51
-
52
- ```css
53
- table.colortable {
54
- & td {
55
- text-align: center;
56
- &.c {
57
- text-transform: uppercase;
58
- }
59
- }
60
- }
61
- ```
62
-
63
- 4. 修复已知的 [Flexbugs](https://github.com/philipwalton/flexbugs) 。
64
- 5. 对以下 CSS 特性提供兼容:
65
- - [`initial` 属性值](https://developer.mozilla.org/en-US/docs/Web/CSS/initial_value)
66
- - [`break-` 属性](https://developer.mozilla.org/en-US/docs/Web/CSS/break-after)
67
- - [`font-variant`](https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant)
68
- - [Media Query Ranges](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#syntax_improvements_in_level_4)
69
-
70
- 当需要修改 PostCSS 配置时,可以通过底层配置 [`tools.postcss`](/configure/app/tools/postcss) 来实现,下面是一个示例:
71
-
72
- ```ts title="modern.config.ts"
73
- export default defineConfig({
74
- tools: {
75
- postcss: {
76
- plugins: ['autoprefixer', ('postcss-flexbugs-fixes': {})],
77
- },
78
- },
79
- });
80
- ```