Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Reverted to original @import behavious in Less CSS

Imports are once again inlined before the top of the file rather than at
the point of the import. There are two reasons for this change:

 1. By inlining before the top of the file, the plugin can ensure that
    each Less/CSS library is included once and once only in the output file.
    This ensures efficient compilation of complex libraries such as Twitter
    Bootstrap, producing several 100% speedup.

 2. The [W3C specification] for `@import` statements states that they are
    only allowed at the top of a file. The two inlining behaviours of sbt-less
    are consistent if this restriction is applied by the stylesheet author.

[W3C specification]: http://www.w3.org/TR/CSS21/cascade.html#at-import
  • Loading branch information...
commit 466d5f1b80133b406ef22f59927153ca30e916d0 1 parent 7d07d68
@davegurnell davegurnell authored
View
17 README.markdown
@@ -35,6 +35,23 @@ Support for SBT 0.11.3 - thanks to [Shikhar Bhushan] for this fix.
Added the [sbt-tipi] plugin for the [Tipi] templating language.
+Removed features:
+
+Reverted to the original placement of Less/CSS `@import` statements.
+Imports are once again inlined before the top of the file rather than at
+the point of the import. There are two reasons for this change:
+
+ 1. By inlining before the top of the file, the plugin can ensure that
+ each Less/CSS library is included once and once only in the output file.
+ This ensures efficient compilation of complex libraries such as Twitter
+ Bootstrap, producing several 100% speedup.
+
+ 2. The [W3C specification] for `@import` statements states that they are
+ only allowed at the top of a file. The two inlining behaviours of sbt-less
+ are consistent if this restriction is applied by the stylesheet author.
+
+[W3C specification]: http://www.w3.org/TR/CSS21/cascade.html#at-import
+
Version 0.4 (current stable release)
====================================
View
3  sbt-less/src/main/scala/com/untyped/sbtless/Graph.scala
@@ -11,7 +11,8 @@ case class Graph(
val templateProperties: Properties,
val downloadDir: File,
val lessVersion: Plugin.LessVersion,
- val prettyPrint: Boolean
+ val prettyPrint: Boolean,
+ val useCommandLine: Boolean = false
) extends com.untyped.sbtgraph.Graph {
type S = com.untyped.sbtless.Source
View
70 sbt-less/src/main/scala/com/untyped/sbtless/LessSource.scala
@@ -2,11 +2,11 @@ package com.untyped.sbtless
import org.mozilla.javascript.{ Callable, Context, Function, FunctionObject, JavaScriptException, NativeArray, NativeObject, Scriptable, ScriptableObject }
import org.mozilla.javascript.tools.shell.{ Environment, Global }
-import java.io.InputStreamReader
import java.nio.charset.Charset
import org.mozilla.javascript._
import sbt._
import scala.collection._
+import scala.sys.process.Process
/**
* Stub out a basic environment for Rhino that emulates running it on the command line.
@@ -54,7 +54,6 @@ object LessSource {
def parseImport(line: String): Option[String] =
importRegex.findAllIn(line).matchData.map(_.group(1)).toList.headOption
-
val compileFunction: String =
"""
|function compile(scriptName, code, min) {
@@ -98,28 +97,49 @@ case class LessSource(val graph: Graph, val src: File) extends Source {
completeRawSource
}
- val minify = !graph.prettyPrint
+ if(graph.useCommandLine) {
+ val temp = java.io.File.createTempFile(src.getName, ".less")
+ val out = new java.io.PrintWriter(new java.io.FileWriter(temp))
+ out.println(less)
+ out.close()
- withContext { ctx =>
- val scope =
- graph.lessVersion match {
- case Plugin.LessVersion.Less130 => less130Scope(ctx)
- case _ => earlyLessScope(ctx)
+ (Process(Seq("lessc", temp.getCanonicalPath, des.getCanonicalPath)) !) match {
+ case 0 => Some(des)
+ case n => sys.error("Could not compile %s source %s".format(graph.pluginName, des))
+ }
+ } else {
+ val minify = !graph.prettyPrint
+
+ withContext { ctx =>
+ try {
+ val scope =
+ graph.lessVersion match {
+ case Plugin.LessVersion.Less130 => less130Scope(ctx)
+ case _ => earlyLessScope(ctx)
+ }
+
+ val lessCompiler =
+ scope.get("compile", scope).asInstanceOf[Callable]
+
+ val css =
+ lessCompiler.call(
+ ctx,
+ scope,
+ scope,
+ Array(src.getPath, less, minify.asInstanceOf[AnyRef])
+ ).toString
+
+ IO.write(des, css)
+ Some(des)
+ } catch {
+ case e: JavaScriptException =>
+ val error = e.getValue.asInstanceOf[Scriptable]
+ val line = ScriptableObject.getProperty(error, "line" ).asInstanceOf[Double].intValue
+ val column = ScriptableObject.getProperty(error, "column" ).asInstanceOf[Double].intValue
+ val message = ScriptableObject.getProperty(error, "message").asInstanceOf[String]
+ sys.error("%s error: %s [%s,%s]: %s".format(graph.pluginName, src.getName, line, column, message))
}
-
- val lessCompiler =
- scope.get("compile", scope).asInstanceOf[Callable]
-
- val css =
- lessCompiler.call(
- ctx,
- scope,
- scope,
- Array(src.getPath, less, minify.asInstanceOf[AnyRef])
- ).toString
-
- IO.write(des, css)
- Some(des)
+ }
}
}
@@ -131,14 +151,14 @@ case class LessSource(val graph: Graph, val src: File) extends Source {
ctx.evaluateReader(
scope,
- new InputStreamReader(getClass().getResourceAsStream(graph.lessVersion.envjsUrl), Charset.forName("utf-8")),
+ new java.io.InputStreamReader(getClass().getResourceAsStream(graph.lessVersion.envjsUrl), Charset.forName("utf-8")),
graph.lessVersion.envjsFilename,
1,
null)
ctx.evaluateReader(
scope,
- new InputStreamReader(getClass().getResourceAsStream(graph.lessVersion.url), Charset.forName("utf-8")),
+ new java.io.InputStreamReader(getClass().getResourceAsStream(graph.lessVersion.url), Charset.forName("utf-8")),
graph.lessVersion.filename,
1,
null)
@@ -158,7 +178,7 @@ case class LessSource(val graph: Graph, val src: File) extends Source {
ctx.evaluateReader(
scope,
- new InputStreamReader(getClass().getResourceAsStream(graph.lessVersion.url), Charset.forName("utf-8")),
+ new java.io.InputStreamReader(getClass().getResourceAsStream(graph.lessVersion.url), Charset.forName("utf-8")),
graph.lessVersion.filename,
1,
null)
View
67 sbt-less/src/main/scala/com/untyped/sbtless/Plugin.scala
@@ -15,6 +15,7 @@ object Plugin extends sbt.Plugin {
val downloadDirectory = SettingKey[File]("less-download-directory", "Temporary directory to download Less CSS files to")
val prettyPrint = SettingKey[Boolean]("less-pretty-print", "Whether to pretty print CSS (default false)")
val lessVersion = SettingKey[LessVersion]("less-version", "The version of the Less CSS compiler to use")
+ val useCommandLine = SettingKey[Boolean]("less-use-command-line", "Use the Less CSS command line script instead of Rhino")
}
sealed trait LessVersion {
@@ -32,37 +33,50 @@ object Plugin extends sbt.Plugin {
import LessKeys._
+ def time[T](out: TaskStreams, msg: String)(func: => T): T = {
+ val startTime = java.lang.System.currentTimeMillis
+ val result = func
+ val endTime = java.lang.System.currentTimeMillis
+ out.log.debug("TIME sbt-less " + msg + ": " + (endTime - startTime) + "ms")
+ result
+ }
+
def unmanagedSourcesTask: Initialize[Task[Seq[File]]] =
(streams, sourceDirectories in less, includeFilter in less, excludeFilter in less) map {
(out, sourceDirs, includeFilter, excludeFilter) =>
- out.log.debug("sourceDirectories: " + sourceDirs)
- out.log.debug("includeFilter: " + includeFilter)
- out.log.debug("excludeFilter: " + excludeFilter)
-
- sourceDirs.foldLeft(Seq[File]()) {
- (accum, sourceDir) =>
- accum ++ sourceDir.descendentsExcept(includeFilter, excludeFilter).get
+ time(out, "unmanagedSourcesTask") {
+ out.log.debug("sourceDirectories: " + sourceDirs)
+ out.log.debug("includeFilter: " + includeFilter)
+ out.log.debug("excludeFilter: " + excludeFilter)
+
+ sourceDirs.foldLeft(Seq[File]()) {
+ (accum, sourceDir) =>
+ accum ++ sourceDir.descendentsExcept(includeFilter, excludeFilter).get
+ }
}
}
def sourceGraphTask: Initialize[Task[Graph]] =
- (streams, sourceDirectories in less, resourceManaged in less, unmanagedSources in less, templateProperties in less, downloadDirectory in less, prettyPrint in less, lessVersion in less) map {
- (out, sourceDirs, targetDir, sourceFiles, templateProperties, downloadDir, prettyPrint, lessVersion) =>
- out.log.debug("sbt-less template properties " + templateProperties)
-
- val graph = Graph(
- log = out.log,
- sourceDirs = sourceDirs,
- targetDir = targetDir,
- templateProperties = templateProperties,
- downloadDir = downloadDir,
- lessVersion = lessVersion,
- prettyPrint = prettyPrint
- )
-
- sourceFiles.foreach(graph += _)
-
- graph
+ (streams, sourceDirectories in less, resourceManaged in less, unmanagedSources in less, templateProperties in less, downloadDirectory in less, prettyPrint in less, lessVersion in less, useCommandLine in less) map {
+ (out, sourceDirs, targetDir, sourceFiles, templateProperties, downloadDir, prettyPrint, lessVersion, useCommandLine) =>
+ time(out, "sourceGraphTask") {
+ out.log.debug("sbt-less template properties " + templateProperties)
+
+ val graph = Graph(
+ log = out.log,
+ sourceDirs = sourceDirs,
+ targetDir = targetDir,
+ templateProperties = templateProperties,
+ downloadDir = downloadDir,
+ lessVersion = lessVersion,
+ prettyPrint = prettyPrint,
+ useCommandLine = useCommandLine
+ )
+
+ sourceFiles.foreach(graph += _)
+
+ graph
+ }
}
def watchSourcesTask: Initialize[Task[Seq[File]]] =
@@ -74,7 +88,9 @@ object Plugin extends sbt.Plugin {
def compileTask =
(streams, unmanagedSources in less, sourceGraph in less) map {
(out, sourceFiles, graph: Graph) =>
- graph.compileAll(sourceFiles)
+ time(out, "compileTask") {
+ graph.compileAll(sourceFiles)
+ }
}
def cleanTask =
@@ -89,6 +105,7 @@ object Plugin extends sbt.Plugin {
includeFilter in less := "*.less",
excludeFilter in less := (".*" - ".") || "_*" || HiddenFileFilter,
lessVersion in less := LessVersion.Less130,
+ useCommandLine in less := false,
sourceDirectory in less <<= (sourceDirectory in conf),
sourceDirectories in less <<= (sourceDirectory in (conf, less)) { Seq(_) },
unmanagedSources in less <<= unmanagedSourcesTask,
View
9 sbt-less/src/main/scala/com/untyped/sbtless/Source.scala
@@ -11,12 +11,11 @@ trait Source extends com.untyped.sbtgraph.Source {
def compile: Option[File]
- def completeRawSource: String =
+ def importlessRawSource: String =
IO.readLines(src).map { line =>
- LessSource.parseImport(line.trim) match {
- case Some(parentName) => graph.getSource(parentName, this).completeRawSource
- case _ => line
- }
+ LessSource.importRegex.replaceAllIn(line, "")
}.mkString("\n")
+ def completeRawSource: String =
+ graph.ancestors(this).foldLeft("")(_ + _.importlessRawSource)
}
View
4 sbt-less/src/sbt-test/sbt-less/include-exclude/fixtures/3.include.css
@@ -1,4 +1,4 @@
.one{color:black;}
.two{color:black;}
-.three{color:black;}
-.six{color:black;}
+.six{color:black;}
+.three{color:black;}
Please sign in to comment.
Something went wrong with that request. Please try again.