Friday, 21 April 2017

Building less from ANT without funny plugins

There are a few libraries from non-trustworthy individual developers which do compile LESS style-sheets in java, most of them are not very transparent: some of them download node.js, some of them use rhino. It is possible to do it in clear, obvious way from your ant build, see the example for Windows below.

Properties to be defined:
${your.extensions.dir} - is some dir to put NodeJS to;
${your.web.sources.dir} - is a dir for static web files, to put CSS into.

This config downloads NodeJS, installs LESS locally and compiles styles.
This example has version for Windows and MacOS, Linux version should be similar to MacOs. Node.JS can also be installed with system package manager, `_install_node` task is not needed in this case.
05 Jan 2018: updated with MacOS executables

<!-- Build less stylesheets -->
<property name="nodejs.dir" location="${your.extensions.dir}/nodejs"/>
<!-- maybe these versions should go to the ivysettings.xml, maybe not because they are not from the maven/ivy -->
<property name="nodejs.ver" value="8.9.1"/>
<property name="less.ver" value="2.7.2"/>
<if>
  <os family="windows" />
  <then>
    <property name="nodejs.archive" value="node-v${nodejs.ver}-win-x86.zip" />
    <property name="nodejs.exec.dir" location="${nodejs.dir}/node-v${nodejs.ver}-win-x86"/>
    <property name="lessc.exec" location="${nodejs.exec.dir}/lessc.cmd"/>
  </then>
  <elseif>
    <os family="mac" />
    <then>
      <property name="nodejs.archive" value="node-v${nodejs.ver}-darwin-x64.tar.gz" />
      <property name="nodejs.exec.dir" location="${nodejs.dir}/node-v${nodejs.ver}-darwin-x64/bin"/>
      <property name="lessc.exec" location="${nodejs.exec.dir}/node_modules/.bin/lessc"/>
    </then>
  </elseif>
  <else>
      <echo message="Unsupported platform, check _install_node in build.xml"/>
  </else>
</if>

<property name="less.dir" value="${your.web.sources.dir}/com/company/web/include" />

<echo message="${nodejs.exec.dir}"/>
<target name="_install_node">
    <if>
        <not><available file="${nodejs.exec.dir}"/></not>
        <then>
            <echo message="installing nodejs..."/>
            <mkdir dir="${nodejs.dir}"/>
            <get src="https://nodejs.org/dist/v${nodejs.ver}/${nodejs.archive}" dest="${nodejs.dir}" usetimestamp="false"/>
            <if>
              <os family="windows" />
              <then>
                  <unzip src="${nodejs.dir}/${nodejs.archive}" dest="${nodejs.dir}/"> </unzip>
              </then>
              <elseif>
                <os family="mac" />
                <then>
                   <untar src="${nodejs.dir}/${nodejs.archive}" dest="${nodejs.dir}/" compression="gzip"> </untar>
                   <chmod dir="${nodejs.exec.dir}" perm="ugo+rx" includes="*"/>
                </then>
              </elseif>
              <else>
                  <echo message="Unsupported platform, check _install_node in build.xml"/>
              </else>
            </if>

        </then>
        <else>
          <echo message="nodejs already installed in ${nodejs.exec.dir}"/>
        </else>
    </if>
</target>

<target name="_install_node_less" depends="_install_node">
  <if>
      <not><available file="${lessc.exec}"/></not>
      <then>
          <echo message="installing less for node from npm..."/>
          <exec dir="${nodejs.exec.dir}" executable="cmd" osfamily="Windows">
              <arg value="/c"/>
              <arg value="${nodejs.exec.dir}/npm.cmd"/>
              <arg value="install"/>
              <arg value="less@${less.ver}"/>
          </exec>
          <exec dir="${nodejs.exec.dir}" executable="npm" osfamily="mac">
              <arg value="install"/>
              <arg value="less@${less.ver}"/>
          </exec>
      </then>
  </if>
</target>

<target name="generate-styles" depends="_install_node_less">
    <echo message="compiling less to ${less.dir} ..."/>
    <!-- win executable -->
    <exec dir="${nodejs.exec.dir}" executable="cmd" osfamily="windows">
        <arg value="/c"/>
        <arg value="${lessc.exec}"/>
        <arg value="${less.dir}/base-style.less"/>
        <arg value="${less.dir}/base-style.css"/>
        <arg value="--source-map"/>
    </exec>
    <!-- mac executable -->
     <exec dir="${nodejs.exec.dir}" executable="/bin/sh" osfamily="mac">
        <arg value="-c"/>
        <arg value="${lessc.exec} --source-map ${less.dir}/base-style.less ${less.dir}/base-style.css"/>
    </exec>
</target>