[RFC] route meta supports lazy loading #1866
PeachScript
started this conversation in
Ideas
Replies: 5 comments 4 replies
-
builtin 等内置组件不会被搜索引擎收集的问题有解吗 |
Beta Was this translation helpful? Give feedback.
3 replies
-
先 own 一下
|
Beta Was this translation helpful? Give feedback.
0 replies
-
|
Beta Was this translation helpful? Give feedback.
1 reply
-
feature/2.3.0 分支 route meta 异步加载的调整计划:
|
Beta Was this translation helpful? Give feedback.
0 replies
-
已移动至独立的 RFC:#1991 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
背景
dumi 2 提供了全文搜索以及 demo 渲染/源码展示/独立打开的能力,背后的数据都存在全局的 Context 中,当初这样设计的原因是:
但 dumi 2 已经被应用于大型文档站点,比如 Ant Design 官网和隐语官网,目前的设计会导致 entry chunk 过大,页面首次加载的白屏时间过长,而且随着文档内容的增加这个情况可能会更加严重,所以需要重新调整路由 meta 数据的加载方案。
当前方案是怎么工作的
在编译时,dumi 会动态生成一个 meta.ts 的临时文件:
dumi/src/features/meta.ts
Lines 54 to 56 in fc4be89
它会通过特殊的 loader 加载每个路由的 3 类数据,分别是:
demos
:当前路由的 demo 数据,包含 demo 源代码、元信息和实际渲染的组件frontmatter
:当前路由的 FrontMatter 数据,包含 Markdown 文档头部配置的值及一些内置值(比如filename
、lastUpdated
等)toc
:当前路由的标题数据texts
:当前路由的文本数据在运行时初始化阶段,dumi 会通过运行时插件将 2、3、4 类数据 patch 到路由表里,这份数据会存储在 Umi 的 AppContext 里,后续通过路由相关的钩子可以拿到:
dumi/src/features/meta.ts
Lines 108 to 133 in fc4be89
以及通过 ContextProvider 将 demos 数据放置在 dumi 的全局 SiteContext 里,后续通过
useSiteData
可以拿到:dumi/src/features/theme/index.ts
Lines 410 to 416 in f84b043
在运行时的消费阶段,一共有 4 处地方会使用这些数据:
route.meta.frontmatter
:dumi/src/client/theme-api/useSidebarData.ts
Line 90 in 4ffe77e
dumi/src/client/theme-api/useSiteSearch/index.ts
Lines 71 to 78 in d0decb2
dumi/src/client/theme-api/DumiDemo.tsx
Lines 41 to 43 in bc79d2c
dumi/src/client/pages/Demo/index.ts
Line 7 in e68fa97
如何解决当下面对的问题
大方向就是,把首屏用不到的数据都拆分到异步 chunk 中,等需要使用的时候再加载,具体方案将逐一说明。
首先需要把上述数据做拆分:
frontmatter
数据仍要保留,对应的运行时插件里frontmatter
数据的 patch 逻辑也要保留type=meta
,可以分成type=frontmatter
、type=demo
和type=text
)来单独加载,loader 逻辑可以复用,因为 dumi 有持久缓存多次加载应该不会影响性能然后需要明确放入异步 chunk 的方案及加载时机,目前的想法是借用路由自己的 chunk 来加载自己的数据,具体到实现层面有 2 个改造要点:
key: value
形式(key 为页面路由文件,value 为对应的 tab 文件数组)作为参数传进去,用于下一步实现dumi/src/loaders/markdown/index.ts
Lines 118 to 136 in 8873af2
接着要确定运行时数据获取的方案调整:
getRouteMetaById
方法,用于异步获取指定路由的 meta 数据,也会成为已有 hookuseRouteMeta
和useTabMeta
的底层方法getDemoById
方法,用于异步获取指定 demo 的 meta 数据及组件,需要记录 demo id 与 chunk 间的关系实现 demo 数据异步加载,demo id 与 chunk 间的关系可能得新做一个 loader type 来实现,比如type=demo-index
getAllRoutesMeta
方法,用于异步获取全量路由的 meta 数据texts
和toc
字段变为空数组,并利用 Proxy 加上废弃提示demos
字段变为空对象,并利用 Proxy 加上废弃提示DumiDemo
组件中改为使用getDemoById
获取 demo 渲染数据最后是处理其他需要异步获取数据的情况,目前看下来就只有搜索框聚焦及 demo 单独打开这两个场景需要依赖页面异步 chunk 中的数据:
useSiteSearch
hook,异步调用getAllRoutesMeta
API 获取所有数据,并完成序列化后传给 worker 建立搜索索引getDemoById
的方法获取对应的 demo 数据后续优化点
任务拆分
一共分为 4 类任务,各类任务之间理论上是弱耦合,可以通过捏造数据调试:
loader 拆分
任务列表:
type=meta
拆分为 4 个 type,分别是:demo
:返回页面的 demo 数据,数据结构与现在一致demo-index
:新增,返回该页面的 demo id 集合,用于根据 demo id 加载对应的 chunk 数据,结构类似{ ids: [...], getter: () => await import('/path/to/xx.md?type=demo') }
frontmatter
:返回页面的 FrontMatter 数据,数据结构与现在一致text
:返回页面的文本数据,包含 texts 和 toc 数据,数据结构与现在一致onResolveDemos
和onResolveAtomMeta
参数挪到默认模式里执行,因为只需要执行一次)调试方式:
.dumi/pages/loader-test.tsx
编写类似内容:pnpm dev
并访问/loader-test
页面查看控制台内容是否符合预期页面组件改造
任务列表:
key: value
数据并传入,该数据已存在,通过api.appData
共享给 compile 插件即可useRouteMeta
和useTabMeta
的调用调试方式:
import texts from '/path/to/xx.md?type=text'
的引入值,比如声明const texts = [...]
orconst tab1Texts = [...]
pnpm dev
meta 临时文件生成改造
frontmatter
数据保持同步引入,其他数据均放置在各个方法中异步引入getAllRoutesMeta
方法,异步以 key:value 形式返回所有路由的 meta 数据{ [id]: { texts, toc, frontmatter } }
,并通过 exports.ts 导出成为 Theme APIgetRouteMetaById
方法,异步返回指定 id 对应的路由数据{ texts, toc, frontmatter }
,并通过 exports.ts 导出成为 ThemeAPIgetDemoById
方法,异步返回指定 demo id 对应的 demo 数据{ component: 页面组件, asset: 元数据 }
,并通过 exports.ts 导出成为 ThemeAPI(demo 与 chunk 的对应关系依赖 loader 拆分中的demo-index
数据)调试方式:
import dmi from '/path/to/xx.md?type=demo-index'
的返回值,数据结构参考上面的任务描述.dumi/pages/api-test.tsx
编写类似内容:pnpm dev
并访问/api-test
页面运行时 API 改造
任务列表:
demos
字段变为空对象,并利用 Proxy 加上废弃提示texts
和toc
字段的设置变为空数组,并利用 Proxy 加上废弃提示useRouteMeta
和useTabMeta
,改为基于getRouteMetaById
API 实现DumiDemo
组件,对 demos 的获取逻辑改为基于getDemoById
API 实现调试方式:
getRouteMetaById
和getDemoById
的 API 返回值,数据结构参考上面的任务描述docs/runtime-test.md
编写类似内容:docs/runtime-test.$tab-a.md
编写类似内容:pnpm dev
并访问/runtime-test
页面,验证 hook 的 Proxy 警告是否正常展示,验证 hook 的返回值是否正常,验证DumiDemo
是否正常渲染/runtime-test?tab=a
页面,验证 hook 返回值是否正常协同流程
时间点
暂时想到这些,如有遗漏欢迎补充
Beta Was this translation helpful? Give feedback.
All reactions