上一篇讲到”改得多了就固化进 blueprint”,这篇兑现这句话。当团队的定制点从三个涨到三十个——统一的公司异常码规范、内部组件库、合规要求的默认配置——继续靠 CUSTOM 标记搬运就是苦役。Blueprint 机制让这些定制变成”生成器原生行为”:你生成的项目第一天就长成公司的样子。
Blueprint 是什么
Blueprint 本质是一个 npm 包,包名约定以 generator-jhipster- 开头(如 generator-jhipster-foo)。安装后通过 --blueprints 选项激活:
npm install -g generator-jhipster-foo
jhipster --blueprints foo
# 或在 .yo-rc.json 中固化:
{
"generator-jhipster": {
"blueprints": [{ "name": "generator-jhipster-foo", "version": "1.2.0" }]
}
}
激活后,blueprint 可以接管或扩展任意子生成器(app、entity、spring-controller、kubernetes……)的任意 priority 阶段:修改上下文变量、替换模板、追加文件。核心概念叫 composability——blueprint 不 fork JHipster,而是声明”我要在哪些钩子上做什么”,JHipster 升级时 blueprint 跟着小版本走即可,fork 那种每次 major 都要重对齐的痛苦被结构性地缓解了。
flowchart TB
subgraph JH["generator-jhipster 9.x"]
A["app 子生成器<br/>initializing → prompting →<br/>configuring → writing → ..."]
end
subgraph BP["generator-jhipster-foo(npm 包)"]
B["声明钩子:<br/>inherit generator<br/>覆盖某模板 / 追加文件 / 改 context"]
end
JH -->|"composable 组合"| BP
BP --> C["产出的应用 =<br/>JHipster 标准 + 公司定制"]
什么场景值得做 blueprint
判断标准:定制点是否跨多个项目且稳定。
| 场景 | 典型定制 | 值不值 |
|---|---|---|
| 公司脚手架统一 | 包名前缀、统一分层目录、内部 parent pom | 值,一次投入全公司复用 |
| 内部组件库接入 | 前端注入公司 UI 库、主题、icon set | 值 |
| 合规默认值 | 审计日志默认开、密码策略、特定安全 header | 值,且避免每个项目漏配 |
| 生成部署脚本 | 公司内部 PaaS 的部署描述文件 | 值 |
| 单个项目的业务定制 | 某个实体的特殊接口 | 不值,放业务代码(第 23 篇) |
| 一次性尝试 | 试试某新技术组合 | 不值,先用 CLI 选项拼 |
我们是在第三个 JHipster 项目立项时动手的:三个项目各自维护一份”初始化后手工改造清单”(17 条),每条都是新人入职的学习成本。做成 blueprint 后清单归零。
开发一个最小 blueprint
以 generator-jhipster-company 为例,五步走完一个能用的骨架。
第一步:脚手架。 社区提供专用工具生成 blueprint 骨架:
npx generator-jhipster-bootstrap-blueprint company
# 产出 generator-jhipster-company/ 工程
cd generator-jhipster-company
npm install && npm run build
目录结构(TypeScript,与 9.x 生成器同构):
generator-jhipster-company/
├── generators/
│ ├── app/index.ts # 接管 app 子生成器
│ └── entity/index.ts # 接管 entity 子生成器(可选)
├── generators/app/templates/ # 你的模板(EJS)
├── package.json # name 必须 generator-jhipster-company
└── tsconfig.json
第二步:声明继承关系。 generators/app/index.ts:
import BaseGenerator from 'generator-jhipster/generators/base';
export default class extends BaseGenerator {
constructor(args, opts, features) {
super(args, opts, { ...features });
// 声明依赖 JHipster 的 app generator,sbsGenerator 表示组合而非整体替换
this.jhipsterContext = this.options.jhipsterContext;
}
get [BaseGenerator.INITIALIZING]() {
return {
...super.initializing,
validateCompanyConfig() {
this.log('company blueprint: initializing');
},
};
}
get [BaseGenerator.WRITING]() {
return {
...super.writing,
writeCompanyFiles() {
this.renderTemplate(
'security-headers.ejs', // blueprint 模板
this.destinationPath('src/main/resources/config/company-security.yml'),
);
},
};
}
}
关键是两个动作:...super.writing 保留 JHipster 原生行为(扩展),再追加自己的 writeCompanyFiles。如果去掉 super 调用,就是整体替换该 priority——composability 的两种粒度都在这。
第三步:改 context 而不是改模板。 想让生成的所有 *Resource.java 带公司异常码?不要复制修改 JHipster 模板(升级就脱轨),而是在 priority 里改共享 context,或在 blueprint 里用文件级后处理:
get [BaseGenerator.POST_WRITING]() {
return {
injectAuditDependency() {
// 给 pom.xml 追加公司审计依赖
this.packageJson.mergeDestinationJson?.('pom.xml', { /* ... */ });
},
};
}
第四步:注册与使用。 本地开发用 npm link:
cd generator-jhipster-company && npm link
mkdir /tmp/demo && cd /tmp/demo
jhipster --blueprints company --skip-checks
# 验证产物包含 company-security.yml 与追加的依赖
第五步:模板维护策略。 修改 JHipster 已有模板的正规姿势是”模板替换 + 上游对齐”:把上游模板拷进 blueprint 声明覆盖,并在 CI 里加一个每日任务 diff 上游模板,JHipster 一更新模板就提醒对齐。覆盖面要克制——覆盖的模板越多,跟版成本越高,这与第 22 篇的升级哲学一脉相承。
官方与社区 blueprint 生态
| Blueprint | 说明 |
|---|---|
| generator-jhipster-nodejs | 后端改用 Node.js(NestJS 风格) |
| generator-jhipster-dotnetcore | 后端改用 .NET Core |
| generator-jhipster-kotlin | Spring 后端改用 Kotlin |
| generator-jhipster-micronaut | 后端改用 Micronaut |
| generator-jhipster-migrate | 官方升级辅助(第 22 篇主力工具) |
| generator-jhipster-docker-azure 等 | 特定部署目标定制 |
| 社区各类 | graphql、grpc、特定前端库等,质量参差 |
选型时看三点:最近 release 是否跟上了当前 JHipster major、issue 区对 9.x 的支持情况、覆盖的模板数量(越少越稳)。
维护成本警告
Blueprint 不是免费午餐,投入前必须知道:
- 跟版义务:JHipster 半年一个 major,blueprint 每次都要验证。9.x 生成器 TypeScript 重写后,老 blueprint 从 JS 迁到 TS 是一次实打实的重构;
- 测试矩阵:blueprint 要在”多种应用选项组合”下都不坏,官方用 blueprint 测试套件跑组合矩阵,自研 blueprint 至少要覆盖自己常用的 3-4 种组合;
- 人员单点:懂生成器 internals 的人团队里通常只有一两个,文档化(为什么加这个钩子、上游模板为什么这么改)比业务代码更不能省;
- 退路:定制点失效时要能从 blueprint 摘除。每个钩子保持小而独立,避免互相纠缠成一张拆不掉的网。
我们的量级参考:初始投入约 3 人周,此后每次 JHipster major 花 2-4 人日对齐,换来三个项目 × 每年两次升级的定制零搬运。项目数量少于两个时,这笔账是亏的。
小结
- Blueprint 是 npm 包 +
--blueprints选项,composability 让你在钩子上扩展而非 fork JHipster,天然比 fork 抗升级。 - 跨项目且稳定的定制(脚手架、组件库、合规默认值)值得做,单项目业务定制不值得。
- 最小闭环五步:脚手架 → 继承声明 → 改 context/追加文件 → npm link 验证 → 上游模板对齐机制。
- 维护成本真实存在:跟版、测试矩阵、人员单点,两个项目以下慎入。
系列导航
- 上一篇:自定义业务模块——不改生成代码的哲学
- 下一篇:微服务拆分实战
- 相关阅读:blueprint 是第 23 篇手改问题的终极解法;migrate blueprint 助攻第 22 篇升级策略