解释在 monorepo 中共享一份 JSON schema 的策略
解读
在国内前端团队普遍采用 monorepo 的当下,“一份 JSON schema 多处复用” 的本质是:既要保证所有子包在 IDE、构建、运行时都能实时拿到同一份权威约束,又要避免“复制粘贴”带来的版本漂移。Grunt 作为任务编排者,需要把 schema 的分发、校验、升级、回滚全部自动化,并兼容国内常见的私有 npm、CNPM、Yarn Berry、Rush 等场景。面试官想听的是“如何用最少的配置,让 100+ 子包零感知地消费同一份 schema,且发布流水线不翻车”。
知识点
- Monorepo 拓扑:了解 pnpm workspace、Yarn workspace、Nx、Rush 的依赖提升规则,才能决定把 schema 放在哪个“最公共”的节点。
- JSON Schema 规范:draft-07/2019-09 的 id、$schema 字段差异,决定了能否用相对路径跨包引用。
- Grunt 插件体系:grunt-jsonschema-validate、grunt-contrib-copy、grunt-watch 的组合套路,以及如何用 grunt-task-loader 把任务注册到每个子包。
- 国内镜像与缓存:CNPM、Nexus、Verdaccio 的“包名重写”规则,可能让 @scope/schema 解析不到,需要 grunt-replace 做二次路径修正。
- 增量校验:grunt-newer 结合 git diff,只对变更子包做 schema 校验,10 万文件级 monorepo 也能 3 秒内完成。
- 版本对齐策略:semver 的“同仓同版本”与“子包独立版本”两种模型,schema 必须跟随“最严格”的子包走,否则会出现“校验通过但运行时失败”的线上事故。
答案
我在上一家公司的 60+ 子包 monorepo 里,用 Grunt 把共享 schema 拆成了三层策略,线上零事故运行两年:
-
仓库层统一源
在根目录建/schemas文件夹,把业务 schema 写成src/index.json,并在package.json里声明
"name": "@corp/schema", "version": "0.0.0-semver-sync", "private": true
这样任何子包都能用"@corp/schema": "workspace:*"拿到绝对同一份文件,彻底解决“复制粘贴”导致的版本漂移。 -
Grunt 自动化分发
根 Gruntfile 注册两段任务:grunt.registerTask('schema:link', () => { fs.writeFileSync('node_modules/@corp/schema/schema.json', fs.readFileSync('schemas/src/index.json')) })grunt.registerTask('schema:validate', () => { grunt.config('jsonschema.validate', { src: ['packages/*/src/**/*.config.json'], schema: 'node_modules/@corp/schema/schema.json' }) })
在grunt watch里把这两任务串起来:schema 文件一改,立即重新 link 并全量校验,开发者保存文件后 1 秒内就能看到 WebStorm 的红线提示,完全零配置。
-
发布流水线兜底
在 GitLab CI 里加一道 grunt 任务:grunt schema:validate --is-ci=true
如果校验失败,直接exit 1,阻断 merge。由于 schema 本身随代码仓一起打 tag,回滚时 schema 也自动回到对应历史版本,避免“新 schema 老代码”误报。
这套方案不依赖私有 npm 发布权限,也不侵入子包构建脚本,新同学 clone 仓库后 npm i && grunt bootstrap 就能直接开发,面试时只要讲清“workspace 协议 + grunt link + CI 强制门控”这三板斧,就能拿到高分。
拓展思考
如果未来要支持“子包按需裁剪 schema”,可以把 schema 拆成 core.json、feature-a.json,在 Gruntfile 里用 grunt.file.expand 动态拼接成 allOf 数组,再写回 node_modules/@corp/schema/index.json;同时把 grunt-jsonschema-validate 换成 ajv 的 compileAsync,利用 grunt-concurrent 并行校验,60 个子包 2000 份配置 5 秒跑完。
更进一步,把 schema 的变更记录打到 CHANGELOG.schema.md,用 grunt-conventional-changelog 自动生成“字段级”升级指南,让后端、测试、前端在企微群里一眼看懂“是否 Breaking”,这就是从“能用”到“好用”的差异化亮点。