sbt如何按条件触发执行resource generator资源生成任务
问题描述
项目需要借助第三方CLI工具将UI源码构建后输出到资源目录,最初通过如下配置实现需求:
Compile / resourceGenerators += { // 具体UI构建逻辑 }.taskValue
上述配置可正常运行,但该资源生成任务耗时较长,期望仅在显式指定触发时(例如执行特定命令)才运行该任务。最初尝试通过创建自定义命令、执行run时切换不同Compile配置的方式实现,但查阅sbt中settings、tasks、commands相关资料后仍未理清实现思路。
补充说明:有方案提出可通过文件缓存机制实现仅在相关文件变更时执行任务,但该方案无法满足实际需求:开发阶段会单独启动UI开发服务器,UI文件变更时会自动触发热重载,开发过程中不需要执行耗时的UI构建任务,仅需要重新编译Scala类并重启应用即可。
实现方案
核心思路是解耦UI构建任务与默认编译资源生成流程,通过配置开关+自定义命令实现「默认跳过、显式触发才执行」的效果,具体配置步骤如下:
- 第一步:定义独立的UI构建任务,不要直接硬编码挂载到
resourceGenerators
// 单独定义UI构建任务,和默认编译流程解耦 lazy val buildUi = taskKey[Seq[File]]("调用第三方CLI构建UI资源,输出到项目资源目录") buildUi := { // 保留原有UI构建逻辑即可:调用第三方CLI、生成文件到指定资源目录 val outputDir = (Compile / resourceManaged).value / "ui" // 示例调用逻辑:Process("npm run build", baseDirectory.value / "ui").! // 最终返回所有生成的文件路径 Option(outputDir.listFiles()).map(_.toSeq).getOrElse(Nil) }
- 第二步:新增配置开关,控制是否在编译流程中自动执行UI构建,默认开发场景下关闭
lazy val autoBuildUi = settingKey[Boolean]("控制编译流程是否自动执行UI构建,默认关闭适配开发场景") ThisBuild / autoBuildUi := false
- 第三步:根据开关状态动态挂载任务,而非强制将UI构建加入资源生成链
// 仅当开关开启时,才将UI构建任务加入资源生成流程 Compile / resourceGenerators ++= { if (autoBuildUi.value) Seq(buildUi.taskValue) else Nil }
- 第四步:自定义快捷命令,实现显式触发带UI构建的运行、打包流程
// 自定义命令:构建UI后启动应用 commands += Command.command("runWithUi") { state => s"set ThisBuild / autoBuildUi := true" :: "run" :: s"set ThisBuild / autoBuildUi := false" :: state } // 自定义命令:构建UI后执行打包 commands += Command.command("packageWithUi") { state => s"set ThisBuild / autoBuildUi := true" :: "package" :: s"set ThisBuild / autoBuildUi := false" :: state }
使用说明
- 日常开发时直接使用原生的
compile、run命令即可,不会触发耗时的UI构建,Scala代码修改后可快速编译重启,UI部分靠独立启动的前端开发服务器实现热重载,不影响开发效率 - 需要单独生成UI资源时,直接执行
buildUi任务即可单独触发UI构建 - 需要本地验证生产环境UI效果、打正式包时,执行自定义的
runWithUi、packageWithUi命令即可,命令会临时开启自动构建开关,完成UI构建后再执行后续逻辑,流程结束后自动恢复开关默认值 - 如果需要在当前sbt会话内长期开启自动UI构建,直接执行
set ThisBuild / autoBuildUi := true即可,重启sbt后会恢复默认关闭状态
内容的提问来源于stack exchange,提问作者Ditti
相关产品推荐
相关产品推荐

