Lantana

Sass is a kind of precompiler for CSS that offers additional features like nested styles, variables or includes. The syntax of scss files is similar to standard CSS, so it's very easy to learn.

My goal is to:

  • nicely integrate Sass into the Maven build process,
  • use Jetty to see the web application with the compiled css files, and
  • see changes to a Sass file live (without running Maven or restarting Jetty).

There is a sass-maven-plugin by the Apereo Foundation that already offers Maven integration and watching changes to sass files. However, I don't fancy the default settings. The default location of sass files is the webapp directory, which means that the sass files are packed into the war file as well, exposing silent comments, variable names and maybe other things that are not meant to be published.

I prefer src/main/sass as source directory. As target, I choose a directory called generated-webapp, which is ought to contain all generated webapp stuff. In this directory, a css directory will contain the compiled css files. The sass-maven-plugin configuration now looks like this:

<plugin>
    <groupId>org.jasig.maven</groupId>
    <artifactId>sass-maven-plugin</artifactId>
    <version>1.1.1</version>
    <executions>
        <execution>
            <id>package</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>update-stylesheets</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <resources>
            <resource>
                <source>
                    <directory>${basedir}/src/main/sass/</directory>
                </source>
                <destination>${project.build.directory}/generated-webapp/css</destination>
            </resource>
        </resources>
    </configuration>
</plugin>

The reason for using generated-webapp instead of ${project.build.directory}/${project.build.finalName} is that Jetty only looks into src/main/webapp for static resources by default. However, if ${project.build.directory}/${project.build.finalName} was added, Jetty would also scan all compiled classes twice, which may result in errors (especially when Spring is involved). What needs to be done now is to add generated-webapp to the list of webapp resources:

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.2.2.v20140723</version>
    <configuration>
        <webApp>
            <resourceBases>
                <directory>${basedir}/src/main/webapp</directory>
                <directory>${project.build.directory}/generated-webapp</directory>
            </resourceBases>
        </webApp>
    </configuration>
</plugin>

After starting Jetty with mvn jetty:run, it nicely returns our css resources.

To make changes to Sass files immediately available, the Sass watcher is started in a second terminal with mvn sass:watch. Jetty will deliver all changes in src/main/sass now, without the need to restart.

A final problem to solve is that the generated-webapp target is not included in the war file by default. The maven-war-plugin needs to be configured properly:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <webResources>
            <resource>
                <directory>${project.build.directory}/generated-webapp</directory>
            </resource>
        </webResources>
    </configuration>
</plugin>