通过 Play 中的“activator run”运行时获取要编译的资产
Posted
技术标签:
【中文标题】通过 Play 中的“activator run”运行时获取要编译的资产【英文标题】:Get assets to compile when running via "activator run" in Play 【发布时间】:2014-08-08 19:23:38 【问题描述】:我使用 Sass 作为我的 CSS 预处理器,并且我试图让它通过资产管道运行。我尝试将此 sassTask 实现为源文件任务和 Web 资产任务,但两种方式都遇到了问题。
如果我将 Sass 作为源任务运行(见下文),它会在 activator run
期间被触发,当请求页面并在页面重新加载时找到更新的文件时。我遇到的问题是,生成的 CSS 文件都被直接转储到 target/web/public/main/lib
,而不是反映在 resources-managed
目录下的子目录中。我不知道如何做到这一点。
相反,我尝试将 Sass 编译实现为 Web 资产任务(见下文)。以这种方式工作,据我所知,resources-managed
不起作用,所以我将我的文件直接编译成target/web/public/main/lib
。我确定我没有足够动态地执行此操作,但我不知道如何做得更好。但这里最大的问题是管道在通过activator run
工作时显然没有运行。我可以使用activator stage
让它运行,但我确实需要它在常规开发工作流程中工作,以便我可以在开发服务器运行时更改样式文件,就像使用 Scala 文件一样。
我尝试过梳理这些论坛、sbt-web 文档和一些现有的插件,但我发现这个过程非常令人沮丧,因为 SBT 的复杂性和实际内容的不透明性发生在构建过程中。
Sass 编译作为源文件任务:
lazy val sassTask = TaskKey[Seq[java.io.File]]("sassTask", "Compiles Sass files")
sassTask :=
import sys.process._
val x = (WebKeys.nodeModules in Assets).value
val sourceDir = (sourceDirectory in Assets).value
val targetDir = (resourceManaged in Assets).value
Seq("sass", "-I", "target/web/web-modules/main/webjars/lib/susy/sass", "--update", s"$sourceDir:$targetDir").!
val sources = sourceDir ** "*.scss"
val mappings = sources pair relativeTo(sourceDir)
val renamed = mappings map case (file, path) => file -> path.replaceAll("scss", "css")
val copies = renamed map case (file, path) => file -> targetDir / path
copies map (_._2)
sourceGenerators in Assets <+= sassTask
将 Sass 编译为 Web 资产任务:
lazy val sassTask = taskKey[Pipeline.Stage]("Compiles Sass files")
sassTask :=
(mappings: Seq[PathMapping]) =>
import sys.process._
val sourceDir = (sourceDirectory in Assets).value
val targetDir = target.value / "web" / "public" / "main"
val libDir = (target.value / "web" / "web-modules" / "main" / "webjars" / "lib" / "susy" / "sass").toString
Seq("sass", "-I", libDir, "--update", s"$sourceDir:$targetDir").!
val sources = sourceDir ** "*.scss"
val mappings = sources pair relativeTo(sourceDir)
val renamed = mappings map case (file, path) => file -> path.replaceAll("scss", "css")
renamed
pipelineStages := Seq(sassTask)
【问题讨论】:
【参考方案1】:我认为根据与Asset Pipeline 相关的文档,源文件任务是一种方法:
作为插件的源文件任务示例有 CoffeeScript、LESS 和 JSHint。其中一些获取源文件并生成目标网络 资产,例如CoffeeScript 生成 JS 文件。此类别中的插件 就其功能而言,它们是相互排斥的,即 只有一个 CoffeeScript 插件会使用 CoffeeScript 源,并且 生成目标 JS 文件。综上,源文件插件产生web 资产。
我认为你试图达到的目标属于这一类。
TL;DR; - build.sbt
val sassTask = taskKey[Seq[File]]("Compiles Sass files")
val sassOutputDir = settingKey[File]("Output directory for Sass generated files")
sassOutputDir := target.value / "web" / "sass" / "main"
resourceDirectories in Assets += sassOutputDir.value
sassTask :=
val sourceDir = (sourceDirectory in Assets).value
val outputDir = sassOutputDir.value
val sourceFiles = (sourceDir ** "*.scss").get
Seq("sass", "--update", s"$sourceDir:$outputDir").!
(outputDir ** "*.css").get
sourceGenerators in Assets += sassTask.taskValue
说明
假设您在 app/assets/<whatever>
目录中有 sass 文件,并且您想在 web/public/main/<whatever>
目录中创建 css 文件,这就是您可以做的。
创建一个任务,它将读取app/assets/<whatever>
目录和子目录中的文件,并输出到我们定义的sassOutputDir
。
val sassTask = taskKey[Seq[File]]("Compiles Sass files")
val sassOutputDir = settingKey[File]("Output directory for Sass generated files")
sassOutputDir := target.value / "web" / "sass" / "main"
resourceDirectories in Assets += sassOutputDir.value
sassTask :=
val sourceDir = (sourceDirectory in Assets).value
val outputDir = sassOutputDir.value
val sourceFiles = (sourceDir ** "*.scss").get
Seq("sass", "--update", s"$sourceDir:$outputDir").!
(outputDir ** "*.css").get
但这还不够。如果要保留目录结构,则必须将 sassOutputDir
添加到 resourceDirectories in Assets
。这是因为 sbt-web 中的映射是这样声明的:
mappings :=
val files = (sources.value ++ resources.value ++ webModules.value) ---
(sourceDirectories.value ++ resourceDirectories.value ++ webModuleDirectories.value)
files pair relativeTo(sourceDirectories.value ++ resourceDirectories.value ++ webModuleDirectories.value) | flat
这意味着所有未映射的文件都使用alternativeflat
策略进行映射。但是解决方法很简单,只需将其添加到您的build.sbt
resourceDirectories in Assets += sassOutputDir.value
这将确保目录结构得以保留。
【讨论】:
天哪,老兄,你救了我的命。令人沮丧的是,我花了 48 小时试图弄清楚这一点,并且我阅读了整个 48 页的 SBT 教程。我想如果我阅读了整个文档,我最终可能会偶然发现这种行为,但我不得不说,SBT 幕后发生的所有“魔法”都非常令人沮丧。 @acjay 很高兴它对您有所帮助。如果你认为它是正确的,请你接受答案,所以问题不是没有答案。谢谢。 您使用sourceGenerators
,但您可能是指resourceGenerators
。无论如何,感谢您指出正确的方向。
@lpiepiora,非常感谢您的回答。这对我帮助很大!以上是关于通过 Play 中的“activator run”运行时获取要编译的资产的主要内容,如果未能解决你的问题,请参考以下文章
Play 中的单元测试!不需要测试 Play Server 的框架应用程序
如何部署和运行 Play! 2.1 通过 Jenkins 到 EC2