内容提要
Shiki是一个代码高亮库,但加载过慢且浪费流量。文章介绍了如何按需加载Shiki所需的语言解析器,减少加载时间和流量浪费。通过动态加载和使用use hook,实现了只加载需要的语言解析器。最后,提到了解决CLS(页面抖动)的方法。
延伸解读
按需加载的核心机制
文章通过 getHighlighterCore 初始化时不加载任何语言,再结合 getLoadedLanguages 检查语言是否已加载,并动态 import 对应的语言模块,实现按需加载。这避免了打包所有 bundledLanguages 造成的流量浪费,同时利用 use hook 等待异步高亮器就绪,使组件在客户端动态加载所需语言解析器。
Next.js App Router 下的限制与 CLS 问题
在 Next.js App Router 中,若需动态渲染代码,必须使用 Client Component,但 Client Component 不支持 top-level await,导致 Shiki 无法在服务端渲染,从而引发首屏 CLS。文章指出,使用 Suspense 和 fallback 可以缓解,但 fallback 需提前占位,且高亮转换仍可能造成视觉差异。
架构选择建议
文章认为,当存在过多动态组件嵌套时,不应使用 Next.js App Router 架构。这是因为 Client Component 的限制和 CLS 问题在复杂场景下难以优雅解决。作者建议在类似需求下考虑其他架构,并感谢 antfu 提供的解决方案,该方案简化自 Shiro 项目。
Q&A
Shiki是什么,它的主要功能是什么?
Shiki是一个代码高亮库,主要用于对代码进行高亮显示。
如何解决Shiki加载速度慢和流量浪费的问题?
通过按需加载Shiki所需的语言解析器,可以减少加载时间和流量浪费。
在Next.js中如何动态加载Shiki语言解析器?
可以使用getLoadedLanguages和getHighlighterCore方法来动态加载需要的语言解析器,而不是一次性加载全部。
使用Suspense和fallback有什么作用?
使用Suspense和fallback可以减少页面抖动(CLS),但需要提前占位以避免误操作。
在复杂的动态组件嵌套中,使用Next.js App Router有什么限制?
在复杂的动态组件嵌套中,不建议使用Next.js App Router架构,因为可能会导致性能问题。
Shiki的按需加载实现中使用了哪些React特性?
按需加载实现中使用了use hook和Promise来动态加载需要的语言解析器。