Shared publicly  - 
 
Using #lesscss with #playframework 2.0

LESSCSS
LESSCSS is a tool using variables, mixins and other goodness to produce CSS.
http://lesscss.org/
In LESSCSS, stylesheets are concise and easier to maintain.

Twitter bootstrap CSS
The Twitter bootstrap is a stylesheet written in LESS. It is a very good basis to start writing HTML applications.
http://twitter.github.com/bootstrap/

Playframework 2.0
#playframework 2.0 is a web framework written in scala with java API.
Its stateless and asynchronous core helps writing scalable web applications.
More information on http://www.playframework.org/2.0. Please note that the version 2.0 is not ready for production yet.

Using LESSCSS with play 2.0
In a Play 2.0 application, copy the LESS files from twitter bootstrap in app / assets / stylesheets.
By default, Play tries to compile all LESS files found in this folder.
This cannot work with the LESS files from twitter bootstrap. Only the main bootstrap.less file that includes the other ones should be compiled.

For this, change the configuration in project / Build.scala:
val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
lessEntryPoints <<= baseDirectory(_ / "app" / "assets" / "stylesheets" ** "bootstrap.less")
)

The LESS compiler will now produces two files: bootstrap.css and the minified version bootstrap.min.css
You can now use this CSS like this:
<link rel="stylesheet" href="@routes.Assets.at("stylesheets/bootstrap.css")">

Let's make a change in a LESS file. For example, change a color in variables.less.
Reload the page in the browser and, in dev mode, you can see your change in the CSS file.
No need to restart, everything is compiled on the fly whenever a file is modified.

Responsive design
With twitter bootstrap, you can also use a responsive design. The layout changes according to the dimension of the browser window, which let use the same website for browsers on desktops, tablets and mobile devices.

For that, we need to compile 2 files: bootstrap.less and responsive.less with the following Build.scala:
val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
lessEntryPoints <<= (sourceDirectory in Compile)(base => (
(base / "assets" / "stylesheets" / "bootstrap.less") +++
(base / "assets" / "stylesheets" / "responsive.less")
))
)

The 2 produced CSS files can now be used. In Production mode, it is even better to include the minified versions like this:

@minified=@{ if (play.Play.isProd()) ".min" else "" }
<link rel="stylesheet" href="@routes.Assets.at("stylesheets/bootstrap"+ minified + ".css")">
<link rel="stylesheet" href="@routes.Assets.at("stylesheets/responsive"+ minified + ".css")">

LESSCSS is well integrated in #playframework .
In developement, the changes are immediately applied.
In Production, the minified version is optimal.
35
9
Mathias Lin's profile photoHelena Hjertén's profile photoRashid Wakileh's profile photoYann Simon's profile photo
26 comments
 
Please note that you need the master version (in GIT) from play to compile the most actual LESS files from bootstrap.
 
Or the 2.0 version of bootstrap (that uses the same Less version than Play 2.0)
 
or even the 2.0.1 version of bootstrap which works with Play 2.0 :)
 
I have followed the instructions on https://github.com/playframework/Play20/wiki/Tips to add Twitter Bootstrap to my play2 application. Upon compiling I get the error "variable @baseLineHeight is undefined" in accordion.less. The variables.less, where the variable is defined with its default of 18px, is in the same directory as the bootstrap.less (and all other twitterbootstrap-less-files), namely /app/assets/stylesheets/bootstrap/.

Running "play-less-entry-points" from the play console gives me the list of .less-files in that directory, so I draw the conclusion that it compiles them in lexical order, rather than starting with bootstrap.less and hence, doesn't have the definition set properly.

Am I overlooking anything? Anyone that has a clue to what I can do to fix this?
 
Did you imported the bootstrap variables.less file in yours ? The first lines of your less file might be
@import"./bootstrap/variables.less"
@import"./bootstrap/mixins.less"
for instance
 
So far, I have not created any .less-files of my own. I'm trying to get it to work with the "vanilla" version of bootstrap first.
While fiddling around the variable undefined error "went away" - I can't really tell you why yet, but I was switching between these two settings in Build.scala.

1st Version (from https://github.com/playframework/Play20/wiki/Tips):
-----------------

val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
lessEntryPoints <<= baseDirectory(customLessEntryPoints)
)

def customLessEntryPoints(base: File): PathFinder = (
(base / "app" / "assets" / "stylesheets" / "bootstrap" * "bootstrap.less") +++ (base / "app" / "assets" / "stylesheets" * "*.less")
)
2nd Version (from the guide above):
------------------

val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
lessEntryPoints <<= (sourceDirectory in Compile)(base => (
(base / "app" / "assets" / "stylesheets" / "bootstrap" * "bootstrap.less") +++
(base / "app" / "assets" / "stylesheets" * "*.less")
))
)
However, this time the .less-files doesn't seem to be compiled at all, and the play-less-entry-points command only lists

$ play-less-entry-points
[info]
[info]
$

(Edit: The reason I believe it doesn't compile at all is because of the above and because the page can't load (find) the bootstrap.min.css)
 
+Yann Simon I used the build.scala method. With the "final" .less file, do you mean the bootstrap.less? From what I see, this is the one that does all the imports - that's why I thought it was strange that it tried to compile the accordion.less file first.
 
<embarrassed blush>
I found the problem... spelling misstake in one of my folder names.
</ embarrassed blush>

However, I now ran into the issue of "EcmaError: TypeError: Cannot call method "charAt" of undefined (less-1.2.1.js#338)" - But I see this is a known error, so I'll go ahead and downgrade to 2.0.1 of bootstrap (or possibly upgrade to the latest release of play, since I saw something about a fix for this in one of the newer builds.)

+Yann Simon +andy petrella Many thanks for your support. I appreciate it a lot!
 
Glad to hear you found the problem!! Enjoy with Play and Bootstrap ^^
 
Just to let you guys know - It works beautifully with bootstrap v2.0.1 now! I feel like a kid at Xmas that just got his new toy to work! ;-)
 
Glad you found your problem. Yeah, the integration of LESS is very enjoyable!
 
I also followed this guide, thanks +Yann Simon for this, and I also ran in to the same issue as +John Ekare , that all the .less files were tried to be compiled an alphabetical order, not only the ones mentioned in Build.scala, even though the play-less-entry-points looked correct when ran on command line. I found that I had to restart the app (stop and 'play run' again) , afterwards it was working ok (does that make sense?). I also ran into the same issue with bootstrap 2.0.3 as reported by +John Ekare but it's working fine with 2.0.1 now :)
 
+Mathias Lin because you changed the configuration of your application, it makes sense to reload it (stop and start, or "reload" in the console)
 
Ok, got it. I'm new to Play!, I thought with Play! everything is about being 'hot deployable', so I assumed also the config. Thanks for the info.
 
yes, almost everything is hot reloaded, except some deep configuration like this, or like adding a new module.
 
Are there any nice new or updated blogs/documentation on how this is done for Play 2.0.4 (without having to build Play from trunk? And is there somewhere a matrix that shows which Twitter Bootstrap version is compatible with which Play version? 
 
Is there a way to pass in configuration options to the less compiler?
 
+Yann Simon Thank you for you reply, lessOptions takes a Seq of strings, how can I pass in a key value option?
 
+Yann Simon Actually, I went through the playframework code and it looks like "lessOptions" are not getting passed to the LessCompiler :(
Add a comment...