通过本章节,你可以了解到 Modern.js 中的入口约定,以及如何自定义入口。
入口(Entry)指的是一个页面的起始模块。
在 Modern.js 应用中,每一个入口对应一个独立的页面,也对应一条服务端路由。默认情况下,Modern.js 会基于目录约定来自动确定页面的入口,同时也支持通过配置项来自定义入口。
Modern.js 提供的很多配置项都是以入口为维度进行划分的,比如页面标题、HTML 模板、页面 Meta 信息、是否开启 SSR/SSG、服务端路由规则等。
Modern.js 初始化的应用是单入口的,应用结构如下:
在 Modern.js 应用中,你可以很方便的将单入口切换成多入口。在应用目录下执行 pnpm run new
,根据提示即可创建入口:
执行后,Modern.js 会自动生成一个新的入口目录,此时可以看到 src/
目录变成如下结构:
原本的入口代码被移动到了和 package.json
中 name
同名的目录下,并创建了 new-entry
入口目录。
Modern.js 会将与 package.json
文件中 name
字段同名的入口作为主入口,主入口的路由为 /
,其他入口的路由为 /{entryName}
。比如,package.json
中的 name
为 myapp
时,src/myapp
会作为应用的主入口。
你可以执行 pnpm run dev
启动开发服务,此时可以看到新增了一条名为 /new-entry
的路由,并且原有页面的路由并未发生变化。
单入口/多入口 和 SPA/MPA 的概念并不等价。前者是关于如何配置和打包应用,而后者是组织前端应用的模式,每个入口都可以是 SPA 或非 SPA 的。
不同的入口类型具有不同的编译和运行时行为。
默认情况下,Modern.js 启动应用前会对 src/
下的文件进行扫描,识别入口,并生成对应的服务端路由。
你可以通过 source.entriesDir 修改识别入口的目录。
入口所在目录必须满足以下三个条件之一:
具有 routes/
目录。
具有 App.[jt]sx?
文件。
具有 entry.[jt]sx?
文件(需要开启 source.enableCustomEntry 使用)。
当 src/
目录满足入口特征时,Modern.js 会认为当前应用为单入口应用。否则,Modern.js 会扫描 src/
下的一级目录,并进一步判断是否为入口,此时应用通常为多入口应用。
在单入口应用中,默认的入口名为 main
。
框架模式指的是需要使用 Modern.js 的框架能力,例如约定式路由、SSR、一体化调用等。这类入口约定下,应用中的入口并不是真正的编译入口。Modern.js 在启动时会生成一个封装过的入口,可以在 node_modules/.modern/[entryName]/index.js
找到真正的入口。
如果入口中存在 routes/
目录,我们称该入口为约定式路由。Modern.js 会在启动时扫描 routes/
下的文件,基于文件约定,自动生成客户端路由(react-router)。例如:
上述目录中,layout.tsx
中导出的组件会作为最外层的组件,page.tsx
中导出的组件会作为 /
路由的组件。
详细内容可以参考路由方案。
如果入口中存在 App.[jt]sx?
文件,我们称为该入口为自控式路由。例如:
以 src/App.tsx
为约定的入口,Modern.js 不会对路由做额外的操作,开发者可以使用 React Router 6 的 API 设置客户端路由,或不设置客户端路由。例如以下代码,在应用中自行设置了客户端路由:
我们推荐开发者使用约定式路由,Modern.js 默认对约定式路由做了一系列资源加载及渲染上的优化,并且提供了开箱即用的 SSR 能力。而在使用自控路由时,这些能力都需要开发者自行封装。
使用该功能需要开启 source.enableCustomEntry。
默认情况下,使用约定式路由或自控式路由时,Modern.js 会自动完成渲染。如果你希望自定义这个行为,可以通过自定义入口文件的方式来实现。
如果入口中存在 entry.[jt]sx
文件,则 Modern.js 不再控制应用的渲染流程,你可以在 entry.[jt]sx
文件中调用 createRoot
和 render
函数,完成应用入口逻辑。
上述代码中,createRoot
函数返回的组件为 routes/
目录生成或 App.tsx
导出的组件,render
函数用于处理渲染与挂载组件。例如,你希望在渲染前执行某些异步任务,可以这样实现:
使用该功能需要开启需要开启 source.enableCustomEntry。
构建模式指的是不使用 Modern.js 提供的 Runtime 能力,只使用 Modern.js 构建能力的开发模式。当应用中未安装 @modern-js/runtime
依赖时,Modern.js 会认为当前应用所有的入口都是构建模式入口。
此时,如果入口中存在 entry.[jt]sx
,则该文件会被识别为 webpack 或 Rspack 的构建入口。此时,Modern.js 不会自动生成入口代码,你需要自行将组件挂载到 DOM 节点上,例如:
在构建模式入口中,将无法使用 Modern.js 框架的运行时能力,比如:
src/routes
下文件的路由modern.config.js
文件中的 runtime
配置将不会再生效在某些情况下,你可能需要自定义入口配置,而不是使用 Modern.js 提供的入口约定。
比如你需要将一个非 Modern.js 应用迁移到 Modern.js,它并不是按照 Modern.js 的目录结构来搭建的。如果你要将它改成 Modern.js 约定的目录结构,会存在一定的迁移成本。这种情况下,你就可以使用自定义入口。
Modern.js 提供了以下配置项,你可以在 modern.config.ts 中配置它们:
下面是一个自定义入口的例子,你也可以查看相关配置项的文档来了解更多用法。
值得注意的是,默认情况下,Modern.js 认为通过配置指定的入口是框架模式入口,将自动生成真正的编译入口。如果你的应用是从 Webpack 或 Vite 等构建工具迁移到 Modern.js 框架时,你通常需要在入口配置中开启 disableMount
选项,此时 Modern.js 认为该入口是构建模式入口。
目前,如果入口所在的目录满足以下条件,也会成为应用入口。
具有 index.[jt]sx?
文件。
具有 pages/
目录。
pages/
目录为 Modern.js 旧版本中的约定式路由,新版本中推荐使用 routes/
目录。
index.[jt]sx?
在旧版本中支持应用自定义 Bootstrap 逻辑和构建模式入口,新版本中推荐使用 entry.[jt]sx?
代替。
当入口中存在 index.[jt]sx
文件,并且当文件默认导出函数时,Modern.js 会将默认的 bootstrap
函数作为入参传入,并用导出的函数替代默认的 bootstrap
,这样开发者可以自定义将组件挂载到 DOM 节点上,或在挂载前添加自定义行为。例如:
当入口目录中存在 index.[jt]sx
(即将废弃) 并且没有通过 export default
导出函数时,该入口也将被认为是构建模式入口。