[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
-
背景
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