NextJS/React 加载远程组件

NextJS/React 加载远程组件

💡 原文中文,约8000字,阅读约需19分钟。
📝

内容提要

本文介绍了使用MDX扩展Markdown并渲染远程组件的方法,实现交互式博文。同时还介绍了在远程组件中使用TailwindCSS的配置和示例代码。

🔎

延伸解读

MDX 的局限与远程组件方案

MDX 在构建时编译组件,适合静态博客,但无法用于动态生成的 CMS 内容。本文提出一种替代方案:在普通 Markdown 中通过自定义 DSL 加载远程打包的 React 组件。这为动态内容提供了嵌入交互组件的可能,但需要自行处理组件加载、渲染和样式隔离。

确保 React 单例与全局暴露

远程组件必须与宿主使用同一份 React 和 ReactDOM,否则 Hooks 等机制会失效。文章通过一个客户端组件在布局挂载时将 React 和 ReactDOM 挂到 window 上,供远程组件以 iife/umd 格式引用。这避免了修改 webpack 配置可能引发的白屏问题,但要求远程组件构建时 external 这些依赖。

样式隔离与暗黑模式兼容

远程组件若直接引入 TailwindCSS,其生成的全局样式可能污染宿主,且层叠顺序可能导致宿主样式崩坏。文章推荐使用 PostCSS + CSS Module,并避免导入 @tailwind base 等指令,使 className 唯一且局部作用域。同时将 darkMode 配置为宿主使用的选择器,可让远程组件自动适配宿主的暗黑模式。

❓

Q&A

MDX 在什么场景下不适用?

对于动态生成内容的 CMS 博客,因为内容都是动态生成的,无法使用 MDX。

如何让远程组件使用宿主的 React 和 ReactDOM?

通过将 React 和 ReactDOM 附加到浏览器侧全局对象上,例如在 layout 中引入一个 Global 组件,在 useIsomorphicLayoutEffect 中执行 Object.assign(window, { React, ReactDOM, react: React, reactDom: ReactDOM })。

远程组件应该打包成什么格式?

远程组件需要打包为 iife 或 umd 格式,并且产物的 React 应该使用 window.React。

如何避免远程组件中的 TailwindCSS 样式污染宿主环境?

使用 PostCSS + TailwindCSS + CSS Module 的组合,确保生成的 className 唯一,并且不要导入 TailwindCSS 的 layer(如 @tailwind base; @tailwind components; @tailwind utilities;)。

如何定义新的 DSL 语法来渲染远程组件?

利用 CodeBlock 扩展,定义类似 `import=远程 js url` 和 `component=从 window 上找到需要渲染的组件位置` 的语法,而不是使用 JS 的 import 语法。

远程组件渲染时如何防止组件报错导致应用崩溃?

使用 ErrorBoundary 包装组件,提供 fallback 显示错误状态,例如 <ErrorBoundary fallback={<ComponentBlockError />}>。

🏷️

标签

➡️

继续阅读