通过"激活器运行"运行时获取要编译的资产在Play中

时间:2014-06-18 13:13:22

标签: scala playframework sbt sbt-web

我使用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编译为网络资产任务:

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 个答案:

答案 0 :(得分:7)

我认为根据与Asset Pipeline相关的文档,源文件任务是一种方法:

  

作为插件的源文件任务示例是CoffeeScript,LESS和   JSHint。其中一些采用源文件并生成目标Web   资产例如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
}

这意味着所有未映射的文件都使用alternative flat策略进行映射。但是,修复它很简单,只需将其添加到build.sbt

即可
resourceDirectories in Assets += sassOutputDir.value

这将确保保留目录结构。