@modern-js/main-doc 0.0.0-next-20221203140534 → 0.0.0-next-20221205074243

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/en/docusaurus-plugin-content-docs/current/apis/app/commands/new.md +0 -2
  3. package/en/docusaurus-plugin-content-docs/current/apis/app/runtime/core/bootstrap.md +17 -3
  4. package/en/docusaurus-plugin-content-docs/current/guides/basic-features/builder.md +46 -0
  5. package/en/docusaurus-plugin-content-docs/current.json +18 -18
  6. package/package.json +3 -3
  7. package/zh/apis/app/commands/new.md +0 -2
  8. package/zh/apis/app/runtime/app/_category_.json +1 -1
  9. package/zh/apis/app/runtime/bff/_category_.json +1 -1
  10. package/zh/apis/app/runtime/core/_category_.json +1 -1
  11. package/zh/apis/app/runtime/core/bootstrap.md +17 -3
  12. package/zh/apis/app/runtime/model/_category_.json +1 -1
  13. package/zh/apis/app/runtime/router/_category_.json +1 -1
  14. package/zh/apis/app/runtime/ssr/_category_.json +1 -1
  15. package/zh/apis/app/runtime/testing/_category_.json +1 -1
  16. package/zh/apis/app/runtime/utility/_category_.json +1 -1
  17. package/zh/apis/app/runtime/web-server/_category_.json +1 -1
  18. package/zh/configure/app/output/ssg.md +118 -114
  19. package/zh/configure/app/server/ssr.md +0 -2
  20. package/zh/guides/advanced-features/custom-app.md +8 -2
  21. package/zh/guides/advanced-features/ssg.md +74 -63
  22. package/zh/guides/advanced-features/ssr.md +76 -11
  23. package/zh/guides/basic-features/builder.md +46 -0
  24. package/zh/guides/basic-features/css/_category_.json +1 -1
  25. package/zh/guides/basic-features/css/less-sass.md +1 -14
  26. package/zh/guides/basic-features/data-fetch.md +1 -1
  27. package/zh/guides/basic-features/routes.md +32 -35
  28. package/zh/guides/concept/entries.md +4 -4
  29. package/zh/tutorials/first-app/c01-getting-started/1.2-minimal-mwa.md +2 -2
  30. package/zh/tutorials/first-app/c01-getting-started/1.4-enable-ssr.md +5 -2
  31. package/zh/tutorials/first-app/c02-generator-and-studio/2.2-boilerplates.md +4 -6
  32. package/zh/tutorials/first-app/c02-generator-and-studio/2.3-configuration.md +2 -4
  33. package/zh/tutorials/first-app/c03-ide/3.1-setting-up.md +1 -1
  34. package/zh/tutorials/first-app/c03-ide/3.2-hints-in-ide.md +44 -50
  35. package/zh/tutorials/first-app/c03-ide/3.3-autofix-in-ide.md +1 -1
  36. package/zh/tutorials/first-app/c03-ide/3.4-autofix-in-cli.md +4 -4
  37. package/zh/tutorials/first-app/c04-es6-plus-and-ts/4.1-use-es6-plus.md +8 -21
  38. package/zh/tutorials/first-app/c04-es6-plus-and-ts/4.2-use-typescript.md +37 -13
  39. package/zh/tutorials/first-app/c05-component/5.1-use-ui-library.md +3 -13
  40. package/zh/tutorials/first-app/c05-component/5.2-use-standalone-component.md +1 -21
  41. package/zh/tutorials/first-app/c06-css-and-component/6.1-css-in-js.md +9 -9
  42. package/zh/tutorials/first-app/c06-css-and-component/6.2-utility-class.md +9 -14
  43. package/zh/tutorials/first-app/c06-css-and-component/6.3-postcss.md +7 -7
  44. package/zh/tutorials/first-app/c06-css-and-component/6.4-design-system.md +1 -1
  45. package/zh/tutorials/first-app/c06-css-and-component/6.5-storybook.md +2 -2
  46. package/zh/tutorials/first-app/c06-css-and-component/6.6-testing.md +8 -17
  47. package/zh/tutorials/first-app/c07-app-entry/7.1-intro.md +23 -18
  48. package/zh/tutorials/first-app/c07-app-entry/7.2-add-entry-in-cli.md +30 -30
  49. package/zh/tutorials/first-app/c07-app-entry/7.3-manage-entries-by-hand.md +4 -9
  50. package/zh/tutorials/first-app/c08-client-side-routing/8.1-code-based-routing.md +66 -63
  51. package/zh/tutorials/first-app/c09-bff/9.2-enable-bff.md +35 -33
  52. package/zh/tutorials/first-app/c09-bff/9.3-fetch-bff.md +28 -102
  53. package/zh/tutorials/first-app/c10-model/10.1-application-architecture.md +4 -6
  54. package/zh/tutorials/first-app/c10-model/10.2-add-model.md +3 -3
  55. package/zh/tutorials/first-app/c10-model/10.3-use-model.md +21 -20
  56. package/zh/tutorials/first-app/c10-model/10.4-testing.md +2 -2
  57. package/zh/tutorials/first-app/c11-container/11.1-use-model-with-app-state.md +34 -68
  58. package/zh/tutorials/first-app/c11-container/11.2-add-container.md +40 -37
  59. package/zh/tutorials/first-app/c11-container/11.3-use-loader.md +6 -4
  60. package/zh/tutorials/first-app/c11-container/11.4-testing.md +2 -2
  61. package/zh/tutorials/foundations/introduction.md +1 -1
  62. package/en/docusaurus-plugin-content-docs/current/apis/app/runtime/default-alias.md +0 -25
  63. package/zh/apis/app/runtime/default-alias.md +0 -23
  64. package/zh/guides/basic-features/image.md +0 -43
  65. package/zh/guides/topic-detail/compile-speed.md +0 -182
  66. package/zh/guides/troubleshooting/compile.md +0 -379
  67. package/zh/tutorials/first-app/c08-client-side-routing/8.2-file-based-routing.md +0 -310
