Monday, July 18, 2016

Less pre-processing with Maven and Jetty

Continuing on from the previous post we will set up a pre-processor for .less files that will continue to process file changes for Jetty to pick up. Regardless of the Java web framework you are using the file layout generally looks similar to the following.

src/
   main/
      java/
      less/
      webapp/
         js/
         css/
         index.html
Jetty will pick up and changes to files made under the webapp directory so we want our less pre-processor to monitor files in the less/ directory put the compiled css files into the css/ directory where Jetty will pick them up.

The standard less compiler is actually written in JavaScript and is available as a Node NPM module. There is also a watch-less NPM module that will monitor files and run the less compiler when changes are detected. To use node modules we will use the frontend-maven-plugin.

<plugin>
    <groupId>com.github.eirslett</groupId>
    <artifactId>frontend-maven-plugin</artifactId>
    <version>0.0.29</version>

    <configuration>
        <nodeVersion>v0.11.14</nodeVersion>
        <npmVersion>2.13.4</npmVersion>
        <installDirectory>.</installDirectory>
        <workingDirectory>.</workingDirectory>
    </configuration>

    <executions>
        <execution>
            <id>install node and npm</id>
            <goals>
                <goal>install-node-and-npm</goal>
            </goals>
        </execution>

        <execution>
            <id>npm install</id>
            <goals>
                <goal>npm</goal>
            </goals>
            <configuration>
                <arguments>install</arguments>
            </configuration>
        </execution>
    </executions>
</plugin>
This will install Node and NPM and then install all NPM modules defined in the package.json file in the root of our project.
{
  "dependencies": {
    "watch-less": "emmostrom/watch-less"
  }
}
This is a version of watch-less I have modified to watch std-in and to have an option to just run once and not monitor files. Now we can modify our groovy plugin code from the previous post to build a process for our watch-less program.

if (isJettyRun) {
  new ProcessBuilder(
    ["node/node", "node_modules/watch-less/cli.js", 
     "-d", "src/main/less/app", 
     "-r", "src/main/webapp/css", 
     "-e", ".css", 
     "--watch-stdin"]
  ).inheritIO().directory(project.getBasedir()).start()                             
} else {
  def proc = new ProcessBuilder(
    ["node/node", "node_modules/watch-less/cli.js", 
     "-d", "src/main/less/app", 
     "-r", "src/main/webapp/css", 
     "-e", ".css", 
     "--once"]
  ).redirectErrorStream(true).directory(project.getBasedir()).start()
  proc.waitForOrKill(15000)
  proc.in.eachLine { line -> println line }
}