0
votes

I have a play 2.0.2 (scala) project which uses bootstrap. I've added bootstrap as a git submodule so that I can easily change its version without having to copy individual files around.

My project structure looks like:

project
  |_ bootstrap
  |    \_ img
  |    \_ js
  |    \_ less
  |         \_ bootstrap.less
  |         \_ responsive.less
  |_ app
       \_ assets
            \_ css
                \_ my.less

My Build.scala has:

def customLessEntryPoints(base: File): PathFinder = (
    (base / "app" / "assets" / "css" * "*.less") +++
    (base / "bootstrap" / "less" / "bootstrap.less") +++
    (base / "bootstrap" / "less" / "responsive.less")
)

def externalAssets(base: File): PathFinder = (base / "bootstrap")
val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
  playAssetsDirectories <+= baseDirectory / "bootstrap",
  playExternalAssets <+= baseDirectory.apply(file => (file, externalAssets(_), "bootstrap")),
  lessEntryPoints <<= baseDirectory(customLessEntryPoints)
  // other settings
)

When I access the web application after doing "~ run", (or if I run play-copy-assets) I get:

[error] {file:/<path_to_project>/}<project>/*:play-copy-assets: No mapping for <path_to_project>\bootstrap\less\bootstrap.less
[error] application -

! Internal server error, for request [GET /] ->

play.api.UnexpectedException: Unexpected exception [RuntimeException: No mapping for <path_to_project>\bootstrap\less\bootstrap.less]
    at sbt.PlayReloader$$anon$2$$anonfun$reload$3$$anonfun$4$$anonfun$apply$12.apply(PlayReloader.scala:233) ~[na:na]
    at sbt.PlayReloader$$anon$2$$anonfun$reload$3$$anonfun$4$$anonfun$apply$12.apply(PlayReloader.scala:226) ~[na:na]
    at scala.Option.map(Option.scala:133) ~[scala-library.jar:0.11.3]
    at sbt.PlayReloader$$anon$2$$anonfun$reload$3$$anonfun$4.apply(PlayReloader.scala:226) ~[na:na]
    at sbt.PlayReloader$$anon$2$$anonfun$reload$3$$anonfun$4.apply(PlayReloader.scala:224) ~[na:na]
    at scala.Either$LeftProjection.map(Either.scala:183) ~[scala-library.jar:0.11.3]
java.lang.RuntimeException: No mapping for <path_to_project>\bootstrap\less\bootstrap.less
    at scala.sys.package$.error(package.scala:27) ~[scala-library.jar:na]
    at scala.Predef$.error(Predef.scala:66) ~[scala-library.jar:0.11.3]
    at sbt.Mapper$$anonfun$fail$1.apply(PathMapper.scala:26) ~[na:na]
    at sbt.Mapper$$anonfun$fail$1.apply(PathMapper.scala:26) ~[na:na]
    at sbt.Alternatives$$anon$1$$anonfun$$bar$1$$anonfun$apply$3.apply(PathMapper.scala:61) ~[na:na]
    at sbt.Alternatives$$anon$1$$anonfun$$bar$1$$anonfun$apply$3.apply(PathMapper.scala:61) ~[na:na]

I'd like the img and js subfolders of bootstrap to be served as assets (alongside or in a different path to the static ones in public) and the bootstrap|responsive.less files compiled into css and served as well.

The custom entry points work fine. That is, if I change them so they're all under /app and move the less files from bootstrap in there, they work. If I move the image and js files under public, that works too. But what I'm trying to achieve is the clean separation.

I'm pretty sure I haven't correctly understood how to use playAssetsDirectories and playExternalAssets, I've tried many variations for these settings. I'm not sure if what I'm trying is possible or how the settings should relate - e.g. does a lessEntryPoint have to be in an asset directory, and are externalAssets considered asset directories? Can anyone point out where I'm going wrong? Thanks in advance.

2

2 Answers

2
votes

If you're trying for clean separation, you may be better off disabling the internal compiler, and using an external tool like Crunch.

If you're not doing that, you may want to restrict Play to use a SINGLE file (my.less) and then include all the others from within there. You cannot compile LESS files using the internal compiler from the public directory -- they are static assets only. If you want Play to have access to them, they should go under app/stylesheets.

Also be aware that LESS 1.3 has some significant problems when trying to compile files that are in sub directories -- this has bitten multiple people on the play-framework mailing list, and Bootstrap in particular is known to blow up with errors.

1
votes

I have applied Bootstrap LESS into my projects as the following:

Have Bootstrap "import" files in asset directory. Play will compile them.

app\assets\bootstrap.less
app\assets\responsive.less

Have the other ".less" files in e.g. app\less

Edit the bootstrap.less file that the path refers to app\less directory

@import "../less/reset.less";

Physically the compliled CSS goes to

\target\scala-2.9.1\resource_managed\main\public

but you can still refer to them as they would be in the public

<link rel="stylesheet" media="screen" href="@routes.Assets.at("bootstrap.css")">