blocks 核心原理:generate-registry 如何自动生成 shadcn Registry JSON(依赖分析 + 路径重写)

📅 发布时间:2026/10/11 22:41:45
blocks 核心原理:generate-registry 如何自动生成 shadcn Registry JSON(依赖分析 + 路径重写)
前端UI组件设计系统【免费下载链接】blocksAn open-source library of UI blocks. Built with React, Tailwind and shadcn/ui项目地址https://gitcode.com/gh_mirrors/blocks28/blocks点击查看免费下载在 blocks 开源 UI 块库中generate-registry脚本负责 shadcn Registry JSON 的自动生成它扫描 content/components/ 下所有 UI 块自动完成依赖分析 路径重写产出符合 shadcn Registry 规范的 JSON 文件。本文带你彻底看懂这套自动化机制——为什么新增一个块后用户就能一行命令安装。想动手验证的话先克隆仓库git clone https://gitcode.com/gh_mirrors/blocks28/blocks 一句话总结blocks 把UI 块代码 依赖清单 安装目标路径全部打包进 JSONshadcn CLI 拿到这份 JSON 就知道该装哪些 npm 包、放哪些 shadcn 组件、把文件写到项目的哪个位置。 目录约定blocks 块库的原料仓自动生成的前提是仓库本身遵守一套严格的目录约定。scripts/generate-registry.ts 开头就锁定了扫描根目录const root content/components; const out public/r; const skipPattern /\.(d|test|spec|stories)\.[jt]sx?$/;规则很简单content/components/下的每个子目录 一个分类如 stats/、sidebar/分类下的单个文件如table-01.tsx或文件夹如 sidebar-01/ 一个块blockisSource()配合skipPattern会过滤掉.d.ts、测试、Storybook 文件只收集纯源码保证生成的 JSON 干净无噪音见 scripts/generate-registry.ts。 第一步递归收集文件walk 函数对于文件夹形式的块walk 函数会递归遍历整个目录把所有源文件汇总成一个扁平列表async function walk(dir: string): Promisestring[] { const files: string[] []; for (const entry of await fs.readdir(dir, { withFileTypes: true })) { const file path.join(dir, entry.name); if (entry.isDirectory()) files.push(...(await walk(file))); else if (entry.isFile() isSource(entry.name)) files.push(file); } return files; }以sidebar-01为例walk收集到的文件会按字母序逐个处理——这正是后面 JSON 里files数组的原始顺序。单文件块则跳过这一步直接使用文件本身scripts/generate-registry.ts。 第二步place 函数决定文件类型 安装目标路径收集到文件后place 函数要回答两个问题这个文件在用户项目里是什么身份装到哪里它先检查相对路径中是否出现app、lib、hooks这类特殊目录文件所在位置文件类型type安装目标targetapp/**registry:pageapp/xxxlib/**registry:liblib/xxxhooks/**registry:hookhooks/xxx其他组件registry:componentcomponents/{块id}/xxx其他单文件块registry:componentcomponents/xxx几个值得注意的细节多文件块统一带上块 id 目录前缀。例如 sidebar-01/nav-main.tsx 的 target 是components/sidebar-01/nav-main.tsx——不同块装进同一项目互不冲突。类型文件单独归类。名为types.ts/*.types.ts或位于types/目录的文件会标记为registry:file和普通组件区分开scripts/generate-registry.ts。title 和 categories 来自元数据content/blocks-metadata.ts 里登记的块会取用name和category未登记的块则用 id 转大写首字母生成默认标题scripts/generate-registry.ts。 第三步依赖分析自动算出 registryDependencies 和 dependencies这是自动二字的核心。脚本对每个文件的源码跑一遍正则捞出所有from ...的导入交给 addDep 分类function addDep(name: string, registry: Setstring, packages: Setstring) { if (name.startsWith(/components/ui/)) { registry.add(name.split(/).pop()!); return; } if (name.startsWith(.) || name.startsWith(/) || name.startsWith(/)) return; // node 内置模块、react/next 全家桶直接跳过 // 其余第三方包scope 包取前两段普通包取第一段 packages.add( name.startsWith() ? name.split(/).slice(0, 2).join(/) : name.split(/)[0] ); }四种导入四个去向/components/ui/xxx→ 提取组件名进registryDependenciesshadcn 组件依赖相对路径./、../或项目内/→ 跳过块内互相引用由路径重写接管Node 内置模块、react、next、next/*→ 跳过scripts/generate-registry.ts 预置了完整白名单其余第三方包 → 取包名主干进dependenciesnpm 依赖scope 包如tabler/icons-react只取前两段用真实产物验证一下。table-01的 public/r/table-01.json 中registryDependencies: [button, collapsible, table]—— 源码里 import 了/components/ui/下的这三个 shadcn 组件dependencies: [lucide-react]—— 源码里 import 了图标库全部是正则自动扫出来的没有一处手工登记。✍️ 第四步路径重写rewrite让代码搬家后也能跑光收集文件还不够——块源码里写着import ... from ./nav-main这样的相对导入文件一旦装进用户项目、路径变了直接照搬必然报错。rewrite 函数专门干这件事function rewrite(code: string, type: File[type], id: string) { const base type registry:lib || type registry:hook ? /lib/${id} : /components/${id}; return code.replace( /import\s(type\s)?({[^}]}|\*\sas\s\w|\w)\sfrom\s)(.?)[]/g, (match, typeWord, imported, prefix, relative) type registry:page prefix ./ ? match : import ${typeWord ?? }${imported} from ${base}/${relative.replace(/^components\//, )} ); }逻辑拆解正则只匹配相对导入./或../开头第三方包、shadcn 组件、react 等绝对导入原样保留相对路径统一改写成用户项目里稳定存在的/别名/components/{块id}/xxxlib 和 hooks 类文件则指向/lib/{块id}页面文件的特例registry:page且前缀是./的导入保持不动——页面内部的./引用在用户项目里同样有效重写反而画蛇添足看一个真实的改写前后对比。sidebar-04/app/page.tsx 源码中import { AppSidebar } from ../app-sidebar;写入 public/r/sidebar-04.json 后变成了import { AppSidebar } from /components/sidebar-04/app-sidebar;正是这一步保证了npx shadcn add装下来的代码开箱即用。 最终产物public/r/ 下的 Registry JSON所有分析结果由 scripts/generate-registry.ts 写入 public/r/总表public/r/registry.json符合 shadcnregistry.jsonschemaname: blocks汇总全部 70 个块的完整 items 列表单块文件每个块一个独立 JSON如 public/r/sidebar-01.json、public/r/chat-03.json符合registry-item.jsonschema以sidebar-01为例产物里 7 个文件全部带着 type target 重写后的 content依赖清单为 7 个 shadcn 组件 2 个 npm 包源文件typetargetindex.tsxregistry:componentcomponents/sidebar-01/index.tsxapp-sidebar.tsxregistry:componentcomponents/sidebar-01/app-sidebar.tsxnav-main.tsxregistry:componentcomponents/sidebar-01/nav-main.tsxtypes.tsregistry:filecomponents/sidebar-01/types.ts而chat-03这种带app/目录的块app/chat/page.tsx会被标记为registry:page、data.json同样归入app/chat/下——与 shadcn CLI 的写入规则完全对齐。⚙️ 如何运行并消费这份 JSON运行见 package.jsonbun run generate:registry构建脚本build:next会在next build之前自动串联执行generate:registry、generate:blocks-data和generate:rss见 package.json所以产物始终与源码同步无需人工维护。消费用户只需把下面这段配置粘贴进项目的components.jsoncomponents/registry-setup.tsx 中内置了这个一键复制对话框registries: { blocks-so: https://blocks.so/r/{name}.json }之后一条命令即可安装任意块npx shadcnlatest add blocks-so/sidebar-01shadcn CLI 会自动拉取对应 JSON按dependencies装 npm 包、按registryDependencies拉 shadcn 组件、按target把重写好的文件写入项目——整个过程完全自动化。 新增块的完整工作流理解了上面四步再看新增流程就非常清晰了运行bun run scripts/add-block.ts --category tables --id table-01 --name Basic Data Table --type filescripts/add-block.ts 生成组件模板并自动追加一条 content/blocks-metadata.ts 元数据实现组件代码普通 React shadcn/ui Tailwind运行bun run generate:registryJSON 自动进入public/r/总结三步走透 shadcn Registry JSON 自动生成步骤关键函数解决的问题文件分类place每个文件装成什么类型、放到项目哪个路径依赖分析addDep自动算出 shadcn 组件依赖与 npm 包依赖路径重写rewrite相对导入 →/别名代码搬家后依旧可用这套机制让 blocks 的注册表零手工维护源码是唯一事实来源JSON 只是它在构建时的一次编译产物。想继续深挖可以从 scripts/ 目录的其他脚本入手——例如 scripts/generate-blocks-data.ts 负责把块源码内联进网站构建scripts/generate-rss.ts 负责生成订阅源。赞分享前端UI组件设计系统【免费下载链接】blocksAn open-source library of UI blocks. Built with React, Tailwind and shadcn/ui项目地址https://gitcode.com/gh_mirrors/blocks28/blocks点击查看免费下载相关推荐如何把自己开源的 Registry 添加到 shadcn/ui 官方开源 Registry 索引如何把自己开源的 Registry 添加到 shadcn/ui 官方开源 Registry 索引 你维护着一个开源的组件 Registry比如 acme前端UI组件设计系统Coolify 中的 shadcn Registry 实战源码级注册表的编写、依赖寻址与 GitHub 分发Coolify 中的 shadcn Registry 实战源码级注册表的编写、依赖寻址与 GitHub 分发 本文以 Coolify 仓库中为 AI Agen后端云原生容器编排运维DevOps解放你的Synology NAS3步解锁非官方M.2驱动器存储潜力解放你的Synology NAS3步解锁非官方M.2驱动器存储潜力 你是否曾为Synology NAS上那些闲置的M.2插槽感到惋惜明明插入了高速NVMe固创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考