ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

LikeC4 内部 React 分发包解析:`@likec4/react` 如何从 `@likec4/diagram` 打包为 `likec4/react`

LikeC4 内部 React 分发包解析:`@likec4/react` 如何从 `@likec4/diagram` 打包为 `likec4/react` LikeC4 内部 React 分发包解析likec4/react如何从likec4/diagram打包为likec4/react【免费下载链接】likec4Visualize, collaborate, and evolve the software architecture with always actual and live diagrams from your code项目地址: https://gitcode.com/GitHub_Trending/li/likec4likec4/react是 LikeC4 仓库中一个刻意“不发布到 npm”的内部打包包它把功能完整的图渲染库likec4/diagram连同 rollup 合并后的类型定义打成单个 ESM 产物并在构建likec4主包时被复制为likec4/react子路径导出。本文以 packages/react/README.md 为核心结合 packages/react/package.json、packages/react/src/index.ts、packages/react/vite.config.mjs 以及 packages/likec4/tsdown.config.mts 等源码完整讲清它的定位、构建链路、分发机制与消费方式读完你可以理解 LikeC4 前端渲染代码从源码到likec4/react公共入口的整条流水线以及为什么它要同时处理 CSS 选择器重写与类型打包。一、定位一个面向内部、随主包分发的前端渲染产物packages/react/README.md全文只有两条关键事实却决定了该包在仓库中的特殊地位该包仅供内部使用不会发布到 npm [!WARNING]提示它是likec4/diagram的打包版本bundled version并带有 rollup 合并后的类型定义构建产物会被复制到likec4主包对外以likec4/react的形式可用。package.json中的配置与之一一对应private: true——npm 发布命令会直接拒绝它从包管理器层面强制“内部包”定位type: module、module: dist/index.mjs、types: dist/index.d.mts——只产出 ESM 格式sideEffects: false——声明无副作用允许打包器安全地做 tree-shakingexports只暴露.映射到dist/index.mjs和./package.json两个入口没有react之类的子路径进一步说明它不是给外部直接消费的 API 面。在 packages/likec4/CHANGELOG.md 中可以看到它的来历一次“为更好可维护性而做的内部重构”中官方将likec4/react定位为likec4/diagram的打包版本与likec4/language-services、likec4/vite-plugin一起被拆分出来实现关注点分离。也就是说likec4/react存在的意义不是提供新 API而是为最终交付物准备一份可直接分发的渲染代码。二、包内唯一源码入口全量转发likec4/diagram并导出 xyflow 命名空间likec4/react的源码只有一个文件 packages/react/src/index.ts逻辑极其精简import { ControlButton as XYControlButton, MiniMap as XYMiniMap, MiniMapNode as XYMiniMapNode, NodeToolbar as XYNodeToolbar, Panel as XYPanel, Position as XYPosition, ViewportPortal as XYViewportPortal, } from xyflow/react import type { Types } from likec4/diagram export * from likec4/diagram export * from likec4/diagram/custom export const xyflow { ControlButton: XYControlButton, MiniMap: XYMiniMapTypes.AnyNode, MiniMapNode: XYMiniMapNode, NodeToolbar: XYNodeToolbar, Panel: XYPanel, Position: XYPosition, ViewportPortal: XYViewportPortal, } as const三层结构清晰可辨export * from likec4/diagram——把图渲染库的全部公开 API 原样转发。从 packages/diagram/src/index.ts 可以看到这份 API 清单包含核心组件LikeC4Diagram、StaticLikeC4Diagram、LikeC4View、ReactLikeC4、LikeC4ProjectsOverviewProvider 类组件LikeC4ModelProvider、LikeC4EditorProvider、LikeC4ProjectsProvider、LikeC4MantineProvider以及大量 hooksuseDiagram、useLikeC4Model、useCurrentViewModel、useLikeC4Project、useLikeC4Styles等、类型LikeC4DiagramProps、LikeC4ViewProps、ReactLikeC4Props、Types与搜索相关组件SearchControl、SearchPanelContent。export * from likec4/diagram/custom——额外转发自定义渲染子路径供需要定制节点/边渲染的场景使用。xyflow命名空间对象——把渲染底层React Flow / xyflow常用构件统一收口为xyflow.*Panel、Position、MiniMap、MiniMapNode、NodeToolbar、ControlButton、ViewportPortal。这样消费方无需直接依赖xyflow/react即可拿到画布辅助组件避免把底层库版本直接暴露给下游。三、构建链路vite rolldown pandacss dts 打包构建脚本在package.json中是build: vite build而真正的工作全部落在 packages/react/vite.config.mjs 中。这份配置集中体现了“内部打包包”的工程考量逐项拆解1. 构建前自动生成 Panda CSS 代码配置中注册了一个自定义插件name: likec4-react在buildStart钩子里先清空styled-system目录再执行pandacss codegenasync buildStart() { this.info(buildStart) await fs.emptyDir(styled-system) await $pandacss codegen }对应的 packages/react/panda.config.mjs 把扫描范围设为src/*.ts与../diagram/src/**/*.{ts,tsx}输出到styled-system——也就是说likec4/react的打包产物里包含了为likec4/diagram全套源码生成的样式代码这正是它能成为“自包含图渲染包”的基础。2. PostCSS 重写:root与body选择器这是整个配置里最微妙的一处。rewriteRootSelector插件遍历 CSS 规则把所有选择器中的:root与body改写为.likec4-shadow-rootif (_val :root || _val body) { updatedSelectors.push(.likec4-shadow-root) updated true continue }原因在 packages/react/CHANGELOG.md 中有据可查早期版本曾在 Shadow DOM 渲染场景下出现样式失效问题后续修复了“react/webcomponents 在 shadow root 中渲染时的 CSS 打包”并直接内联了 shadow-root 渲染逻辑不再依赖react-shadow依赖。把全局选择器收敛到.likec4-shadow-root可以保证这些样式在 Shadow DOM 宿主上生效又不会污染外部页面全局样式——这与 packages/diagram/src/shadowroot/ 目录下的 Shadow DOM 渲染能力是配套的。3. 依赖外置与 React 去重构建时把package.json中dependencies与peerDependencies的所有包除use-sync-external-store外都声明为 external并通过正则如^react(\/.*)?$精确匹配子路径const externals Object .keys({ ...packageJson.dependencies, ...packageJson.peerDependencies }) .filter((dep) dep ! use-sync-external-store)同时在resolve.dedupe中指定react、react-dom避免因依赖图里存在多份 React 导致 hooks 状态错乱。CHANGELOG 里也明确记录把use-sync-external-store标记为 external是为了“避免重复的 React 内部实现”。4. 类型定义打包rollup types使用vite-plugin-dts的bundleTypes能力把react-error-boundary、likec4/diagram、mantine/*、likec4/diagram/custom、likec4/styles/*、react-hookz/web、xstate、xstate/*等依赖的类型合并进单一dist/index.d.mts——这正是 README 所说的“rollup type definitions”。由于likec4/diagram的类型被整体打进包内消费者导入likec4/react时无需再安装likec4/diagram即可获得完整类型。5. 产物规格只构建 ES 格式formats: [es]文件名固定为[name].mjsminify: true、cssMinify: true面向生产assetsInlineLimit: 1024 * 1024 * 22MB小于 2MB 的静态资源直接内联target: esnext不向下兼容转译。四、分发机制构建likec4时把 dist 复制为likec4/reactlikec4/react自身不发布但它的产物会在构建主包时被搬运到likec4内部。在 packages/likec4/tsdown.config.mts 中build:done钩子会调用copyReact()async function copyReact() { const from resolve(../react/dist/) if (!existsSync(from)) { throw new Error(likec4/react/dist/ not found: ${from}) } const to resolve(./react/) await emptyDir(to) await mkdir(to, { recursive: true }) await fs.copy(from, to) }值得注意的细节是如果likec4/react/dist/不存在构建会直接失败并抛出错误——也就是说likec4包的构建强依赖likec4/react先完成构建这是一个显式的构建顺序约束。作为对照同一钩子还负责搬运likec4/spa的静态应用与 MCP 的 app 资源。搬运完成后packages/likec4/package.json 的exports中出现了对外入口./react: { types: ./react/index.d.mts, import: ./react/index.mjs, default: ./react/index.mjs }于是likec4/react这个公共子路径就诞生了同时likec4/react被列入likec4的dependencies见 packages/likec4/package.json 中likec4/react: workspace:*。README 所说的“构建产物被复制到 likec4 包并可作为 likec4/react 使用”在这一层被完整兑现。五、消费方vite 插件虚拟模块与别名映射likec4/react的实际消费场景集中在 LikeC4 的 vite 集成中可以从三处源码看到调用关系别名解析packages/likec4/src/vite/aliases.ts 中likec4/react: resolve(pkg, react/index.mjs)把likec4/react映射到主包内复制出的react/index.mjs文件。虚拟模块代码生成packages/vite-plugin/src/virtuals/react.ts 生成的模块代码直接import { LikeC4ModelProvider as Provider, LikeC4View as GenericView, ReactLikeC4 as GenericReactLikeC4 } from likec4/react——即用户项目中的 React 渲染组件最终由likec4/react提供。类型声明packages/vite-plugin/src/modules.d.ts 为likec4:react虚拟模块声明类型时也从likec4/react导入LikeC4ViewProps、ReactLikeC4Props等类型packages/vite-plugin/tsconfig.json 中则把likec4/react的sources直接指回../react/src/index.ts保证开发时类型走源码。而在构建产物的外部依赖处理上packages/likec4/src/vite/config-react.ts 会把likec4/react、likec4/model与react、react-dom一并列为 external避免重复打包。六、在本仓库中构建与验证如果你想在本地跑通这条链路可以按顺序执行仅介绍操作方式不改动仓库内容# 1. 先构建 likec4/react内部包产出 dist/index.mjs 与 dist/index.d.mts pnpm --filter likec4/react build # 2. 再构建 likec4 主包build:done 钩子会把 react/dist 复制为 react/ 目录 pnpm --filter likec4 build之后检查packages/likec4/react/下应出现index.mjs、index.d.mts以及打包好的样式产物。如果你的使用场景是直接在自己的项目里引入 LikeC4 渲染组件通常不需要关心这个内部包标准路径是安装likec4包后通过likec4/react子路径导入类型、运行时入口均已由上述复制过程准备好。七、小结回看整条链路likec4/react的设计意图非常明确源码侧保持likec4/diagram单一份实现交付侧通过一个私有的打包包把渲染代码、Panda 样式与 rollup 类型合并成单一 ESM 产物再由主包构建复制为likec4/react公共入口。它同时解决了三个实际问题体积与依赖只外置 React 等运行时依赖内部依赖mantine/*、xyflow、xstate 等被打进产物消费方安装成本低类型完整性通过vite-plugin-dts的 bundle 能力dist/index.d.mts自带全部相关类型样式隔离通过 PostCSS 把:root/body改写为.likec4-shadow-root适配 Shadow DOM 渲染场景详见 packages/react/CHANGELOG.md 与 packages/diagram/src/shadowroot/。理解了likec4/react也就理解了 LikeC4 前端渲染代码“一份源码、多端分发”的骨架likec4/diagram是设计likec4/react是打包likec4/react是公共入口而likec4:react虚拟模块则是开发期的类型与代码桥梁参考 packages/vite-plugin/src/virtuals/react.ts。【免费下载链接】likec4Visualize, collaborate, and evolve the software architecture with always actual and live diagrams from your code项目地址: https://gitcode.com/GitHub_Trending/li/likec4创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表