@@ -1,379 +0,0 @@
1
- ---
2
- sidebar_position: 1
3
- ---
4
-
5
- # 编译构建问题
6
-
7
- ### 如何配置 Webpack/Babel/PostCSS 等工具?
8
-
9
- 请参考 [配置底层工具](/docs/guides/advanced-features/low-level)。
10
-
11
- ### 如何自定义 HTML 模板?
12
-
13
- 请参考 [自定义 HTML 模板](/docs/guides/basic-features/html)。
14
-
15
- ### 如何提升编译构建速度?
16
-
17
- 请参考 [提升编译速度](/docs/guides/topic-detail/compile-speed)。
18
-
19
- ### 如何查看最终生效的 webpack 配置?
20
-
21
- 可以通过 [modern inspect](/docs/apis/app/commands/inspect) 命令来查看最终生效的 webpack 配置。
22
-
23
- ---
24
-
25
- ### 如何配置组件库按需引入?
26
-
27
- 默认情况下,Modern.js 内置了 antd 组件库的按需引入配置。
28
-
29
- 如果需要配置其他组件库的按需引入,可以通过 [tools.babel](/docs/configure/app/tools/babel) 配置 [babel-plugin-import](https://github.com/umijs/babel-plugin-import) 插件。
30
-
31
- ```ts title="modern.config.ts"
32
- export default defineConfig({
33
- tools: {
34
- babel: (config, { addPlugins }) => {
35
- addPlugins([
36
- [
37
- 'babel-plugin-import',
38
- {
39
- libraryName: 'xxx-components',
40
- libraryDirectory: 'es',
41
- style: true,
42
- },
43
- ],
44
- ]);
45
- },
46
- },
47
- });
48
- ```
49
-
50
- ---
51
-
52
- ### 如何移除代码中的 console?
53
-
54
- 在生产环境构建时,我们可以移除代码中的 `console`,从而避免开发环境的日志被输出到生产环境。
55
-
56
- 由于 Modern.js 默认在生产环境使用 [terser](https://github.com/terser/terser) 进行代码压缩,因此我们可以通过 [tools.terser](/docs/configure/app/tools/terser) 配置项来移除 `console`:
57
-
58
- ```js title="modern.config.ts"
59
- export default defineConfig({
60
- tools: {
61
- terser: opt => {
62
- if (typeof opt.terserOptions?.compress === 'object') {
63
- opt.terserOptions.compress.drop_console = true;
64
- }
65
- },
66
- },
67
- });
68
- ```
69
-
70
- 如果只希望移除 `console.log` 和 `console.warn`,保留 `console.error`,可以配置为:
71
-
72
- ```js title="modern.config.ts"
73
- export default defineConfig({
74
- tools: {
75
- terser: opt => {
76
- if (typeof opt.terserOptions?.compress === 'object') {
77
- opt.terserOptions.compress.pure_funcs = ['console.log', 'console.warn'];
78
- }
79
- },
80
- },
81
- });
82
- ```
83
-
84
- ---
85
-
86
- ### 如何清空 webpack 编译缓存?
87
-
88
- 默认情况下,Modern.js 的 webpack 编译缓存生成在 `./node_modules/.cache/webpack` 目录下。
89
-
90
- 如果需要清空本地的编译缓存,可以执行以下命令:
91
-
92
- ```bash
93
- rm -rf ./node_modules/.cache
94
- ```
95
-
96
- ---
97
-
98
- ### 如何配置静态资源的 CDN 路径?
99
-
100
- 如果需要将 JS、CSS 等静态资源上传到 CDN 使用,那么可以通过 [output.assetPrefix](/docs/configure/app/output/asset-prefix) 配置来设置静态资源的 URL 前缀。
101
-
102
- ```typescript title="modern.config.ts"
103
- import { defineConfig } from '@modern-js/app-tools';
104
-
105
- export default defineConfig({
106
- output: {
107
- assetPrefix: 'https://cdn.example.com/assets/',
108
- },
109
- });
110
- ```
111
-
112
- ---
113
-
114
- ### 如何在编译过程中进行 ESLint 代码校验?
115
-
116
- 出于编译性能的考虑,Modern.js 默认不会在编译过程中进行 ESLint 校验,如果需要该功能,可以手动安装并注册社区中的 [eslint-webpack-plugin](https://github.com/webpack-contrib/eslint-webpack-plugin)。
117
-
118
- 注册该插件的示例代码如下,更详细的用法请参考 [eslint-webpack-plugin](https://github.com/webpack-contrib/eslint-webpack-plugin) 文档。
119
-
120
- ```typescript title="modern.config.ts"
121
- import { defineConfig } from '@modern-js/app-tools';
122
- import ESLintPlugin from 'eslint-webpack-plugin';
123
-
124
- export default defineConfig({
125
- tools: {
126
- webpackChain(chain) {
127
- chain.plugin('eslint-plugin').use(ESLintPlugin, [
128
- {
129
- extensions: ['.js', '.ts', '.jsx', 'tsx', '.mjs'],
130
- },
131
- ]);
132
- },
133
- },
134
- });
135
- ```
136
-
137
- ---
138
-
139
- ### 如何配置 SRI 校验?
140
-
141
- 在 Modern.js 中,需要自主引入社区中的 [webpack-subresource-integrity](https://github.com/waysact/webpack-subresource-integrity) 插件来开启 SRI 校验。
142
-
143
- 配置 [webpack-subresource-integrity](https://github.com/waysact/webpack-subresource-integrity) 的示例如下:
144
-
145
- ```typescript title="modern.config.ts"
146
- import { defineConfig } from '@modern-js/app-tools';
147
- import { SubresourceIntegrityPlugin } from 'webpack-subresource-integrity';
148
-
149
- export default defineConfig({
150
- tools: {
151
- webpackChain(chain) {
152
- chain.output.crossOriginLoading('anonymous');
153
- chain.plugin('subresource-integrity').use(SubresourceIntegrityPlugin);
154
- },
155
- },
156
- });
157
- ```
158
-
159
- :::info SRI
160
- 子资源完整性 Subresource Integrity(SRI)是专门用来校验资源的一种方案,它读取资源标签中的 integrity 属性,将其中的信息摘要值,和资源实际的信息摘要值进行对比,如果发现无法匹配,那么浏览器就会拒绝执行资源。
161
-
162
- 对于 script 标签来说,结果为拒绝执行其中的代码;对于 CSS link 来说,结果为不加载其中的样式。
163
- :::
164
-
165
- ---
166
-
167
- ### Less/Sass 代码没有被正确编译?
168
-
169
- Modern.js 通过插件来编译 Less/Sass 代码,请确认你是否启用了对应的插件。
170
-
171
- - [启用 Less 插件教程](/docs/configure/app/tools/less#启用)
172
- - [启用 Sass 插件教程](/docs/configure/app/tools/sass#启用)
173
-
174
- ---
175
-
176
- ### 在 Monorepo 中引用其他模块,代码没有被正确编译?
177
-
178
- 出于编译性能的考虑,默认情况下,Modern.js 不会通过 `babel-loader` 或 `ts-loader` 来编译 `node_modules` 下的文件,也不会编译当前工程目录外部的文件。
179
-
180
- 通过 `source.include` 配置项,可以指定需要额外进行编译的目录或模块。
181
-
182
- 详见 [source.include 用法介绍](/docs/configure/app/source/include/)。
183
-
184
- ---
185
-
186
- ### 打包时出现 JavaScript heap out of memory?
187
-
188
- 该报错表示打包过程中出现了内存溢出问题,大多数情况下是由于打包的内容较多,超出了 Node.js 默认的内存上限。
189
-
190
- 如果出现 OOM 问题,最简单的方法是通过增加内存上限来解决,Node.js 提供了 `--max-old-space-size` 选项来对此进行设置。你可以在 `modern build` 命令前添加 [NODE_OPTIONS](http://nodejs.cn/api/cli/node_options_options.html) 来设置此参数:
191
-
192
- ```bash
193
- NODE_OPTIONS=--max_old_space_size=16384 modern build
194
- ```
195
-
196
- 参数的值代表内存上限大小(MB),一般情况下设置为 `16384`(16GB)即可。
197
-
198
- Node.js 官方文档中有对以下参数更详细的解释:
199
-
200
- - [NODE_OPTIONS](http://nodejs.cn/api/cli/node_options_options.html)
201
- - [--max-old-space-size](http://nodejs.cn/api/cli/max_old_space_size_size_in_megabytes.html)
202
-
203
- 除了增加内存上限,通过开启一些编译策略来提升效率也是一个解决方案,详见 [提升编译速度](/docs/guides/topic-detail/compile-speed)。
204
-
205
- ---
206
-
207
- ### webpack 编译出现 'compilation' argument 报错?
208
-
209
- 如果编译时出现以下报错,通常是由于项目中安装了错误的 webpack 版本,或者安装了多个 webpack 版本引起:
210
-
211
- ```bash
212
- TypeError: The 'compilation' argument must be an instance of Compilation
213
- ```
214
-
215
- webpack 版本问题有以下几种情况:
216
-
217
- 1. 项目的 package.json 中直接声明了 webpack 依赖,并且与 Modern.js 依赖的 webpack 版本范围不同,无法匹配到同一个版本。
218
- 2. 项目里安装的多个 npm 包都依赖了 webpack,并且它们依赖的 webpack 版本范围不同,无法匹配到同一个版本。
219
- 3. 由于包管理器的 lock 机制,导致 lock 文件中产生了多个 webpack 版本。
220
-
221
- 如果是第一种情况,建议从项目的 package.json 中移除 webpack 依赖。因为 Modern.js 默认封装了 webpack 相关能力,并且会在 `tools.webpack` 配置项中传入 webpack 对象。因此在大多数情况下,不建议在项目中额外安装 webpack 依赖。
222
-
223
- 如果是第二种情况,建议看看能否升级某个 npm 包,使其依赖的 webpack 版本范围与 Modern.js 保持一致。也可以通过包管理器的能力来手动统一版本,比如使用 [yarn resolutions](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/) 或 [pnpm overrides](https://pnpm.io/package_json#pnpmoverrides)。
224
-
225
- 如果是第三种情况,可以使用第二种情况中提到的两种方法,也可以尝试删除 lock 文件后重新安装来解决。
226
-
227
- :::info
228
- 删除 lock 文件会使项目中的依赖版本自动升级到指定范围下的最新版,请进行充分的测试。
229
- :::
230
-
231
- ---
232
-
233
- ### Less 文件中的除法不生效?
234
-
235
- Less v4 版本与 v3 版本相比,除法的写法有一些区别:
236
-
237
- ```less
238
- // Less v3
239
- .math {
240
- width: 2px / 2; // 1px
241
- width: 2px ./ 2; // 1px
242
- width: (2px / 2); // 1px
243
- }
244
-
245
- // Less v4
246
- .math {
247
- width: 2px / 2; // 2px / 2
248
- width: 2px ./ 2; // 1px
249
- width: (2px / 2); // 1px
250
- }
251
- ```
252
-
253
- Modern.js 内置的 Less 版本为 v4,低版本的写法不会生效,请注意区分。
254
-
255
- Less 中除法的写法也可以通过配置项来修改,详见 [Less - Math](https://lesscss.org/usage/#less-options-math)。
256
-
257
- ---
258
-
259
- ### 编译产物中存在未编译的 ES6+ 代码?
260
-
261
- 默认情况下,Modern.js 不会通过 `babel-loader` 或 `ts-loader` 来编译 `node_modules` 下的文件。如果项目引入的 npm 包中含有 ES6+ 语法,会被打包进产物中。
262
-
263
- 遇到这种情况时,可以通过 [source.include](/docs/configure/app/source/include) 配置项来指定需要额外进行编译的目录或模块。
264
-
265
- ---
266
-
267
- ### 编译时报错 `You may need additional loader`?
268
-
269
- 如果编译过程中遇到了以下报错提示,表示存在个别文件无法被正确编译。
270
-
271
- ```bash
272
- Module parse failed: Unexpected token
273
- File was processed with these loaders:
274
- * some-loader/index.js
275
-
276
- You may need an additional loader to handle the result of these loaders.
277
- ```
278
-
279
- 解决方法:
280
-
281
- - 如果是引用了当前工程外部的 `.ts` 文件,或者是 node_modules 下的 `.ts` 文件,请添加 [source.include](/docs/configure/app/source/include) 配置项,指定需要额外进行编译的文件。
282
- - 如果是引用了 Modern.js 不支持的文件格式,请自行配置对应的 webpack loader 进行编译。
283
-
284
- ---
285
-
286
- ### 打开页面后报错,提示 exports is not defined?
287
-
288
- 如果编译正常,但是打开页面后出现 `exports is not defined` 报错,通常是因为在项目中使用 babel 编译了一个 CommonJS 模块,导致 babel 出现异常。
289
-
290
- 在正常情况下,Modern.js 是不会使用 babel 来编译 CommonJS 模块的。如果项目中使用了 `source.include` 配置项,或使用了 `tools.babel` 的 `addIncludes` 方法,则可能会把一些 CommonJS 模块加入到 babel 编译中。
291
-
292
- 该问题有两种解决方法:
293
-
294
- 1. 避免将 CommonJS 模块加入到 babel 编译中。
295
- 2. 将 babel 的 `sourceType` 配置项设置为 `unambiguous`,示例如下:
296
-
297
- ```js
298
- export default defineConfig({
299
- tools: {
300
- babel(config) {
301
- config.sourceType = 'unambiguous';
302
- },
303
- },
304
- });
305
- ```
306
-
307
- 将 `sourceType` 设置为 `unambiguous` 可能会产生一些其他影响,请参考 [babel 官方文档](https://babeljs.io/docs/en/options#sourcetype)。
308
-
309
- ---
310
-
311
- ### 打包后发现 Tree Shaking 没有生效?
312
-
313
- Modern.js 在生产构建时会默认开启 webpack 的 Tree Shaking 功能,Tree Shaking 是否能够生效,取决于业务代码能否满足 webpack 的 Tree Shaking 条件。
314
-
315
- 如果你遇到了 Tree Shaking 不生效的问题,可以检查下相关 npm 包的 `sideEffects` 配置是否正确,如果不了解 `sideEffects` 是什么,可以阅读以下两篇文档:
316
-
317
- - [webpack 官方文档 - Tree Shaking](https://webpack.docschina.org/guides/tree-shaking/)
318
- - [Tree Shaking 问题排查指南](https://bytedance.feishu.cn/docs/doccn8E1ldDct5uv1EEDQs8Ycwe)
319
-
320
- ---
321
-
322
- ### 热更新后 React 组件的 state 丢失?
323
-
324
- Modern.js 使用 React 官方的 [Fast Refresh](https://github.com/pmmmwh/react-refresh-webpack-plugin) 能力来进行组件热更新。
325
-
326
- 在使用 Fast Refresh 时,要求组件不能为匿名函数,否则热更新后无法保留 React 组件的 state。
327
-
328
- 以下写法都是不正确的:
329
-
330
- ```js
331
- // 错误写法 1
332
- export default function () {
333
- return <div>Hello World</div>;
334
- }
335
-
336
- // 错误写法 2
337
- export default () => <div>Hello World</div>;
338
- ```
339
-
340
- 正确的写法为:
341
-
342
- ```js
343
- // 正确写法 1
344
- export default function MyComponent() {
345
- return <div>Hello World</div>;
346
- }
347
-
348
- // 正确写法 2
349
- const MyComponent = () => <div>Hello World</div>
350
-
351
- export default MyComponent;
352
- ```
353
-
354
- ---
355
-
356
- ### webpack 编译缓存未生效,应该如何排查?
357
-
358
- Modern.js 默认开启了 webpack 的持久化缓存。
359
-
360
- 首次编译完成后,会自动生成缓存文件,并输出到 `./node_modules/.cache/webpack` 目录下。执行第二次编译时,会命中缓存,并大幅度提高编译速度。
361
-
362
- 当 `modern.config.ts` 或 `package.json` 等配置文件被修改时,缓存会自动失效。
363
-
364
- 如果项目中 webpack 编译缓存一直未生效,可以添加以下配置进行排查:
365
-
366
- ```ts
367
- export default defineConfig({
368
- tools: {
369
- webpack(config) {
370
- config.infrastructureLogging = {
371
- ...config.infrastructureLogging,
372
- debug: true,
373
- };
374
- },
375
- },
376
- });
377
- ```
378
-
379
- 添加以上配置后,webpack 会输出日志用于 debug,请参考 `PackFileCacheStrategy` 相关的日志来了解缓存失效的原因。
@@ -1,310 +0,0 @@
1
- ---
2
- title: 使用约定式路由​​​​
3
- ---
4
-
5
- 上一小节中,我们学习了如何使用【 自控式路由 】方式实现客户端路由。
6
-
7
- 这一小节中,我们将在 landing-page 入口里,学习使用【 约定式路由 】。
8
-
9
- 我们首先将 `landing-page` 入口的**标识** `App.tsx` 删除,换成另一种符合约定的**标识** `pages/`。
10
-
11
- 我们在终端执行以下代码修改 `landing-page` 文件内容:
12
-
13
- import Tabs from '@theme/Tabs';
14
- import TabItem from '@theme/TabItem';
15
-
16
- <Tabs>
17
- <TabItem value="macOS" label="macOS" default>
18
-
19
- ```bash
20
- rm src/landing-page/App.tsx src/landing-page/App.css
21
- mkdir -p src/landing-page/pages/
22
- touch src/landing-page/pages/_app.tsx src/landing-page/pages/index.tsx src/landing-page/pages/docs.tsx
23
- ```
24
-
25
- </TabItem>
26
- <TabItem value="Windows" label="Windows">
27
-
28
- ```powershell
29
- rm src/landing-page/App.tsx
30
- rm src/landing-page/App.css
31
- mkdir -p src/landing-page/pages/
32
- ni src/landing-page/pages/_app.tsx
33
- ni src/landing-page/pages/index.tsx
34
- ni src/landing-page/pages/docs.tsx
35
- ```
36
-
37
- </TabItem>
38
- </Tabs>
39
-
40
-
41
- `pages/` 跟 `App.tsx` 一样,都起到入口**标识**的作用,让 `src/landing-page` 被识别为入口。
42
-
43
- 如果存在 `App.tsx` 则优先使用 `App.tsx` 作为编译入口。而 `pages/` 则默认启用【 约定式路由 】的客户端路由实现方式,`pages/` 中的文件路径和文件内容,将被自动自动转换成客户端路由逻辑。
44
-
45
- 执行命令后,项目结构如下:
46
-
47
- ```md
48
- .
49
- ├── .vscode/
50
- │ ├── extensions.json
51
- │ └── settings.json
52
- ├── src/
53
- │ ├── contacts/
54
- │ │ ├── components/
55
- │ │ │ ├── Avatar/
56
- │ │ │ │ ├── index.stories.tsx
57
- │ │ │ │ └── index.tsx
58
- │ │ │ └── Item/
59
- │ │ │ ├── index.test.tsx
60
- │ │ │ └── index.tsx
61
- │ │ ├── styles/
62
- │ │ │ └── utils.css
63
- │ │ ├── App.css
64
- │ │ └── App.tsx
65
- │ ├── landing-page/
66
- │ │ └── pages/
67
- │ │ ├── _app.tsx
68
- │ │ ├── docs.tsx
69
- │ │ └── index.tsx
70
- │ ├── .eslintrc.json
71
- │ └── modern-app-env.d.ts
72
- ├── .editorconfig
73
- ├── .gitignore
74
- ├── .npmrc
75
- ├── .nvmrc
76
- ├── README.md
77
- ├── package.json
78
- ├── pnpm-lock.yaml
79
- └── tsconfig.json
80
- ```
81
-
82
- 注:以上展示的是手动创建入口的方式。
83
-
84
- 以下介绍自动启用方式,开发者可在自己的项目中尝试:
85
-
86
- 在 modern.js 项目中,执行`pnpm run new`命令, 按照以下选项选择,实现创建入口时,自动启用【 约定式路由 】:
87
-
88
- ```bash
89
- # 请选择你想要的操作:
90
- ❯ 新建「应用入口」
91
-
92
- #填写入口名称:
93
- landing-page
94
- ```
95
-
96
- 假设这个 `landing-page` 入口是一个简单的有导航栏的落地页,包含两个子页面:一个首页和一个文档页,我们用客户端路由的方式来区别这两个子页面。
97
-
98
- 我们先分别实现这个入口两个子页面的内容,`src/landing-page/pages/index.tsx` 是首页,内容为:
99
-
100
- ```js
101
- import { Helmet } from '@modern-js/runtime/head';
102
-
103
- const Index = () => (
104
- <>
105
- <Helmet>
106
- <title>Home</title>
107
- </Helmet>
108
- <p>
109
- Welcome to <a href="/contacts">Contact List</a>!
110
- </p>
111
- </>
112
- );
113
-
114
- export default Index;
115
- ```
116
-
117
- `src/landing-page/pages/docs.tsx` 是文档页,内容为:
118
-
119
- ```js
120
- import { Helmet } from '@modern-js/runtime/head';
121
-
122
- const Docs = () => (
123
- <>
124
- <Helmet>
125
- <title>Docs</title>
126
- </Helmet>
127
- <p>I am docs</p>
128
- </>
129
- );
130
-
131
- export default Docs;
132
- ```
133
-
134
- 最后,`src/landing-page/pages/_app.tsx` 是下划线开头的,代表这是【 约定式路由 】中一个特殊的功能文件,为整个入口提供根组件,可以用于实现全局布局、公共 UI 等。
135
-
136
- 在这里,我们只实现一个简单的导航和结构:
137
-
138
- ```js
139
- import { ComponentType } from 'react';
140
- import { NavLink } from '@modern-js/runtime/router';
141
-
142
- const App = ({ Component, ...pageProps }: { Component: ComponentType }) => (
143
- <div>
144
- <h2>Nav:</h2>
145
- <ul>
146
- <li>
147
- <NavLink
148
- to="/"
149
- exact={true}
150
- activeStyle={{
151
- color: '#f60',
152
- }}>
153
- Home
154
- </NavLink>
155
- </li>
156
- <li>
157
- <NavLink
158
- to="/docs"
159
- activeStyle={{
160
- color: '#f60',
161
- }}>
162
- Docs
163
- </NavLink>
164
- </li>
165
- </ul>
166
- <h2>Content:</h2>
167
- <Component {...pageProps} />
168
- </div>
169
- );
170
-
171
- export default App;
172
- ```
173
-
174
- 执行 `pnpm run dev`,访问 `http://localhost:8080/landing-page/`,可以看到结果:
175
-
176
- ![result](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/08/result.png)
177
-
178
- 点击 Nav 里的链接,URL 变为 `http://localhost:8080/landing-page/docs`,内容会变为:
179
-
180
- ![result1](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/08/result1.png)
181
-
182
- 我们同样可以开启/关闭 SSR 选项([配置教程](/docs/configure/app/server/ssr)),并查看 HTML 源码。结果和【 自控式路由 】的 contacts 入口一样。
183
-
184
- :::info 注
185
- Modern.js Lint 规则集要求 React 组件的文件名或目录名都用 Pascal 命名风格,跟组件本身的名字保持一致,首字母大写。
186
-
187
- `pages/` 里面的文件虽然也是 React 组件,但它们是基于约定用于指定路由的特殊组件文件,对应的是 URL 中的路径,所以这里是一种例外情况,文件名/目录名跟 [URL 命名风格](https://geemus.gitbooks.io/http-api-design/content/en/requests/downcase-paths-and-attributes.html)保持一致更好,最好用 dash 命名风格(全小写,- 连字符分隔)。
188
- :::
189
-
190
- 接下来我们再实现一个简单的评论详情页,因为评论会有很多条,所以评论详情页的 URL 包含动态部分,例如:`http://localhost:8080/landing-page/docs/comments/:commentTitle/`
191
-
192
- 对于像 `:commentTitle` 这样的动态部分,Modern.js 提供了一种特殊的文件命名方式来实现。
193
-
194
- 执行以下命令,新建以下文件:
195
-
196
- <Tabs>
197
- <TabItem value="macOS" label="macOS" default>
198
-
199
- ```bash
200
- mkdir -p src/landing-page/pages/comments/\[commentTitle\]
201
- touch src/landing-page/pages/comments/\[commentTitle\]/index.tsx
202
- ```
203
-
204
- </TabItem>
205
- <TabItem value="Windows" label="Windows">
206
-
207
- ```powershell
208
- mkdir -p src/landing-page/pages/comments/[commentTitle]
209
- ni src/landing-page/pages/comments/[commentTitle\/index.tsx
210
- ```
211
-
212
- </TabItem>
213
- </Tabs>
214
-
215
- `landing-page` 入口中的文件结构变成:
216
-
217
- ```md
218
- .
219
- └── pages/
220
- ├── comments/
221
- │ └── [commentTitle]/
222
- │ └── index.tsx
223
- ├── _app.tsx
224
- ├── docs.tsx
225
- └── index.tsx
226
- ```
227
-
228
- `[commentTitle]` 将会被 Modern.js 转换成动态路由。
229
-
230
- 我们首先安装文件中需要的依赖:
231
-
232
- ```bash
233
- pnpm add lodash
234
- pnpm add -D @types/lodash
235
- ```
236
-
237
- `pages/comments/[commentTitle]/index.tsx` 的内容为:
238
-
239
- ```js
240
- import { Helmet } from '@modern-js/runtime/head';
241
- import { Link } from '@modern-js/runtime/router';
242
- import _ from 'lodash';
243
-
244
- const Index = ({ match: { params } }: any) => {
245
- const title = _.startCase(params.commentTitle);
246
- return (
247
- <>
248
- <Helmet>
249
- <title>Comment: {title}</title>
250
- </Helmet>
251
- <p>
252
- <Link to="/docs/">{'< Back'}</Link>
253
- </p>
254
- <h1>Subject: {title}</h1>
255
- <p>Post: I am a comment</p>
256
- </>
257
- );
258
- };
259
-
260
- export default Index;
261
- ```
262
-
263
- 修改 `docs.tsx`,添加跳转到评论页的链接:
264
-
265
- ```js
266
- import { Helmet } from '@modern-js/runtime/head';
267
- import { Link } from '@modern-js/runtime/router';
268
-
269
- const Docs = () => (
270
- <>
271
- <Helmet>
272
- <title>Docs</title>
273
- </Helmet>
274
- <p>I am docs</p>
275
- <p>
276
- <Link to="/comments/i-am-a-comment-title">[Random comment]</Link>
277
- </p>
278
- </>
279
- );
280
-
281
- export default Docs;
282
- ```
283
-
284
- :::info 注
285
- `pages/` 和 `App.tsx` 一样,应该专注于路由的组织,具体的 UI 实现和业务逻辑,一旦复杂到要拆分成多个文件的程度,应该放到 `pages/` 外面,在同一个应用入口目录中,用 **feature 目录**、**role 目录**的方式来组织。
286
-
287
- 例如使用 `src/landing-page/docs/components/Article/index.tsx` 来组织功能特性。
288
-
289
- `landing-page/docs/` 和 `landing-page/pages/docs/` 不同,前者是 **feature 目录**,将修改频率不同或由不同人负责开发的业务逻辑,封装在同一个黑盒里,这种目录下的问题与具体路由解耦。
290
-
291
- `pages/` 目录里的组件文件,负责把这些 feature 组件组织到一起,通过特定的路由结构提供给用户。
292
-
293
- 因此 `pages/` 目录里基本上不应该有组件之外的文件,也不应该有过于复杂和具体的实现。
294
- :::
295
-
296
- 执行 `pnpm run dev`,访问 `http://localhost:8080/landing-page/docs/`,可以看到效果如下:
297
-
298
- ![result2](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/08/result2.png)
299
-
300
- 点击评论链接,跳转到 `http://localhost:8080/landing-page/comments/i-am-a-comment-title`,效果如下:
301
-
302
- ![result3](https://lf3-static.bytednsdoc.com/obj/eden-cn/aphqeh7uhohpquloj/modern-js/docs/08/result3.png)
303
-
304
- URL 中的动态部分,在代码中被转换成了标题内容,修改最后部分 URL 后重新访问,标题内容同样发生改变。
305
-
306
- 本小节中,我们学习了基本的【 约定式路由 】用法,除了 `_app.tsx` 外,我们还可以使用 [`_layout.tsx`](/docs/apis/app/hooks/src/pages#部分-layout) 实现这个访问路径下的公共 UI,可以用 [`404.tsx`](/docs/apis/app/hooks/src/pages#404-路由) 自定义 404 页面等。
307
-
308
- ---
309
-
310
- > 本小节的代码可以在[这里查看](https://github.com/modern-js-dev/modern-js-examples/tree/main/tutorials/c08/hello-modern-2)。