JavaScript has long been the de facto choice for client-side web development, but lately it's been catching on server-side as well. While we like to think that Apps Script has contributed to the trend, projects such as Mozilla's Rhino and Node.js have also done a great deal to popularize the concept. As a result, developers have created a wealth of new open-source JavaScript libraries, and in this post we'll talk about how you can leverage them in your Apps Script projects.
Underscore One library I wanted to use in my scripts was Underscore, which describes itself as "a utility-belt library for JavaScript." It provides a wealth of helper functions that make coding in JavaScript cleaner and more enjoyable. Take, for example, the simple situation where you want to log each value in a range.
// Using plain JavaScript. for (var i = 0; i < values.length; i++) { for (var j = 0; j < values[i].length; j++) { Logger.log(values[i][j]); } }
Although writing for loops like this is a common pattern, it's a fair amount of typing and you need to keep track of counter variables that serve little purpose. Underscore provides an each() method that makes the process much simpler.
for
each()
// Using Underscore. _.each(values, function(row) { _.each(row, function(cell) { Logger.log(cell); }); });
Passing anonymous functions as parameters takes a little getting used to, but if you've worked with jQuery, the pattern feels familiar.
Underscore also has some great extensions, and Underscore.string provides some useful string manipulation features. My favorite is the ability to use sprintf() notation in JavaScript, which can simplify the process of building complex strings.
sprintf()
// Using plain JavaScript. var message = "Hello, " + firstName + " " + lastName + ". Your wait time is " + wait + " minutes."; // Using Underscore.string. var message = _.sprintf("Hello, %s %s. Your wait time is %d minutes.", firstName, lastName, wait);
Integrating with Apps Script The simplest way to include the Underscore library in a project would be to paste its source code directly into your script, but this would lead to a lot of duplication if you end up using it in multiple projects. Earlier this year, we released a feature in Apps Script called libraries that allows you to share scripts and include them in other projects. Packaging a JavaScript library like Underscore as an Apps Script library is possible, but requires some helper functions to work correctly.
When Underscore loads, it creates a global variable named "_" that you use to access its functionality. Apps Script specifically prevents the global scope of a library from interfering with the global scope of the script that includes it, so I built a helper function into the library to pass the variable around.
// In the library. function load() { return _; }
In my script that includes the library, I simply make a call to that function and use the result to set up my own "_" variable.
// In the script that includes the library. var _ = Underscore.load();
To try my copy of the Underscore library in your own project, use the project key "MGwgKN2Th03tJ5OdmlzB8KPxhMjh3Sh48" and the code snippet above. You can browse the full source code here.
Using it with the HtmlService Using the code above, I could easily include the library in my server-side Apps Script code, but I also wanted to use these functions client-side in my web app served by the HtmlService. To accomplish this, I created a copy of the Underscore source code, wrapped it in <script> tags, and stored them in Html files (instead of Script files). These snippet files could then be included in my web app's HtmlTemplates using the helper function below.
<script>
// In the library. var FILES = ['Underscore.js', 'Underscore.string.js', 'Init.js']; function include(output) { for (var i = 0; i < FILES.length; i++) { var file = FILES[i]; output.append( HtmlService.createHtmlOutputFromFile(file).getContent()); } }
This function was called in the web app's HtmlTemplate using the simple code below.
<!-- In the web app that includes the library. --> <html> <head> <? Underscore.include(output) ?> </head> ...
Other libraries Integrating with Underscore was fairly easy, but trying the same approach with other open-source libraries may be a bit more complicated. Some libraries won't run correctly in the Apps Script environment if they rely on certain capabilities within the browser or Node.js runtime. Additionally, to be served by the HtmlService, the code must pass the Caja engine's strict validation, which many popular libraries don't meet. In some cases, you may be able to manually patch the library to work around these issue, but this usually requires a deep understanding of how the library works.
We hope you're inspired to use Underscore and other open-source libraries in your own work. If you find a library that works great with Apps Script, share it with me on Google+ and I'll help get the word out.