@modern-js/main-doc 2.5.0 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.turbo/turbo-build.log +1 -1
- package/en/apis/app/commands.mdx +297 -0
- package/en/apis/app/hooks/_category_.json +1 -1
- package/en/apis/app/hooks/config/upload.mdx +10 -0
- package/en/apis/app/hooks/src/routes.mdx +2 -2
- package/en/components/init-app.mdx +5 -5
- package/en/configure/app/bff/prefix.mdx +2 -3
- package/en/configure/app/bff/proxy.mdx +1 -1
- package/en/configure/app/dev/before-start-url.mdx +13 -0
- package/en/configure/app/dev/host.mdx +13 -0
- package/en/configure/app/output/ssg.mdx +3 -3
- package/en/configure/app/runtime/master-app.mdx +1 -1
- package/en/configure/app/server/ssr.mdx +18 -0
- package/en/configure/app/source/entries-dir.mdx +1 -1
- package/en/configure/app/testing/transformer.mdx +1 -1
- package/en/configure/app/tools/jest.mdx +1 -1
- package/en/guides/advanced-features/rspack-start.mdx +69 -0
- package/en/guides/advanced-features/ssg.mdx +8 -8
- package/en/guides/advanced-features/ssr.mdx +210 -5
- package/en/guides/basic-features/alias.mdx +4 -4
- package/en/guides/{css/tailwindcss.mdx → basic-features/css.mdx} +60 -3
- package/en/guides/basic-features/data-fetch.mdx +4 -4
- package/en/guides/basic-features/env-vars.mdx +4 -0
- package/en/guides/basic-features/routes.mdx +23 -7
- package/en/guides/concept/builder.mdx +1 -1
- package/en/guides/get-started/quick-start.mdx +2 -2
- package/en/guides/topic-detail/micro-frontend/c03-main-app.mdx +1 -1
- package/en/tutorials/first-app/c03-css.mdx +1 -1
- package/en/tutorials/first-app/c07-container.mdx +17 -17
- package/en/tutorials/first-app/c08-entries.mdx +23 -23
- package/package.json +3 -3
- package/scripts/summary.en.json +1 -1
- package/scripts/summary.zh.json +1 -1
- package/zh/apis/app/commands.mdx +299 -0
- package/zh/apis/app/hooks/_category_.json +1 -1
- package/zh/apis/app/hooks/config/upload.mdx +12 -2
- package/zh/apis/app/hooks/src/routes.mdx +2 -2
- package/zh/components/init-app.mdx +5 -5
- package/zh/configure/app/bff/prefix.mdx +1 -1
- package/zh/configure/app/bff/proxy.mdx +1 -1
- package/zh/configure/app/dev/before-start-url.mdx +13 -0
- package/zh/configure/app/dev/host.mdx +13 -0
- package/zh/configure/app/output/ssg.mdx +3 -3
- package/zh/configure/app/server/ssr.mdx +19 -1
- package/zh/configure/app/source/entries-dir.mdx +1 -1
- package/zh/guides/advanced-features/rspack-start.mdx +69 -0
- package/zh/guides/advanced-features/ssg.mdx +8 -8
- package/zh/guides/advanced-features/ssr.mdx +213 -6
- package/zh/guides/basic-features/alias.mdx +4 -4
- package/zh/guides/{css/tailwindcss.mdx → basic-features/css.mdx} +60 -3
- package/zh/guides/basic-features/data-fetch.mdx +4 -4
- package/zh/guides/basic-features/env-vars.mdx +4 -0
- package/zh/guides/basic-features/routes.mdx +23 -7
- package/zh/guides/concept/builder.mdx +2 -2
- package/zh/guides/get-started/quick-start.mdx +2 -2
- package/zh/guides/topic-detail/micro-frontend/c03-main-app.mdx +1 -1
- package/zh/tutorials/first-app/c03-css.mdx +1 -1
- package/zh/tutorials/first-app/c07-container.mdx +17 -17
- package/zh/tutorials/first-app/c08-entries.mdx +23 -23
- package/en/apis/app/commands/_category_.json +0 -5
- package/en/apis/app/commands/build.mdx +0 -39
- package/en/apis/app/commands/dev.mdx +0 -61
- package/en/apis/app/commands/inspect.mdx +0 -61
- package/en/apis/app/commands/lint.mdx +0 -19
- package/en/apis/app/commands/new.mdx +0 -55
- package/en/apis/app/commands/serve.mdx +0 -27
- package/en/apis/app/commands/test.mdx +0 -35
- package/en/apis/app/commands/upgrade.mdx +0 -18
- package/en/guides/css/_category_.json +0 -5
- package/en/guides/css/css-in-js.mdx +0 -40
- package/en/guides/css/css-modules.mdx +0 -87
- package/en/guides/css/less-sass.mdx +0 -17
- package/en/guides/css/postcss.mdx +0 -79
- package/zh/apis/app/commands/_category_.json +0 -5
- package/zh/apis/app/commands/build.mdx +0 -39
- package/zh/apis/app/commands/dev.mdx +0 -61
- package/zh/apis/app/commands/inspect.mdx +0 -61
- package/zh/apis/app/commands/lint.mdx +0 -19
- package/zh/apis/app/commands/new.mdx +0 -54
- package/zh/apis/app/commands/serve.mdx +0 -27
- package/zh/apis/app/commands/test.mdx +0 -35
- package/zh/apis/app/commands/upgrade.mdx +0 -18
- package/zh/guides/css/_category_.json +0 -5
- package/zh/guides/css/css-in-js.mdx +0 -40
- package/zh/guides/css/css-modules.mdx +0 -87
- package/zh/guides/css/less-sass.mdx +0 -17
- package/zh/guides/css/postcss.mdx +0 -80
@@ -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
|
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
|
-
##
|
292
|
+
## Streaming SSR
|
292
293
|
|
293
|
-
Modern.js supports streaming rendering in React 18
|
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
|
-
|
306
|
-
|
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
|
:::
|
@@ -23,10 +23,10 @@ For example, import the modules from the `src/common/` directory in the `src/App
|
|
23
23
|
```bash
|
24
24
|
.
|
25
25
|
├── common
|
26
|
-
│
|
27
|
-
│
|
28
|
-
│
|
29
|
-
│
|
26
|
+
│ ├── styles
|
27
|
+
│ │ └── base.css
|
28
|
+
│ └── utils
|
29
|
+
│ └── index.ts
|
30
30
|
├── App.tsx
|
31
31
|
```
|
32
32
|
|
@@ -2,7 +2,64 @@
|
|
2
2
|
sidebar_position: 2
|
3
3
|
---
|
4
4
|
|
5
|
-
#
|
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
|
-
|
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
|
-
|
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
|
|
@@ -81,9 +81,9 @@ When a routing file is passed through `[]`, it is passed as a [dynamic route](/g
|
|
81
81
|
|
82
82
|
```tsx
|
83
83
|
// routes/user/[id]/page.loader.tsx
|
84
|
-
import {
|
84
|
+
import { LoaderFunctionArgs } from '@modern-js/runtime/router';
|
85
85
|
|
86
|
-
export default async ({ params }:
|
86
|
+
export default async ({ params }: LoaderFunctionArgs) => {
|
87
87
|
const { id } = params;
|
88
88
|
const res = await fetch(`https://api/user/${id}`);
|
89
89
|
return res.json();
|
@@ -100,9 +100,9 @@ A common usage scenario is to obtain query parameters via `request`:
|
|
100
100
|
|
101
101
|
```tsx
|
102
102
|
// routes/user/[id]/page.loader.ts
|
103
|
-
import {
|
103
|
+
import { LoaderFunctionArgs } from '@modern-js/runtime/router';
|
104
104
|
|
105
|
-
export default async ({ request }:
|
105
|
+
export default async ({ request }: LoaderFunctionArgs) => {
|
106
106
|
const url = new URL(request.url);
|
107
107
|
const userId = url.searchParams.get('id');
|
108
108
|
return queryUser(userId);
|
@@ -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:
|
@@ -77,7 +77,7 @@ In order to facilitate the introduction of the relationship between `<Layout>` a
|
|
77
77
|
.
|
78
78
|
└── routes
|
79
79
|
├── blog
|
80
|
-
│
|
80
|
+
│ └── page.tsx
|
81
81
|
├── layout.tsx
|
82
82
|
├── page.tsx
|
83
83
|
└── user
|
@@ -124,9 +124,9 @@ With a file directory named `[]`, the generated route will be used as a dynamic
|
|
124
124
|
```
|
125
125
|
└── routes
|
126
126
|
├── [id]
|
127
|
-
│
|
127
|
+
│ └── page.tsx
|
128
128
|
├── blog
|
129
|
-
│
|
129
|
+
│ └── page.tsx
|
130
130
|
└── page.tsx
|
131
131
|
```
|
132
132
|
|
@@ -148,7 +148,7 @@ For example, the following directory structure:
|
|
148
148
|
└── routes
|
149
149
|
├── $.tsx
|
150
150
|
├── blog
|
151
|
-
│
|
151
|
+
│ └── page.tsx
|
152
152
|
└── page.tsx
|
153
153
|
```
|
154
154
|
|
@@ -215,9 +215,9 @@ When the component exists in the routing directory, all routing switches under t
|
|
215
215
|
.
|
216
216
|
└── routes
|
217
217
|
├── blog
|
218
|
-
│
|
219
|
-
│
|
220
|
-
│
|
218
|
+
│ ├── [id]
|
219
|
+
│ │ └── page.tsx
|
220
|
+
│ └── page.tsx
|
221
221
|
├── layout.tsx
|
222
222
|
├── loading.tsx
|
223
223
|
└── page.tsx
|
@@ -225,6 +225,22 @@ When the component exists in the routing directory, all routing switches under t
|
|
225
225
|
|
226
226
|
When a route jumps from `/` to `/blog`, if the JS Chunk of the `<Blog>` component is not loaded, the component UI exported in `loading.tsx` will be displayed first. But when jumping from `/blog` to `/blog/20220101`, it will not be displayed.
|
227
227
|
|
228
|
+
### Redirect
|
229
|
+
|
230
|
+
You can redirect routes by creating a [`data loader`](/guides/basic-features/data-fetch) file, Suppose you have the file `routes/user/page.tsx` and you want to redirect the route corresponding to this file, you can create the file `routes/user/page.loader.ts`:
|
231
|
+
|
232
|
+
```ts title="routes/user/page.loader.ts"
|
233
|
+
import { redirect } from "@edenx/runtime/router"
|
234
|
+
|
235
|
+
export default () => {
|
236
|
+
const user = await getUser();
|
237
|
+
if(!user){
|
238
|
+
return redirect('/login');
|
239
|
+
}
|
240
|
+
return null;
|
241
|
+
}
|
242
|
+
```
|
243
|
+
|
228
244
|
### ErrorBoundary
|
229
245
|
|
230
246
|
In each layer directory under `routes/`, the developer can also define a `error.tsx` file, and export a `<ErrorBoundary>` component by default.
|
@@ -14,7 +14,7 @@ From the perspective of building, Modern.js is divided into three layers, from t
|
|
14
14
|
|
15
15
|
- Upper-layer framework: Modern.js.
|
16
16
|
- Universal build engine: Modern.js Builder.
|
17
|
-
- Low-level bundlers: webpack and
|
17
|
+
- Low-level bundlers: webpack and rspack.
|
18
18
|
|
19
19
|
<img src="https://lf3-static.bytednsdoc.com/obj/eden-cn/zq-uylkvT/ljhwZthlaukjlkulzlp/builder-layers-1117.png" style={{ maxWidth: '540px' }} />
|
20
20
|
|
@@ -129,9 +129,9 @@ The bundle is generated to `dist/` by default, and the directory structure is as
|
|
129
129
|
.
|
130
130
|
├── asset-manifest.json
|
131
131
|
├── html
|
132
|
-
│
|
132
|
+
│ └── main
|
133
133
|
├── loader-routes
|
134
|
-
│
|
134
|
+
│ └── main
|
135
135
|
├── modern.config.json
|
136
136
|
├── route.json
|
137
137
|
└── static
|
@@ -149,7 +149,7 @@ export default () => {
|
|
149
149
|
然后在主应用中使用 `useModuleApp` 方法获取 `MApp` 组件, 并在主应用渲染 `MApp`。
|
150
150
|
|
151
151
|
```tsx title=主应用:App.tsx
|
152
|
-
import { useModuleApp } from '@modern-js/plugin-runtime';
|
152
|
+
import { useModuleApp } from '@modern-js/plugin-garfish/runtime';
|
153
153
|
|
154
154
|
function App() {
|
155
155
|
const { MApp } = useModuleApps();
|
@@ -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
|
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
|
|
@@ -255,23 +255,23 @@ The refactoring is complete, and the current project structure is:
|
|
255
255
|
├── package.json
|
256
256
|
├── pnpm-lock.yaml
|
257
257
|
├── src
|
258
|
-
│
|
259
|
-
│
|
260
|
-
│
|
261
|
-
│
|
262
|
-
│
|
263
|
-
│
|
264
|
-
│
|
265
|
-
│
|
266
|
-
│
|
267
|
-
│
|
268
|
-
│
|
269
|
-
│
|
270
|
-
│
|
271
|
-
│
|
272
|
-
│
|
273
|
-
│
|
274
|
-
│
|
258
|
+
│ ├── components
|
259
|
+
│ │ ├── Avatar
|
260
|
+
│ │ │ └── index.tsx
|
261
|
+
│ │ └── Item
|
262
|
+
│ │ └── index.tsx
|
263
|
+
│ ├── containers
|
264
|
+
│ │ └── Contacts.tsx
|
265
|
+
│ ├── models
|
266
|
+
│ │ └── contacts.ts
|
267
|
+
│ ├── modern-app-env.d.ts
|
268
|
+
│ ├── routes
|
269
|
+
│ │ ├── archives
|
270
|
+
│ │ │ └── page.tsx
|
271
|
+
│ │ ├── layout.tsx
|
272
|
+
│ │ └── page.tsx
|
273
|
+
│ └── styles
|
274
|
+
│ └── utils.css
|
275
275
|
└── tsconfig.json
|
276
276
|
```
|
277
277
|
|
@@ -29,29 +29,29 @@ When created, the project will look like this:
|
|
29
29
|
├── package.json
|
30
30
|
├── pnpm-lock.yaml
|
31
31
|
├── src
|
32
|
-
│
|
33
|
-
│
|
34
|
-
│
|
35
|
-
│
|
36
|
-
│
|
37
|
-
│
|
38
|
-
│
|
39
|
-
│
|
40
|
-
│
|
41
|
-
│
|
42
|
-
│
|
43
|
-
│
|
44
|
-
│
|
45
|
-
│
|
46
|
-
│
|
47
|
-
│
|
48
|
-
│
|
49
|
-
│
|
50
|
-
│
|
51
|
-
│
|
52
|
-
│
|
53
|
-
│
|
54
|
-
│
|
32
|
+
│ ├── modern-app-env.d.ts
|
33
|
+
│ ├── landing-page
|
34
|
+
│ │ └── routes
|
35
|
+
│ │ ├── index.css
|
36
|
+
│ │ ├── layout.tsx
|
37
|
+
│ │ └── page.tsx
|
38
|
+
│ └── myapp
|
39
|
+
│ ├── components
|
40
|
+
│ │ ├── Avatar
|
41
|
+
│ │ │ └── index.tsx
|
42
|
+
│ │ └── Item
|
43
|
+
│ │ └── index.tsx
|
44
|
+
│ ├── containers
|
45
|
+
│ │ └── Contacts.tsx
|
46
|
+
│ ├── models
|
47
|
+
│ │ └── contacts.ts
|
48
|
+
│ ├── routes
|
49
|
+
│ │ ├── archives
|
50
|
+
│ │ │ └── page.tsx
|
51
|
+
│ │ ├── layout.tsx
|
52
|
+
│ │ └── page.tsx
|
53
|
+
│ └── styles
|
54
|
+
│ └── utils.css
|
55
55
|
└── tsconfig.json
|
56
56
|
```
|
57
57
|
|
package/package.json
CHANGED
@@ -11,13 +11,13 @@
|
|
11
11
|
"modern",
|
12
12
|
"modern.js"
|
13
13
|
],
|
14
|
-
"version": "2.
|
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.
|
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.
|
28
|
+
"@modern-js/builder-doc": "2.7.0"
|
29
29
|
},
|
30
30
|
"scripts": {
|
31
31
|
"build": "npx ts-node ./scripts/sync.ts"
|
package/scripts/summary.en.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
[{"name":"assetPrefix","dirname":"dev"},{"name":"hmr","dirname":"dev"},{"name":"https","dirname":"dev"},{"name":"port","dirname":"dev"},{"name":"progressBar","dirname":"dev"},{"name":"startUrl","dirname":"dev"},{"name":"lazyCompilation","dirname":"experiments"},{"name":"appIcon","dirname":"html"},{"name":"crossorigin","dirname":"html"},{"name":"disableHtmlFolder","dirname":"html"},{"name":"favicon","dirname":"html"},{"name":"faviconByEntries","dirname":"html"},{"name":"inject","dirname":"html"},{"name":"injectByEntries","dirname":"html"},{"name":"meta","dirname":"html"},{"name":"metaByEntries","dirname":"html"},{"name":"mountId","dirname":"html"},{"name":"tags","dirname":"html"},{"name":"tagsByEntries","dirname":"html"},{"name":"template","dirname":"html"},{"name":"templateByEntries","dirname":"html"},{"name":"templateParameters","dirname":"html"},{"name":"templateParametersByEntries","dirname":"html"},{"name":"title","dirname":"html"},{"name":"titleByEntries","dirname":"html"},{"name":"assetPrefix","dirname":"output"},{"name":"assetsRetry","dirname":"output"},{"name":"charset","dirname":"output"},{"name":"cleanDistPath","dirname":"output"},{"name":"convertToRem","dirname":"output"},{"name":"copy","dirname":"output"},{"name":"cssModuleLocalIdentName","dirname":"output"},{"name":"dataUriLimit","dirname":"output"},{"name":"disableCssExtract","dirname":"output"},{"name":"disableCssModuleExtension","dirname":"output"},{"name":"disableFilenameHash","dirname":"output"},{"name":"disableInlineRuntimeChunk","dirname":"output"},{"name":"disableMinimize","dirname":"output"},{"name":"disableSourceMap","dirname":"output"},{"name":"disableTsChecker","dirname":"output"},{"name":"distPath","dirname":"output"},{"name":"enableAssetFallback","dirname":"output"},{"name":"enableAssetManifest","dirname":"output"},{"name":"enableCssModuleTSDeclaration","dirname":"output"},{"name":"enableInlineScripts","dirname":"output"},{"name":"enableInlineStyles","dirname":"output"},{"name":"enableLatestDecorators","dirname":"output"},{"name":"externals","dirname":"output"},{"name":"filename","dirname":"output"},{"name":"legalComments","dirname":"output"},{"name":"overrideBrowserslist","dirname":"output"},{"name":"polyfill","dirname":"output"},{"name":"svgDefaultExport","dirname":"output"},{"name":"buildCache","dirname":"performance"},{"name":"bundleAnalyze","dirname":"performance"},{"name":"chunkSplit","dirname":"performance"},{"name":"printFileSize","dirname":"performance"},{"name":"profile","dirname":"performance"},{"name":"removeConsole","dirname":"performance"},{"name":"removeMomentLocale","dirname":"performance"},{"name":"checkSyntax","dirname":"security"},{"name":"sri","dirname":"security"},{"name":"alias","dirname":"source"},{"name":"compileJsDataURI","dirname":"source"},{"name":"define","dirname":"source"},{"name":"exclude","dirname":"source"},{"name":"globalVars","dirname":"source"},{"name":"include","dirname":"source"},{"name":"moduleScopes","dirname":"source"},{"name":"preEntry","dirname":"source"},{"name":"resolveExtensionPrefix","dirname":"source"},{"name":"resolveMainFields","dirname":"source"},{"name":"autoprefixer","dirname":"tools"},{"name":"babel","dirname":"tools"},{"name":"cssExtract","dirname":"tools"},{"name":"cssLoader","dirname":"tools"},{"name":"devServer","dirname":"tools"},{"name":"htmlPlugin","dirname":"tools"},{"name":"inspector","dirname":"tools"},{"name":"less","dirname":"tools"},{"name":"minifyCss","dirname":"tools"},{"name":"postcss","dirname":"tools"},{"name":"pug","dirname":"tools"},{"name":"rspack","dirname":"tools"},{"name":"sass","dirname":"tools"},{"name":"styleLoader","dirname":"tools"},{"name":"styledComponents","dirname":"tools"},{"name":"terser","dirname":"tools"},{"name":"tsChecker","dirname":"tools"},{"name":"tsLoader","dirname":"tools"},{"name":"webpack","dirname":"tools"},{"name":"webpackChain","dirname":"tools"}]
|
1
|
+
[{"name":"assetPrefix","dirname":"dev"},{"name":"beforeStartUrl","dirname":"dev"},{"name":"hmr","dirname":"dev"},{"name":"host","dirname":"dev"},{"name":"https","dirname":"dev"},{"name":"port","dirname":"dev"},{"name":"progressBar","dirname":"dev"},{"name":"startUrl","dirname":"dev"},{"name":"lazyCompilation","dirname":"experiments"},{"name":"appIcon","dirname":"html"},{"name":"crossorigin","dirname":"html"},{"name":"disableHtmlFolder","dirname":"html"},{"name":"favicon","dirname":"html"},{"name":"faviconByEntries","dirname":"html"},{"name":"inject","dirname":"html"},{"name":"injectByEntries","dirname":"html"},{"name":"meta","dirname":"html"},{"name":"metaByEntries","dirname":"html"},{"name":"mountId","dirname":"html"},{"name":"tags","dirname":"html"},{"name":"tagsByEntries","dirname":"html"},{"name":"template","dirname":"html"},{"name":"templateByEntries","dirname":"html"},{"name":"templateParameters","dirname":"html"},{"name":"templateParametersByEntries","dirname":"html"},{"name":"title","dirname":"html"},{"name":"titleByEntries","dirname":"html"},{"name":"assetPrefix","dirname":"output"},{"name":"assetsRetry","dirname":"output"},{"name":"charset","dirname":"output"},{"name":"cleanDistPath","dirname":"output"},{"name":"convertToRem","dirname":"output"},{"name":"copy","dirname":"output"},{"name":"cssModuleLocalIdentName","dirname":"output"},{"name":"dataUriLimit","dirname":"output"},{"name":"disableCssExtract","dirname":"output"},{"name":"disableCssModuleExtension","dirname":"output"},{"name":"disableFilenameHash","dirname":"output"},{"name":"disableInlineRuntimeChunk","dirname":"output"},{"name":"disableMinimize","dirname":"output"},{"name":"disableSourceMap","dirname":"output"},{"name":"disableTsChecker","dirname":"output"},{"name":"distPath","dirname":"output"},{"name":"enableAssetFallback","dirname":"output"},{"name":"enableAssetManifest","dirname":"output"},{"name":"enableCssModuleTSDeclaration","dirname":"output"},{"name":"enableInlineScripts","dirname":"output"},{"name":"enableInlineStyles","dirname":"output"},{"name":"enableLatestDecorators","dirname":"output"},{"name":"externals","dirname":"output"},{"name":"filename","dirname":"output"},{"name":"legalComments","dirname":"output"},{"name":"overrideBrowserslist","dirname":"output"},{"name":"polyfill","dirname":"output"},{"name":"svgDefaultExport","dirname":"output"},{"name":"buildCache","dirname":"performance"},{"name":"bundleAnalyze","dirname":"performance"},{"name":"chunkSplit","dirname":"performance"},{"name":"printFileSize","dirname":"performance"},{"name":"profile","dirname":"performance"},{"name":"removeConsole","dirname":"performance"},{"name":"removeMomentLocale","dirname":"performance"},{"name":"checkSyntax","dirname":"security"},{"name":"sri","dirname":"security"},{"name":"alias","dirname":"source"},{"name":"compileJsDataURI","dirname":"source"},{"name":"define","dirname":"source"},{"name":"exclude","dirname":"source"},{"name":"globalVars","dirname":"source"},{"name":"include","dirname":"source"},{"name":"moduleScopes","dirname":"source"},{"name":"preEntry","dirname":"source"},{"name":"resolveExtensionPrefix","dirname":"source"},{"name":"resolveMainFields","dirname":"source"},{"name":"autoprefixer","dirname":"tools"},{"name":"babel","dirname":"tools"},{"name":"cssExtract","dirname":"tools"},{"name":"cssLoader","dirname":"tools"},{"name":"devServer","dirname":"tools"},{"name":"htmlPlugin","dirname":"tools"},{"name":"inspector","dirname":"tools"},{"name":"less","dirname":"tools"},{"name":"minifyCss","dirname":"tools"},{"name":"postcss","dirname":"tools"},{"name":"pug","dirname":"tools"},{"name":"rspack","dirname":"tools"},{"name":"sass","dirname":"tools"},{"name":"styleLoader","dirname":"tools"},{"name":"styledComponents","dirname":"tools"},{"name":"terser","dirname":"tools"},{"name":"tsChecker","dirname":"tools"},{"name":"tsLoader","dirname":"tools"},{"name":"webpack","dirname":"tools"},{"name":"webpackChain","dirname":"tools"}]
|