5

我使用 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)
4

1 回答 1

8

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

作为插件的源文件任务示例有 CoffeeScript、LESS 和 JSHint。其中一些获取源文件并生成目标 Web 资产,例如 CoffeeScript 生成 JS 文件。此类别中的插件在功能方面相互排斥,即只有一个 CoffeeScript 插件将获取 CoffeeScript 源并生成目标 JS 文件。总之,源文件插件产生网络资产。

我认为您尝试实现的目标属于这一类。

TL;博士; -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

解释

假设您在目录中有 sass 文件app/assets/<whatever>,并且您想在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
}

但这还不够。如果要保留目录结构,则必须将您的目录添加sassOutputDirresourceDirectories 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
}

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

resourceDirectories in Assets += sassOutputDir.value

这将确保保留目录结构。

于 2014-06-19T13:33:35.633 回答