在文件注释中编写模板,动态更新内容片段

在 Makeflow,我们使用 mono repo 来组织主项目,经常需要在不同的文件(如 README.md、gitlab-ci.yml、Dockerfile、tsconfig.json 等)中引用各种包、文件或目录。项目内容的增减都可能导致相关引用的修改,不熟悉相关内容的同事,常常会出现错误或者遗漏。而其中一些问题,可能很难及时发现。

为了解决这类问题,我们需要尽量将相关内容的更新自动化:使用模板和脚本自动更新,并加入 CI。在这个过程中,我们引入了一个新工具: makeflow/inplate ,它提供了一套简单的注释语法,可以将 handlebars 模板写在文件注释中,通过配置的变量来生成注释区域的内容。

以我们的主项目根目录 tsconfig.json 文件为例(当然实际上我们有几十个引用 ):

{
  "references": [
    // @inplate
    // {{#each nonRootTSProjectPaths}}
    // {"path": "{{this}}"}{{#unless @last}},{{/unless}}
    // {{/each}}
    // @plate
    {"path": "app/pack"},
    {"path": "app/src/program"},
    {"path": "app/src/service-worker"},
    {"path": "website/pack"},
    {"path": "website/src/program"}
    // @end
  ],
  "files": []
}

在注释 @inplate@plate 之间就是内容片段的 handlebars 模板:

{{#each nonRootTSProjectPaths}}
{"path": "{{this}}"}{{#unless @last}},{{/unless}}
{{/each}}

@plate@end 之间则是会被自动更新的内容片段。

这里缺失的一块儿是变量 nonRootTSProjectPaths ,我们将通过 inplate 的配置文件 inplate.config.js 提供:

const Path = require('path');

const Glob = require('glob');

const nonRootTSProjectConfigPaths = Glob.sync('*/**/tsconfig.json', {
  ignore: '**/node_modules/**',
  dot: true,
});

const nonRootTSProjectPaths = nonRootTSProjectConfigPaths.map(path =>
  Path.dirname(path),
);

module.exports = {
  'tsconfig.json': {
    data: {
      nonRootTSProjectPaths,
    },
  },
};

这样一来,我们就可以通过执行 inplate --update 来更新 tsconfig.json 中的项目引用了:

在 CI 中,则可以使用 inplate --assert 命令确认当前相关配置文件没有需要修改的地方。

Inplate 支持多种注释风格和使用方式,生成内容后会自动使用 prettier 进行格式化(如果有安装和配置), 请移步 项目主页 了解更多。

如果你正在维护的项目中,也有类似的情况,inplate 或许可以是一个趁手的小工具:

  • 项目引用、文件、文件夹列表维护(结合 Glob 等小工具)。
  • 环境变量列表维护(通过 mock 配置文件中的相关方法调用获取)。
  • 同步代码片段到文档(结合 ts-morph 等小工具)。
  • 等等。

如果有任何使用问题,也欢迎评论或者通过 issue 告诉我们。

Makeflow(makeflow.com)让团队经验可以像文档一样详细地记录在流程中,指导和验证工作实践。每一次经验的迭代都可以通过任务的执行自然“推送”到整个团队,消除工作流程从想法到实践、从实践到改进之间的多种障碍。大到产品迭代管理,小到监控报警处置:记录、实践、再记录,把每一次进步写入团队基因——延续、变化、可复制。