From 2e9f738ab5a42cdee5be24f1084395017c72d25e Mon Sep 17 00:00:00 2001 From: wangyiming Date: Tue, 2 Dec 2025 17:36:53 +0800 Subject: [PATCH 1/5] docs: overiew of break changes --- .../en/guides/basic-features/render/ssg.mdx | 5 +- packages/document/docs/zh/guides/_meta.json | 7 +- .../zh/guides/basic-features/render/ssg.mdx | 5 +- .../docs/zh/guides/upgrade/_meta.json | 1 + .../docs/zh/guides/upgrade/config.mdx | 695 ++++++++++++++++++ .../document/docs/zh/guides/upgrade/entry.mdx | 468 ++++++++++++ .../docs/zh/guides/upgrade/overview.mdx | 36 + 7 files changed, 1212 insertions(+), 5 deletions(-) create mode 100644 packages/document/docs/zh/guides/upgrade/_meta.json create mode 100644 packages/document/docs/zh/guides/upgrade/config.mdx create mode 100644 packages/document/docs/zh/guides/upgrade/entry.mdx create mode 100644 packages/document/docs/zh/guides/upgrade/overview.mdx diff --git a/packages/document/docs/en/guides/basic-features/render/ssg.mdx b/packages/document/docs/en/guides/basic-features/render/ssg.mdx index 0ee674528140..6bc4aa02a88e 100644 --- a/packages/document/docs/en/guides/basic-features/render/ssg.mdx +++ b/packages/document/docs/en/guides/basic-features/render/ssg.mdx @@ -27,11 +27,12 @@ export default defineConfig({ }); ``` -::::info Scope +:::info - Use `output.ssg` for single-entry apps. - Use `output.ssgByEntries` for multi-entry apps. - If `output.ssg` is `true` and `output.ssgByEntries` is not set, all routes under all entries are treated as SSG routes. -:::: + +::: ## Development Debugging diff --git a/packages/document/docs/zh/guides/_meta.json b/packages/document/docs/zh/guides/_meta.json index e978ec327731..4e99d86b2ae0 100644 --- a/packages/document/docs/zh/guides/_meta.json +++ b/packages/document/docs/zh/guides/_meta.json @@ -29,5 +29,10 @@ "name": "troubleshooting", "label": "troubleshooting" }, - "deprecated" + "deprecated", + { + "type": "dir", + "name": "upgrade", + "label": "从 Modern.js 2.0 升级" + } ] diff --git a/packages/document/docs/zh/guides/basic-features/render/ssg.mdx b/packages/document/docs/zh/guides/basic-features/render/ssg.mdx index fb1fb0a5552f..fe849cfdc728 100644 --- a/packages/document/docs/zh/guides/basic-features/render/ssg.mdx +++ b/packages/document/docs/zh/guides/basic-features/render/ssg.mdx @@ -28,11 +28,12 @@ export default defineConfig({ }); ``` -::::info 适用范围 +:::info 适用范围 - 单入口请使用 `output.ssg`。 - 多入口请使用 `output.ssgByEntries`。 - 当仅设置 `output.ssg: true` 且未配置 `output.ssgByEntries` 时,所有入口下的所有路由都会作为 SSG 路由处理。 -:::: + +::: ## 开发环境调试 diff --git a/packages/document/docs/zh/guides/upgrade/_meta.json b/packages/document/docs/zh/guides/upgrade/_meta.json new file mode 100644 index 000000000000..02846b13b9ca --- /dev/null +++ b/packages/document/docs/zh/guides/upgrade/_meta.json @@ -0,0 +1 @@ +["overview", "config", "entry"] diff --git a/packages/document/docs/zh/guides/upgrade/config.mdx b/packages/document/docs/zh/guides/upgrade/config.mdx new file mode 100644 index 000000000000..b754a6e3961c --- /dev/null +++ b/packages/document/docs/zh/guides/upgrade/config.mdx @@ -0,0 +1,695 @@ +# 配置变化 + +本篇文档主要介绍从 Modern.js 2.0 升级到 3.0 时,配置项层面的不兼容变更以及推荐的迁移方式。 + +## html + +### html.appIcon + +**变更内容**: 不再支持字符串形式,必须使用对象格式。 + +**V2 类型**: +```typescript +type AppIconItem = { + src: string; + size: number; + target?: 'apple-touch-icon' | 'web-app-manifest'; +}; + +type AppIcon = string | { + name?: string; + icons: AppIconItem[]; + filename?: string; +}; +``` + +**V3 类型**: +```typescript +type AppIconItem = { + src: string; + size: number; + target?: 'apple-touch-icon' | 'web-app-manifest'; +}; + +type AppIcon = { + name?: string; + icons: AppIconItem[]; + filename?: string; +}; +``` + +**迁移示例**: +```typescript +// v2 +export default { + html: { + appIcon: './src/assets/icon.png', + }, +}; + +// v3 +export default { + html: { + appIcon: { + icons: [{ + src: './src/assets/icon.png', + size: 180 + }] + } + }, +}; +``` + +### html.xxxByEntries + +**变更内容**: `metaByEntries`、`templateParametersByEntries`、`injectByEntries`、`tagsByEnties`、`faviconByEntries`、`templateByEnties`、`titleByEntries` 等配置已废弃,需要使用函数语法代替。 + +**处理步骤**: +1. 移除相关配置 +2. 使用 `html.xxx` 的函数用法代替 + +**迁移示例**: +```typescript +// v2 +export default { + html: { + metaByEntries: { + foo: { + description: 'TikTok', + }, + // 其他配置... + }, + }, +}; + +// v3 +export default { + html: { + meta({ entryName }) { + switch (entryName) { + case 'foo': + return { + description: 'TikTok', + }; + // 其他配置... + } + }, + }, +}; +``` + +### html.disableHtmlFolder + +**变更内容**: 该配置已废弃,使用 `html.outputStructure` 代替。 + +**迁移示例**: +```typescript +// v2 - 等同于 html.outputStructure 配置为 nested +export default { + html: { + disableHtmlFolder: true, + }, +}; + +// v3 +export default { + html: { + outputStructure: 'flat', + }, +}; +``` + +## output + +### output.overrideBrowserslist + +**变更内容**: 需要根据项目现有配置情况处理。 + +**处理步骤**: +1. 检查项目中是否有 `.browserslistrc` 文件 +2. 检查 `edenx.config.[ts|js]` 中是否配置了 `output.overrideBrowserslist` +3. 检查 package.json 中是否配置了 browserslist + +如果都没有,则创建 `.browserslistrc` 文件,内容为支持 ES6 的浏览器: + +```typescript +chrome >= 51 +edge >= 15 +firefox >= 54 +safari >= 10 +ios_saf >= 10 +``` + +### output.enableAssetFallback + +**变更内容**: 该配置已废弃,注释掉并添加说明。 + +```typescript +// 该配置已废弃,如有问题请咨询 oncall 解决 +// output: { +// enableAssetFallback: true, +// }, +``` + +### output.cssModuleLocalIdentName + +**变更内容**: 该配置已废弃,使用 `output.cssModules.localIdentName` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + cssModuleLocalIdentName: '[path][name]__[local]-[hash:base64:6]', + }, +}; + +// v3 +export default { + output: { + cssModules: { + localIdentName: '[path][name]__[local]-[hash:base64:6]', + }, + }, +}; +``` + +### output.disableCssExtract + +**变更内容**: 该配置已废弃,使用 `output.injectStyles` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + disableCssExtract: true, + }, +}; + +// v3 +export default { + output: { + injectStyles: true, + }, +}; +``` + +### output.disableFilenameHash + +**变更内容**: 该配置已废弃,使用 `output.filenameHash` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + disableFilenameHash: true, + }, +}; + +// v3 +export default { + output: { + filenameHash: false, + }, +}; +``` + +### output.disableMinimize + +**变更内容**: 该配置已废弃,使用 `output.minify` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + disableMinimize: true, + }, +}; + +// v3 +export default { + output: { + minify: false, + }, +}; +``` + +### output.disableSourceMap + +**变更内容**: 该配置已废弃,使用 `output.sourceMap` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + disableSourceMap: true, + }, +}; + +// v3 +export default { + output: { + sourceMap: false, + }, +}; +``` + +### output.enableInlineScripts + +**变更内容**: 该配置已废弃,使用 `output.inlineScripts` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + enableInlineScripts: true, + }, +}; + +// v3 +export default { + output: { + inlineScripts: true, + }, +}; +``` + +### output.enableInlineStyles + +**变更内容**: 该配置已废弃,使用 `output.inlineStyles` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + enableInlineStyles: true, + }, +}; + +// v3 +export default { + output: { + inlineStyles: true, + }, +}; +``` + +### output.enableLatestDecorators + +**变更内容**: 该配置已废弃,使用 `source.decorators` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + enableLatestDecorators: true, + }, +}; + +// v3 +export default { + source: { + decorators: { + version: '2022-03', + }, + }, +}; +``` + +### output.disableNodePolyfill + +**变更内容**: 该配置已废弃,通过注册 `pluginNodePolyfill` 代替。 + +**迁移示例**: +```typescript +// v2 +export default { + output: { + disableNodePolyfill: false, + }, +}; + +// v3 +import { pluginNodePolyfill } from "@rsbuild/plugin-node-polyfill"; +export default { + builderPlugins: [ + pluginNodePolyfill() + ] +}; +``` + +## source + +### source.resolveMainFields + +**变更内容**: 该配置已废弃,使用 `resolve.mainFields` 代替。 + +**迁移示例**: +```typescript +// v2 +source: { + resolveMainFields: ['custom', 'module', 'main'] +} + +// v3 +resolve: { + mainFields: ['custom', 'module', 'main'] +} +``` + +### source.resolveExtensionPrefix + +**变更内容**: 该配置已废弃,使用 `resolve.extensions` 代替。 + +**迁移示例**: +```typescript +// v2 +source: { + resolveExtensionPrefix: ['.ts', '.tsx', '.js'] +} + +// v3 +resolve: { + extensions: ['.ts', '.tsx', '.js'] +} +``` + +### source.moduleScopes + +**变更内容**: 该配置已废弃,直接移除。 + +### source.enableCustomEntry + +**变更内容**: 该配置已废弃,直接移除。 + +## tools + +### tools.esbuild + +**变更内容**: 该配置已废弃,需要手动切换到 esbuild 压缩。 + +```typescript +// 该配置已废弃,请参考 [切换压缩器](https://rsbuild.rs/zh/config/output/minify#%E5%88%87%E6%8D%A2%E5%8E%8B%E7%BC%A9%E5%99%A8) 来手动切换到 esbuild 压缩 +// tools: { +// esbuild: { /* 配置 */ } +// }, +``` + +### tools.terser + +**变更内容**: 该配置已废弃,需要手动切换到 Terser 压缩。 + +```typescript +// 该配置已废弃,请参考 [切换压缩器](https://rsbuild.rs/zh/config/output/minify#%E5%88%87%E6%8D%A2%E5%8E%8B%E7%BC%A9%E5%99%A8) 来手动切换到 Terser 压缩 +// tools: { +// terser: { /* 配置 */ } +// }, +``` + +### tools.devServer + +**变更内容 1**: `after`、`before`、`devMiddleware` 配置已废弃,使用 `dev` 配置代替。 + +**迁移示例**: +```typescript +// v2 +export default { + tools: { + devServer: { + before: [...], + after: [...], + devMiddleware: { + writeToDisk: true + } + } + } +}; + +// v3 +export default { + dev: { + setupMiddlewares: [...], + writeToDisk: true + } +}; +``` + +**变更内容 2**: `client`、`https`、`liveReload` 配置已废弃,使用对应的 `dev.client`、`dev.https`、`dev.liveReload` 配置代替。 + +**迁移示例**: +```typescript +// v2 +export default { + tools: { + devServer: { + client: { + port: 8081 + } + } + } +}; + +// v3 +export default { + dev: { + client: { + port: 8081 + } + } +}; +``` + +**变更内容 3**: `hot` 配置已废弃,使用 `dev.hmr` 配置代替。 + +**迁移示例**: +```typescript +// v2 +export default { + tools: { + devServer: { + hot: false + } + } +}; + +// v3 +export default { + dev: { + hmr: false + } +}; +``` + +## dev + +### dev.port + +**变更内容**: 该配置已被移除,改为 `server.port`。 + +**迁移示例**: +```typescript +// 改动前 +dev: { + port: 8080 +} + +// 改动后 +server: { + port: process.env.NODE_ENV === 'development' && 8080 +} +``` + +## runtime + +### runtime.router + +**变更内容**: 不再需要,可以直接移除。 + +### runtime.state + +**变更内容**: 该配置被废弃,建议使用第三方状态管理库。 + +## experiments + +### experiments.lazyCompilation + +**变更内容**: 该配置已废弃,改为 `dev.lazyCompilation`。 + +**迁移示例**: +```typescript +// v2 +experiments: { + lazyCompilation: true +} + +// v3 +dev: { + lazyCompilation: true +} +``` + +## plugins + +### autoLoadPlugins + +**变更内容**: 该配置已被废弃,需要手动注册插件。 + +**处理步骤**: +1. 移除 `autoLoadPlugins` 配置 +2. 手动导入并注册需要使用的插件 + +**支持的插件变量名**: +- `@edenx/app-tools`: `appTools` +- `@edenx/plugin-slardar-web`: `slardarWebPlugin` +- `@edenx/plugin-i18n`: `i18nPlugin` +- `@edenx/plugin-starling-intl`: `starlingIntlPlugin` +- `@edenx/plugin-bff`: `bffPlugin` +- `@edenx/plugin-gulu`: `guluPlugin` +- `@edenx/plugin-gulux`: `guluxPlugin` +- `@edenx/plugin-ssg`: `ssgPlugin` +- `@edenx/plugin-garfish`: `garfishPlugin` + +**迁移示例**: +```typescript +// v2 - 自动加载插件 +export default { + autoLoadPlugins: true +} + +// v3 - 手动注册插件 +import { defineConfig, appTools } from '@edenx/app-tools'; +import { i18nPlugin } from '@edenx/plugin-i18n'; +import { ssgPlugin } from '@edenx/plugin-ssg'; + +export default defineConfig({ + plugins: [ + appTools(), + i18nPlugin(), + ssgPlugin() + ] +}) +``` + +### app-tools 插件 + +**变更内容**: 该插件不需要传入任何参数。 + +**迁移示例**: +```typescript +// v2 +plugins: [ + appTools({ + bundler: 'rspack' + }) +], + +// v3 +plugins: [ + appTools() +], +``` + +### plugin-gecko + +**变更内容**: 按以下步骤处理 + +**处理步骤**: +1. 检测 `edenx.config.[tj]s` 中是否有注册 `@edenx/plugin-gecko` +2. 如果有,将 gecko 插件的注册相关代码移除或注释 +3. 添加注释说明直接使用 gecko 原子服务 + +**迁移示例**: +```typescript +// 移除 gecko 插件注册代码 +// 请直接使用 gecko 原子服务 [Gecko 原子服务用户文档](https://bytedance.larkoffice.com/wiki/GQgHwQpubiAksVkWDnwcgeRjn8c) +// import { geckoPlugin } from '@edenx/plugin-gecko'; +// plugins: [ +// geckoPlugin() +// ], +``` + +## performance + +### performance.transformLodash + +**变更内容**: 不再需要,可以直接移除。 + +**迁移示例**: +```typescript +// v2 +export default { + performance: { + transformLodash: true + } +} + +// v3 - 直接移除该配置 +export default { + // 配置... +} +``` + +## 升级检查清单 + +在完成升级后,请检查以下项目: + +### 配置文件检查 + +- [ ] 移除所有废弃的配置项 +- [ ] 更新为新的配置结构 +- [ ] 手动注册必要的插件 +- [ ] 检查 `.browserslistrc` 文件是否存在 + +### 插件检查 + +- [ ] 移除 `autoLoadPlugins` 配置 +- [ ] 手动导入并注册所有需要的插件 +- [ ] 更新插件参数(如 appTools 不需要参数) +- [ ] 移除 gecko 插件注册 + +### 开发环境检查 + +- [ ] 验证开发服务器启动正常 +- [ ] 检查 HMR 功能是否正常 +- [ ] 确认端口配置正确 +- [ ] 测试中间件配置 + +### 构建检查 + +- [ ] 验证生产构建成功 +- [ ] 检查 CSS 提取和压缩 +- [ ] 确认文件名哈希配置 +- [ ] 验证代码压缩配置 + +### 运行时检查 + +- [ ] 确认路由功能正常 +- [ ] 检查状态管理是否需要调整 +- [ ] 验证懒加载功能 + +## 常见问题 + +### Q: 升级后项目无法启动怎么办? + +A: 首先检查配置文件中的废弃项是否已经移除,然后检查插件是否已经正确注册。可以查看控制台错误信息来定位具体问题。 + +### Q: 如何处理旧的 tools.esbuild 配置? + +A: 需要根据 [切换压缩器](https://rsbuild.rs/zh/config/output/minify#%E5%88%87%E6%8D%A2%E5%8E%8B%E7%BC%A9%E5%99%A8) 文档手动配置压缩器。 + +### Q: 插件注册后仍然不生效? + +A: 确认插件已经正确导入和注册,并且插件版本与 EdenX 3.0 兼容。 + +### Q: 如何处理废弃的性能优化配置? + +A: 大部分性能优化配置已经被废弃或移到了其他地方,参考上述文档进行迁移,或考虑使用 Rspack 的原生优化功能。 + + diff --git a/packages/document/docs/zh/guides/upgrade/entry.mdx b/packages/document/docs/zh/guides/upgrade/entry.mdx new file mode 100644 index 000000000000..1705b3d5c5b7 --- /dev/null +++ b/packages/document/docs/zh/guides/upgrade/entry.mdx @@ -0,0 +1,468 @@ +# 入口变更 + +本章节介绍 Modern.js 从 2.0 升级到 3.0 时,页面入口相关的变更内容。 + +## 概述 + +Modern.js 3.0 对入口机制进行了优化和简化,主要变更包括: + +- **入口文件命名变更**:自定义入口文件从 `index.[jt]sx` 改为 `entry.[jt]sx` +- **Bootstrap 函数替换**:使用新的 `createRoot` 和 `render` API +- **运行时配置迁移**:`App.config` 和 `routes/layout` 的 `config` 导出需要迁移 +- **初始化逻辑迁移**:`App.init` 和 `routes/layout` 的 `init` 导出需要改为运行时插件 + +## 入口类型识别 + +在开始迁移前,首先需要识别你的项目使用的入口类型。 + +### 入口识别条件 + +Modern.js 会扫描目录并识别符合以下**任一条件**的入口: + +1. **具有 `routes/` 目录** → 约定式路由入口 +2. **具有 `App.[jt]sx?` 文件** → 自控式路由入口 +3. **具有 `index.[jt]sx?` 文件(2.0)或 `entry.[jt]sx?` 文件(3.0)**→ 自定义入口 + +### 单入口 vs 多入口 + +**单入口应用**:默认扫描 `src/` 目录 + +```bash +src/ +├── routes/ # 或者 +├── App.tsx # 或者 +└── index.tsx # 2.0 版本 +``` + +**多入口应用**:扫描 `src/` 目录下的一级子目录 + +```bash +src/ +├── entry1/ +│ └── routes/ # 每个子目录都是一个入口 +└── entry2/ + └── App.tsx +``` + +:::tip +你可以通过 [source.entriesDir](/configure/app/source/entries-dir) 配置修改入口扫描目录。 +::: + +## 迁移步骤 + +本小节中的迁移操作都是仅当项目中实际存在对应用法时才需要执行,例如 `bootstrap` 函数、`App.config/App.init`、`routes/layout.tsx` 中的 `config/init` 函数等。 + +### 1.自定义入口文件重命名 + +如果你的项目使用了自定义入口文件(`index.[jt]sx`),需要将其重命名为 `entry.[jt]sx`。 + +**2.0 版本:** + +```bash +src/ +└── index.tsx +``` + +**3.0 版本:** + +```bash +src/ +└── entry.tsx +``` + +### 2.Bootstrap 函数迁移 + +如果你的入口文件导出了一个接收 `App` 和 `bootstrap` 参数的函数,需要改用新的 API。 + +**2.0 版本:** + +```tsx title="src/index.tsx" +export default (App: React.ComponentType, bootstrap: () => void) => { + // 执行初始化操作 + initSomething().then(() => { + bootstrap(); + }); +}; +``` + +**3.0 版本:** + +```tsx title="src/entry.tsx" +import { createRoot } from '@modern-js/runtime/react'; +import { render } from '@modern-js/runtime/browser'; + +// 创建根组件 +const ModernRoot = createRoot(); + +// 执行初始化操作 +async function beforeRender() { + await initSomething(); +} + +// 渲染应用 +beforeRender().then(() => { + render(); +}); +``` + +:::info 说明 +- `createRoot()` 返回的组件对应 `routes/` 目录生成或 `App.tsx` 导出的组件 +- `render()` 函数用于处理渲染与挂载组件 + +::: + +### 3.App.config 迁移 + +如果你在 `App.[tj]sx` 中定义了 `App.config`,需要将其迁移到运行时配置文件中。 + +**2.0 版本:** + +```tsx title="src/App.tsx" +const App = () => { + return
Hello
; +}; + +App.config = { + router: { + supportHtml5History: true, + }, +}; + +export default App; +``` + +**3.0 版本:** + +在入口同级目录创建 `modern.runtime.ts`: + +```ts title="src/modern.runtime.ts" +import { defineRuntimeConfig } from '@modern-js/runtime'; + +export default defineRuntimeConfig({ + router: { + supportHtml5History: true, + }, +}); +``` + +:::warning 注意 +Modern.js 3.0 不再支持在 `modern.config.ts` 中配置 runtime,必须使用 `modern.runtime.ts` 文件。 +::: + +### 4.App.init 迁移 + +如果你在 `App.[tj]sx` 中定义了 `App.init`,需要将其改为运行时插件。 + +**2.0 版本:** + +```tsx title="src/App.tsx" +const App = () => { + return
Hello
; +}; + +App.init = (context) => { + context.store = createStore(); + context.request = (url: string) => fetch(url); +}; + +export default App; +``` + +**3.0 版本:** + +```ts title="src/modern.runtime.ts" +import type { RuntimePlugin } from '@modern-js/runtime'; +import { defineRuntimeConfig } from '@modern-js/runtime'; + +const initPlugin = (): RuntimePlugin => ({ + name: 'init-plugin', + setup: (api) => { + return { + init({ context }) { + context.store = createStore(); + context.request = (url: string) => fetch(url); + }, + }; + }, +}); + +export default defineRuntimeConfig({ + plugins: [initPlugin()], +}); +``` + +### 5.routes/layout.tsx 中的 config 导出迁移 + +如果你在 `routes/layout.tsx` 中导出了 `config` 函数,需要将其迁移到运行时配置文件。 + +**2.0 版本:** + +```tsx title="src/routes/layout.tsx" +export const config = () => { + return { + router: { + supportHtml5History: true, + }, + }; +}; + +export default function Layout() { + return ; +} +``` + +**3.0 版本:** + +```tsx title="src/routes/layout.tsx" +export default function Layout() { + return ; +} +``` + +```ts title="src/modern.runtime.ts" +import { defineRuntimeConfig } from '@modern-js/runtime'; + +export default defineRuntimeConfig({ + router: { + supportHtml5History: true, + }, +}); +``` + +### 6.routes/layout.tsx 中的 init 导出迁移 + +如果你在 `routes/layout.tsx` 中导出了 `init` 函数,需要将其改为运行时插件。 + +**2.0 版本:** + +```tsx title="src/routes/layout.tsx" +export const init = (context) => { + context.request = (url: string) => fetch(url); +}; + +export default function Layout() { + return ; +} +``` + +**3.0 版本:** + +```tsx title="src/routes/layout.tsx" +export default function Layout() { + return ; +} +``` + +```ts title="src/modern.runtime.ts" +import type { RuntimePlugin } from '@modern-js/runtime'; +import { defineRuntimeConfig } from '@modern-js/runtime'; + +const initPlugin = (): RuntimePlugin => ({ + name: 'init-plugin', + setup: (api) => { + return { + init({ context }) { + context.request = (url: string) => fetch(url); + }, + }; + }, +}); + +export default defineRuntimeConfig({ + plugins: [initPlugin()], +}); +``` + + +## 多入口应用迁移注意事项 + +对于多入口应用,需要在 `src/modern.runtime.ts` 中使用函数形式的配置,根据入口名称返回不同的运行时配置。 + +### 配置方式 + +**目录结构:** + +```bash +src/ +├── modern.runtime.ts # 统一的运行时配置文件 +├── entry1/ +│ └── routes/ +└── entry2/ + └── App.tsx +``` + +**配置示例:** + +```ts title="src/modern.runtime.ts" +import { defineRuntimeConfig } from '@modern-js/runtime'; + +export default defineRuntimeConfig((entryName) => { + // 公共配置 + const commonConfig = { + plugins: [commonPlugin()], + }; + + // 根据入口名称返回特定配置 + if (entryName === 'entry1') { + return { + ...commonConfig, + router: { + supportHtml5History: true, + }, + plugins: [ + ...commonConfig.plugins, + entry1Plugin(), + ], + }; + } + + if (entryName === 'entry2') { + return { + ...commonConfig, + router: { + supportHtml5History: false, + }, + plugins: [ + ...commonConfig.plugins, + entry2Plugin(), + ], + }; + } + + // 默认配置 + return commonConfig; +}); +``` + +:::info 说明 +- `entryName` 参数对应入口目录名称 +- 主入口(与 `package.json` 中 `name` 同名):传入的是该目录名 +- 其他入口:传入的是入口目录名 + +::: + +### 迁移注意事项 + +1. **合并同一入口的配置**:如果同一入口下同时存在 `App.config/App.init` 和 `routes/layout.tsx` 的 `config/init`,需要将它们合并到 `src/modern.runtime.ts` 文件中对应入口的配置里 + +2. **多个插件并列配置**:多个运行时插件可以在 `plugins` 数组中并列配置 + +3. **清理旧代码**:迁移完成后,记得删除原文件中的: + - `App.config` 属性 + - `App.init` 方法 + - `routes/layout.tsx` 中的 `config` 导出 + - `routes/layout.tsx` 中的 `init` 导出 + +### 迁移示例 + +假设你有一个 2.0 版本的多入口应用: + +**2.0 版本目录结构:** + +```bash +src/ +├── main/ +│ ├── routes/ +│ │ └── layout.tsx # 含 config 和 init +│ └── App.tsx # 含 App.config 和 App.init +└── admin/ + └── routes/ + └── layout.tsx # 含 config 和 init +``` + +**2.0 版本配置:** + +```tsx title="src/main/App.tsx" +const App = () =>
Main App
; + +App.config = { + router: { supportHtml5History: true }, +}; + +App.init = (context) => { + context.mainData = 'main'; +}; +``` + +```tsx title="src/admin/routes/layout.tsx" +export const config = () => ({ + router: { supportHtml5History: false }, +}); + +export const init = (context) => { + context.adminData = 'admin'; +}; +``` + +**3.0 版本迁移后:** + +```bash +src/ +├── modern.runtime.ts # 新增统一配置文件 +├── main/ +│ ├── routes/ +│ │ └── layout.tsx # 移除 config 和 init +│ └── App.tsx # 移除 App.config 和 App.init +└── admin/ + └── routes/ + └── layout.tsx # 移除 config 和 init +``` + +```ts title="src/modern.runtime.ts" +import { defineRuntimeConfig } from '@modern-js/runtime'; +import type { RuntimePlugin } from '@modern-js/runtime'; + +// main 入口的初始化插件 +const mainInitPlugin = (): RuntimePlugin => ({ + name: 'main-init-plugin', + setup: (api) => { + return { + init({ context }) { + context.mainData = 'main'; + }, + }; + }, +}); + +// admin 入口的初始化插件 +const adminInitPlugin = (): RuntimePlugin => ({ + name: 'admin-init-plugin', + setup: (api) => { + return { + init({ context }) { + context.adminData = 'admin'; + }, + }; + }, +}); + +export default defineRuntimeConfig((entryName) => { + if (entryName === 'main') { + return { + router: { + supportHtml5History: true, + }, + plugins: [mainInitPlugin()], + }; + } + + if (entryName === 'admin') { + return { + router: { + supportHtml5History: false, + }, + plugins: [adminInitPlugin()], + }; + } + + return {}; +}); +``` + +## 相关链接 + +- [页面入口](/guides/concept/entries) +- [运行时配置](/configure/app/runtime/0-intro) +- [Runtime 插件](/plugin/introduction.html#runtime-插件) +- [source.entries 配置](/configure/app/source/entries) +- [source.entriesDir 配置](/configure/app/source/entries-dir) diff --git a/packages/document/docs/zh/guides/upgrade/overview.mdx b/packages/document/docs/zh/guides/upgrade/overview.mdx new file mode 100644 index 000000000000..dc75ec8ca8ed --- /dev/null +++ b/packages/document/docs/zh/guides/upgrade/overview.mdx @@ -0,0 +1,36 @@ +# 概述 + +本文档将帮助您从 Modern.js 2.0 升级到 Modern.js 3.0。 + +## 升级概览 + +Modern.js 3.0 带来了多项重大改进和变化,主要包括: + +- **构建工具升级**:默认使用 [Rspack](https://rspack.dev) 构建,不再支持 Webpack,构建配置与 [Rsbuild](https://rsbuild.dev) 对齐。 +- **React 生态升级**:全面支持 [React 19](https://react.dev/blog/2024/04/25/react-19) 和 [React Router v7](https://reactrouter.com)。 +- **插件系统重构**:重新设计插件 API,支持在 CLI、Runtime、Server 层通过自定义插件扩展框架能力。 +- **React Server Component**:支持在 [CSR](/guides/get-started/glossary#csr) 和 [SSR](/guides/basic-features/render/ssr) 项目中使用 React Server Component。 +- **国际化增强**:提供开箱即用的 [i18n 插件](/guides/advanced-features/international),简化国际化开发流程。 +- **SSG 能力完善**:提供完整的[静态站点生成(SSG)](/guides/basic-features/render/ssg)支持。 +- **路由配置增强**:支持[配置式路由](/guides/basic-features/routes/config-routes),可单独使用或与[约定式路由](/guides/basic-features/routes/routes)结合,提供更灵活的路由定义方式。 + + +## 升级前置检查 + +在开始升级之前,请确认: + +1. 当前项目使用的是 Modern.js 2.0 +2. 确定使用的 react 版本是 17 及以上 +2. 确定使用的 node.js 版本是 18.20.8 及以上,推荐使用 node.js 22 以上版本 + + +## 获取帮助 + +如果在升级过程中遇到任何问题,您可以通过以下方式获取帮助: + +- 查阅 [Modern.js 官方文档](https://modernjs.dev) +- 在 [GitHub Issues](https://github.com/web-infra-dev/modern.js/issues) 中搜索相关问题或提交新的 issue +- 加入 [Modern.js Discord 社区](https://discord.gg/modernjs)与其他开发者交流 + +我们建议在提交 issue 时提供尽可能详细的信息,包括错误日志、配置文件和复现步骤,以便更快地解决问题 + From a6d44692371fc54e773e345cc84643040abb95a1 Mon Sep 17 00:00:00 2001 From: wangyiming Date: Tue, 2 Dec 2025 17:39:43 +0800 Subject: [PATCH 2/5] docs: overiew of break changes --- .../docs/en/guides/concept/entries.mdx | 13 +++-- .../docs/zh/guides/concept/entries.mdx | 12 ++-- .../docs/zh/guides/upgrade/config.mdx | 57 ------------------- 3 files changed, 15 insertions(+), 67 deletions(-) diff --git a/packages/document/docs/en/guides/concept/entries.mdx b/packages/document/docs/en/guides/concept/entries.mdx index 2be399c42750..396f51518b67 100644 --- a/packages/document/docs/en/guides/concept/entries.mdx +++ b/packages/document/docs/en/guides/concept/entries.mdx @@ -193,10 +193,15 @@ If you don't want to use any of Modern.js's runtime capabilities, you can also m ```js title=src/entry.tsx import React from 'react'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import App from './App'; -ReactDOM.render(, document.getElementById('root')); +const container = document.getElementById('root'); + +if (container) { + const root = createRoot(container); + root.render(); +} ``` In this mode, **you will not be able to use Modern.js framework's runtime capabilities**, such as: @@ -237,10 +242,6 @@ export default defineConfig({ }); ``` -It is worth noting that, by default, Modern.js considers entries specified through the configuration as **framework mode entries** and will automatically generate the actual compilation entry. - -If your application is migrating from build tools like Webpack or Vite to the Modern.js framework, you typically need to enable the `disableMount` option in the entry configuration. In this case, Modern.js will treat the entry as a **build mode entry**. - ## In-Depth The concept of page entry is derived from the concept of [Entrypoint](https://webpack.js.org/concepts/entry-points/) in webpack. It is mainly used to configure JavaScript or other modules to be executed during application startup. webpack's [best practice](https://webpack.docschina.org/concepts/entry-points/#multi-page-application) for web applications usually corresponds entries to HTML output files, meaning each additional entry will eventually generate a corresponding HTML file in the output. The modules imported by the entry will be compiled and packaged into multiple Chunk outputs. For example, JavaScript modules may ultimately generate several file outputs similar to `dist/static/js/index.ea39u8.js`. diff --git a/packages/document/docs/zh/guides/concept/entries.mdx b/packages/document/docs/zh/guides/concept/entries.mdx index c62ae61f9a1a..29e55c67e6ae 100644 --- a/packages/document/docs/zh/guides/concept/entries.mdx +++ b/packages/document/docs/zh/guides/concept/entries.mdx @@ -196,12 +196,18 @@ beforeRender().then(() => { ```js title=src/entry.tsx import React from 'react'; -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import App from './App'; -ReactDOM.render(, document.getElementById('root')); +const container = document.getElementById('root'); + +if (container) { + const root = createRoot(container); + root.render(); +} ``` + 在该模式下,**将无法使用 Modern.js 框架的运行时能力**,比如: - 约定式路由,即基于 `src/routes` 下文件的路由 @@ -241,8 +247,6 @@ export default defineConfig({ }); ``` -值得注意的是,默认情况下,Modern.js 认为通过配置指定的入口是**框架模式入口**,将自动生成真正的编译入口。如果你的应用是从 Webpack 或 Vite 等构建工具迁移到 Modern.js 框架时,你通常需要在入口配置中开启 `disableMount` 选项,此时 Modern.js 认为该入口是**构建模式入口**。 - ## 深入了解 页面入口的概念衍生自 webpack 的入口(Entrypoint)概念,其主要用于配置 JavaScript 或其他模块在应用启动时加载和执行。webpack 对于网页应用的 [最佳实践](https://webpack.docschina.org/concepts/entry-points/#multi-page-application) 通常将入口与 HTML 产物对应,即每增加一个入口最终就会在产物中生成一份对应的 HTML 文件。入口引入的模块会在编译打包后生成多个 Chunk 产物,例如对于 JavaScript 模块最终可能会生成数个类似 `dist/static/js/index.ea39u8.js` 的文件产物。 diff --git a/packages/document/docs/zh/guides/upgrade/config.mdx b/packages/document/docs/zh/guides/upgrade/config.mdx index b754a6e3961c..6f4f7cf70697 100644 --- a/packages/document/docs/zh/guides/upgrade/config.mdx +++ b/packages/document/docs/zh/guides/upgrade/config.mdx @@ -636,60 +636,3 @@ export default { } ``` -## 升级检查清单 - -在完成升级后,请检查以下项目: - -### 配置文件检查 - -- [ ] 移除所有废弃的配置项 -- [ ] 更新为新的配置结构 -- [ ] 手动注册必要的插件 -- [ ] 检查 `.browserslistrc` 文件是否存在 - -### 插件检查 - -- [ ] 移除 `autoLoadPlugins` 配置 -- [ ] 手动导入并注册所有需要的插件 -- [ ] 更新插件参数(如 appTools 不需要参数) -- [ ] 移除 gecko 插件注册 - -### 开发环境检查 - -- [ ] 验证开发服务器启动正常 -- [ ] 检查 HMR 功能是否正常 -- [ ] 确认端口配置正确 -- [ ] 测试中间件配置 - -### 构建检查 - -- [ ] 验证生产构建成功 -- [ ] 检查 CSS 提取和压缩 -- [ ] 确认文件名哈希配置 -- [ ] 验证代码压缩配置 - -### 运行时检查 - -- [ ] 确认路由功能正常 -- [ ] 检查状态管理是否需要调整 -- [ ] 验证懒加载功能 - -## 常见问题 - -### Q: 升级后项目无法启动怎么办? - -A: 首先检查配置文件中的废弃项是否已经移除,然后检查插件是否已经正确注册。可以查看控制台错误信息来定位具体问题。 - -### Q: 如何处理旧的 tools.esbuild 配置? - -A: 需要根据 [切换压缩器](https://rsbuild.rs/zh/config/output/minify#%E5%88%87%E6%8D%A2%E5%8E%8B%E7%BC%A9%E5%99%A8) 文档手动配置压缩器。 - -### Q: 插件注册后仍然不生效? - -A: 确认插件已经正确导入和注册,并且插件版本与 EdenX 3.0 兼容。 - -### Q: 如何处理废弃的性能优化配置? - -A: 大部分性能优化配置已经被废弃或移到了其他地方,参考上述文档进行迁移,或考虑使用 Rspack 的原生优化功能。 - - From 102f52c0f404f688b56a3074ece0eb33865ac1c8 Mon Sep 17 00:00:00 2001 From: wangyiming Date: Tue, 2 Dec 2025 17:47:48 +0800 Subject: [PATCH 3/5] docs: overiew of break changes --- .../docs/zh/guides/upgrade/config.mdx | 61 +------------------ .../document/docs/zh/guides/upgrade/entry.mdx | 2 +- 2 files changed, 2 insertions(+), 61 deletions(-) diff --git a/packages/document/docs/zh/guides/upgrade/config.mdx b/packages/document/docs/zh/guides/upgrade/config.mdx index 6f4f7cf70697..bfcb70d06dcc 100644 --- a/packages/document/docs/zh/guides/upgrade/config.mdx +++ b/packages/document/docs/zh/guides/upgrade/config.mdx @@ -127,7 +127,7 @@ export default { **处理步骤**: 1. 检查项目中是否有 `.browserslistrc` 文件 -2. 检查 `edenx.config.[ts|js]` 中是否配置了 `output.overrideBrowserslist` +2. 检查 `modern.config.[ts|js]` 中是否配置了 `output.overrideBrowserslist` 3. 检查 package.json 中是否配置了 browserslist 如果都没有,则创建 `.browserslistrc` 文件,内容为支持 ES6 的浏览器: @@ -537,46 +537,6 @@ dev: { ## plugins -### autoLoadPlugins - -**变更内容**: 该配置已被废弃,需要手动注册插件。 - -**处理步骤**: -1. 移除 `autoLoadPlugins` 配置 -2. 手动导入并注册需要使用的插件 - -**支持的插件变量名**: -- `@edenx/app-tools`: `appTools` -- `@edenx/plugin-slardar-web`: `slardarWebPlugin` -- `@edenx/plugin-i18n`: `i18nPlugin` -- `@edenx/plugin-starling-intl`: `starlingIntlPlugin` -- `@edenx/plugin-bff`: `bffPlugin` -- `@edenx/plugin-gulu`: `guluPlugin` -- `@edenx/plugin-gulux`: `guluxPlugin` -- `@edenx/plugin-ssg`: `ssgPlugin` -- `@edenx/plugin-garfish`: `garfishPlugin` - -**迁移示例**: -```typescript -// v2 - 自动加载插件 -export default { - autoLoadPlugins: true -} - -// v3 - 手动注册插件 -import { defineConfig, appTools } from '@edenx/app-tools'; -import { i18nPlugin } from '@edenx/plugin-i18n'; -import { ssgPlugin } from '@edenx/plugin-ssg'; - -export default defineConfig({ - plugins: [ - appTools(), - i18nPlugin(), - ssgPlugin() - ] -}) -``` - ### app-tools 插件 **变更内容**: 该插件不需要传入任何参数。 @@ -596,25 +556,6 @@ plugins: [ ], ``` -### plugin-gecko - -**变更内容**: 按以下步骤处理 - -**处理步骤**: -1. 检测 `edenx.config.[tj]s` 中是否有注册 `@edenx/plugin-gecko` -2. 如果有,将 gecko 插件的注册相关代码移除或注释 -3. 添加注释说明直接使用 gecko 原子服务 - -**迁移示例**: -```typescript -// 移除 gecko 插件注册代码 -// 请直接使用 gecko 原子服务 [Gecko 原子服务用户文档](https://bytedance.larkoffice.com/wiki/GQgHwQpubiAksVkWDnwcgeRjn8c) -// import { geckoPlugin } from '@edenx/plugin-gecko'; -// plugins: [ -// geckoPlugin() -// ], -``` - ## performance ### performance.transformLodash diff --git a/packages/document/docs/zh/guides/upgrade/entry.mdx b/packages/document/docs/zh/guides/upgrade/entry.mdx index 1705b3d5c5b7..38cd9a67d9c4 100644 --- a/packages/document/docs/zh/guides/upgrade/entry.mdx +++ b/packages/document/docs/zh/guides/upgrade/entry.mdx @@ -1,4 +1,4 @@ -# 入口变更 +# 入口变化 本章节介绍 Modern.js 从 2.0 升级到 3.0 时,页面入口相关的变更内容。 From f703139af429c43a9c7d42405be902a9dc5cc36e Mon Sep 17 00:00:00 2001 From: wangyiming Date: Tue, 2 Dec 2025 17:49:43 +0800 Subject: [PATCH 4/5] docs: overiew of break changes --- .../document/docs/zh/guides/basic-features/data/data-cache.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/document/docs/zh/guides/basic-features/data/data-cache.mdx b/packages/document/docs/zh/guides/basic-features/data/data-cache.mdx index 6cfa297a15c4..355bfa9ee0a9 100644 --- a/packages/document/docs/zh/guides/basic-features/data/data-cache.mdx +++ b/packages/document/docs/zh/guides/basic-features/data/data-cache.mdx @@ -67,7 +67,7 @@ interface CacheOptions { ## 使用范围 与 react 的 [cache](https://react.dev/reference/react/cache) 函数只能在 server component 组件中使用不同, -EdenX 提供的 `cache` 函数可以在任意的前端或服务端的代码中使用。 +Modern.js 提供的 `cache` 函数可以在任意的前端或服务端的代码中使用。 ## 详细用法 From 47d765d6a619069493a27738ec03817cec86d522 Mon Sep 17 00:00:00 2001 From: wangyiming Date: Tue, 2 Dec 2025 20:20:55 +0800 Subject: [PATCH 5/5] chore: remove the doc --- .../en/guides/basic-features/render/ssg.mdx | 30 ------------------- .../zh/guides/basic-features/render/ssg.mdx | 30 ------------------- 2 files changed, 60 deletions(-) diff --git a/packages/document/docs/en/guides/basic-features/render/ssg.mdx b/packages/document/docs/en/guides/basic-features/render/ssg.mdx index 6bc4aa02a88e..6267c9131071 100644 --- a/packages/document/docs/en/guides/basic-features/render/ssg.mdx +++ b/packages/document/docs/en/guides/basic-features/render/ssg.mdx @@ -93,36 +93,6 @@ Each route in **conventional routing** will generate a separate HTML file. Check After running `pnpm run serve` to start the project, inspect the returned document in the Network tab of the browser's development tools. The document includes the fully rendered content from the component. -### Preventing Default Behavior - -By default, all routes in **conventional routing** have SSG enabled. Modern.js provides another field to prevent the default SSG behavior. - -For example, in the following directory structure, routes `/`, `/user`, and `/user/profile` all have SSG enabled: - -```bash -. -├── src -│ └── routes -│ ├── layout.tsx -│ ├── page.tsx -│ └── user -│ ├── layout.tsx -│ ├── page.tsx -│ └── profile -│ └── page.tsx -``` - -You can disable the default behavior of certain routes by configuring `preventDefault`. After configuring as shown below, only the SSG pages for `/` and `/user/profile` will be generated: - -```js -export default defineConfig({ - output: { - ssg: { - preventDefault: ['/user'], - }, - }, -}); -``` ## Using SSG in Manual Routing diff --git a/packages/document/docs/zh/guides/basic-features/render/ssg.mdx b/packages/document/docs/zh/guides/basic-features/render/ssg.mdx index fe849cfdc728..9091f1fb5ec4 100644 --- a/packages/document/docs/zh/guides/basic-features/render/ssg.mdx +++ b/packages/document/docs/zh/guides/basic-features/render/ssg.mdx @@ -94,36 +94,6 @@ export default () => { 执行 `pnpm run serve` 启动项目后,访问页面,在浏览器我们工具的 Network 窗口,查看请求返回的文档,文档包含组件渲染后的完整页面内容。 -### 阻止默认行为 - -默认情况下,**约定式路由**的路由会全部开启 SSG。Modern.js 提供了另一个字段,用来阻止默认的 SSG 行为。 - -例如以下目录结构,`/`、`/user`、`/user/profle` 三条路由都开启 SSG: - -```bash -. -├── src -│ └── routes -│ ├── layout.tsx -│ ├── page.tsx -│ └── user -│ ├── layout.tsx -│ ├── page.tsx -│ └── profile -│ └── page.tsx -``` - -可以通过配置 `preventDefault` 来禁用某些路由的默认行为。进行下面配置后,最终只会生成 `/`、`/user/profle` 两条路由的 SSG 页面: - -```js -export default defineConfig({ - output: { - ssg: { - preventDefault: ['/user'], - }, - }, -}); -``` ## 在自控式路由中使用