Cannot get sbt-concat to bundle styles from sbt-sass or sbt-less

574 views Asked by At

(Example project provided) I cannot get sbt-concat to work as designed to find and concatenate stylesheets that result from styles that may be produced from preprocessor tasks. In my production app, I'm trying to use it to bundle select minified output files from sbt-sass. It does not work within the complex setup of that project, so I created an example project to see if I could get it to work at all. It does not work in the example project either. Here is a test project build.sbt that tries to create several bundles, with just about every possibility I can think of, just to see if any of them work (public Github repo, which you should be able to clone and immediately replicate the problem):

import com.typesafe.sbt.web.Import.WebKeys._
import com.typesafe.sbt.web.pipeline.Pipeline

name := """sbt-concat-test"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala, SbtWeb)

scalaVersion := "2.11.1"

libraryDependencies ++= Seq(
  jdbc,
  anorm,
  cache,
  ws
)

resolvers += Resolver.sonatypeRepo("releases")

includeFilter in (Assets, LessKeys.less) := "*.less"

excludeFilter in (Assets, LessKeys.less) := "_*.less"

val myPipelineTask = taskKey[Pipeline.Stage]("Some pipeline task")

myPipelineTask := { mappings => println(mappings); mappings }

pipelineStages := Seq(myPipelineTask, concat)

Concat.groups := Seq(
  "style-group1.css" -> group(sourceDirectory.value  ** "*.css"),
  "style-group2.css" -> group(baseDirectory.value  ** "*.css"),
  "style-group3.css" -> group((sourceDirectory in Assets).value  ** "*.css"),
  "style-group4.css" -> group(target.value  ** "*.css"),
  "style-group5.css" -> group(Seq("core.css", "styles/core.css", "assets/styles/core.css", "app/assets/styles/core.css")),
  "style-group6.css" -> group(Seq("lessStyle.css", "ui/lessStyle.css", "styles/ui/lessStyle.css", "assets/styles/ui/lessStyle.css", "app/assets/styles/ui/lessStyle.css")),
  "style-group7.css" -> group(Seq("sassStyle.css", "ui/sassStyle.css", "styles/ui/sassStyle.css", "assets/styles/ui/sassStyle.css", "app/assets/styles/ui/sassStyle.css")),
  "style-group8.css" -> group(Seq("**/*.css"))
)

I run ; clean; reload; stage from activator to test. I see asset source files copied over into the target folder, with the following results for the declared bundles:

  • style-group1.css does not exist
  • style-group2.css contains the contents of button.css and core.css
  • style-group3.css contains the contents of core.css and button.css
  • style-group4.css does not exist
  • style-group5.css contains only the contents of core.css
  • style-group6.css contains only the contents of compiled lessStyle.scss
  • style-group7.css contains only the contents of compiled sassStyle.scss
  • style-group8.css does not exist

I do not understand why the 2nd and 3rd cases do not pick up the preprocessor-produced css files, yet the tailor-made 6th and 7th cases do. Perhaps notably, the result of myPipelineTask shows PathMappings for all source files, as well as the derived css and sourcemaps from the Sass and Less tasks.

1

There are 1 answers

1
acjay On BEST ANSWER

According to Typesafe support, the source of my woes is the fact that sbt-concat implements its PathFinder logic in such a way as to only pick up assets that are verbatim the same filename as in the source directory. The sequence of relative filenames works for files in the target directory, but has no pattern matching. This is rather unfortunate.

What does work is to construct a Seq of output files that will exist post-compilation by using a PathFinder on the source directory. So for .scss files, something like:

Concat.groups := {
  // Determine the output names of the style files to bundle
  // This is really roundabout because sbt-concat only offers 2 ways of
  // specifying files, relative paths and using a PathFinder, and the
  // latter approach restricts itself to source files instead of output files.
  val sourceDir = (sourceDirectory in Assets).value
  val scssFiles = (sourceDir ** "*.scss").getPaths
  val scssRelativePaths = scssFiles.map(_.stripPrefix(sourceDir.getPath).stripPrefix("/"))
  val outputRelativePaths = scssRelativePaths.map(_.stripSuffix(".scss") + ".min.css")
  Seq("bundle.min.css" -> group(outputRelativePaths))
}

As a side note, another quirk of sbt-concat is that it doesn't put its new files in its own directory in web-assets:assetsTarget to separate them from artifacts of other pipeline stages. The Concat.parentDir is also unnecessary because you can simply anything you would place in that variable as a prefix for your bundle file name directly.