Grunt usemin in Salesforce projects

Lately I’ve been doing a lot more JavaScript heavy development on the Force.com platform and have started using Grunt for build tasks.  I value the ease of extensibility and vast library of existing plugins that are available.  This post describes how one of the more popular plugins, grunt-usemin, can be configured within a Force.com project.  The post has some background information to give context, but the entirety of a complete project set up and build process is out of scope.

The grunt-usemin npm page describes it as “replaces the references of scripts, stylesheets and other assets within HTML files dynamically with optimized versions of them.” I have focused in on the scripts and stylesheets portion.

In a recent article about using Gulp to develop static resources, Bob Roberts outlined a way that localhost resources can be used to speed up development that builds from Kevin Poorman’s AngularVisualforceSeed which uses a python server.  I recommend the same approach, but use grunt-contrib-connect for the server since I am using grunt. A deep discussion of that is out of scope for this post, but for ease of reference, the basic idea is that there are two mutually exclusive components that contain the css and JS includes — one localhost.component with script and href tags that reference localhost (e.g., src=”https://localhost:8000/js/myjs.js”) and one, server.component, that uses “normal” $Resource and $URLFOR. The resultant setup is something like:

When running in localhost mode the c:localhost component gets rendered with its script/link tags with src/href=”https://localhost…”. The page is rendered in Salesforce, but the css and JS files are served from your localhost server which allows you to see changes instantly without the need to redeploy the static resource (obviously a huge win).

The actual JavaScript source code lives outside of the static resources or MavensMate resource-bundle and, instead, copy the build output there and compress it to a static resource as part of the build process (out of scope for this post). This makes it simpler to use a more typical JavaScript project setup such as something that Yeoman would generate, with the final build output not needing to contain everything in the source.  Additionally, as part of the build process we can generate the contents of the localhost and server Visualforce components.

This setup has an index.html file in the source directory that later gets built to a localhost.component (references non-minified files) and a server.component (references minified files). The index file has references to the JavaScript and CSS files, listed in the order of their dependencies (look at grunt-wiredep if you’re using bower).  It is important that the files are listed in the correct dependency order so that when the concatenation is done code that is dependent on other code comes after it in the resulting file.  Here is a simple example.

Note: For developing locally this file would be transformed, with the href and src attributes prefixed with https://localhost:<someport>, copied to a src/components/localhost.component, and deployed. 

The directives in the comments instruct usemin to concatenate and then minify what is between them and output them in the specified files — main.min.css for the css and main.min.js for the JavaScript and replace the multiple individual link and script tags with the references to the single minified files.  Once those files are created the build process can do what it needs with them (e.g., add them to the static resource being built).

The step that is missing from this which would be present in a non Salesforce JavaScript app is the filerev step. It is not necessary for Salesforce projects since the magic of URLFOR and $Resource with static resources takes care of it.  However, in order to do that the generated file needs to use the $Resource global variable and the $URLFOR function.  By default, usemin just replaces the JS script tags with a script tag and css link tags with a link tag.  So, the above configuration would result in the following:

To get it to generate Visualforce friendly output the blockReplacements option of usemin can be used as in the following:

That will result in the following Visualforce friendly output.

That ends up as the contents of the server.component. By incorporating these block replacements into the build process, it is ensured that the component will use the correct minified css and JS file names. However, if it is unlikely that their names will ever change you might be able to just create the component once with the above two lines in it and then leave this out of the process.

More

This post covered a bit of how usemin can be used within a Salesforce application. There is much, much more that can be done with grunt in Salesforce projects that was not covered. I recommend taking a look at a tool like grunt if you start doing any JavaScript heavy development on the Force.com platform.

2 thoughts on “Grunt usemin in Salesforce projects

  1. Thanks for documenting this Peter. We have used grunt and gulp heavily while building Trailhead, I never get a chance to document this. I am glad you wrote this a better way through a blog post, this is good, keep it coming 🙂

    1. Thanks Harshit! I love how easy it is to add functionality with grunt and gulp. Our CI builds fail when Apex doesn’t have at least 75% coverage, and now when our JavaScript doesn’t have 90% — pretty simple to set up thanks to grunt plugins. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *