I am using Sass as my CSS preprocesser, and I'm trying to have it run via the asset pipeline. I've tried implementing this sassTask as a source file task and as a web asset task, but I'm running into problems both ways.
If I run Sass as a source task (see below), it gets triggered during activator run
when a page is requested and updated files are found upon page reloads. The problem I'm running into is that the resulting CSS files are all getting dumped directly into target/web/public/main/lib
, instead of into the subdirectories reflecting the ones they are getting built into under the resources-managed
directory. I can't figure out how to make this happen.
Instead, I tried implementing Sass compilation as a web asset task (see below). Working this way, as far as I can tell, resources-managed
does not come into play, and so I compile my files directly into target/web/public/main/lib
. I'm sure I'm not doing this dynamically enough, but I don't know how to do it any better. But the biggest problem here is that the pipeline apparently does not run when working through activator run
. I can get it to run using activator stage
, but I really need this to work in the regular development workflow so that I can change style files as the dev server is running, same as with Scala files.
I have tried combing through these forums, through the sbt-web docs, and through some of the existing plugins, but I am finding this process to be highly frustrating, due to the complexity of SBT and the opaqueness of what is actually happening in the build process.
Sass compilation as a source file task:
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 compilation as web asset task:
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)
I think that according to the documentation related to the Asset Pipeline, a Source File task is a way to go:
I think what you try to achieve falls into this category.
TL;DR; -
build.sbt
Explanation
Assuming you have sass file in a
app/assets/<whatever>
directory, and that you want to create css files inweb/public/main/<whatever>
directory, this is what you could do.Create a task, which will read in files in the
app/assets/<whatever>
directory and subdirectories, and output them to our definedsassOutputDir
.This is not enough though. If you want to keep the directory structure you have to add your
sassOutputDir
to theresourceDirectories in Assets
. This is because mappings in sbt-web are declared like this:which means that all unmapped files are mapped using an alternative
flat
strategy. However the fix for it is simple, just add this to yourbuild.sbt
This will make sure the directory structure is preserved.