I recently came across GAS — Google App Script and immediately the first hurdle I had to overcome to was make my NPM packages available on there.
I had to hop through a couple loops to make this happen. I wanted to call out the steps in this blog so it’ll hopefully help someone out there as well.
GAS does not provide any sort of package management system such as NPM, if you didn’t know. The only way to use your libraries is to make them available via a standalone script hosted in cloud. You’ll then be able to make your lib available in your script by using eval on UrlFetchApp.fetch
. I.e.:
eval(UrlFetchApp.fetch('https://hostedsomwhere/sdk.js').getContentText());
Now the question is how to “convert” your NPM package into a standalone script that then you can serve over the internet. This process is called bundling your lib. I looked at a couple options such as Webpack, Babel, rollup etc. However, frankly I found Browseify to be simplest to use.
Browseify provides a wide variety of options for bundling. You can bundle your app for a node environment where a global
is defined or you can bundle for a browser. GAS environment is still a strange one to me — the global is undefined so it’s not a full node env. At the same time, I saw warnings in GAS console about how it’s not a browser env either:
Using browser-only version of superagent in non-browser environment
So if you do know what GAS is doing under the hood, do let me know in the comments below. But I digress. Install Browesify globally:
npm install -g browserify
Then navigate to your package’s folder and run the following command:
browserify --standalone sdk_name --bare src/index.js -o dist/sdk.js
I found the standalone and bare flags produce the best result. Here src/index.js points to the entry point to your lib and dist/sdk.js is output of the bundled sdk. sdk_name
is a name you can assign to your package and it can be anything.
Once you have dist/sdk.js
you’ll then need to host the script somewhere. I simply dropped in in a S3 bucket in our AWS subscription and made the script public, you can go down any route you like.
Now, let’s get back to GAS dashboard. Now reference your sdk in the script by calling eval on UrlFetchApp and point to where you’ve hosted your bundled sdk:
From there one, the sdk become globally available in the script and you can call the methods as you’d normally. Now, your lib is available to be used in GAS.
It’s worth mentioning that this approach will work if your lib does not make any network calls. If it does, you’d need to do more work as we’ll discuss below.
What if your lib makes network calls?
If you’re using fetch
or superagent
to make calls in your lib, then it won’t work in App Script. You’ll be presented with some sort of error with XHR not being available or the global not being there.
The best way I found is to replace the network calls in your code with GAS’s UrlFetchApp.fetch
:
// Make a POST request with a JSON payload.
var data = {
'name': 'Bob Smith',
'age': 35,
'pets': ['fido', 'fluffy']
};
var options = {
'method' : 'post',
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
'payload' : JSON.stringify(data)
};
UrlFetchApp.fetch('https://httpbin.org/post', options);
You’d essentially find all instances of network calls in your lib and replace them with UrlFetchApp.fetch(). Granted this isn’t a trivial process of find and replace. However, it is a couple hours worth of work.
Doing this work does mean, you’ll likely need to maintain two versions of your SDK: one with UrlFetchApp for GAS and others with Superagent fetch or etc.. However, at this point that seems to be the price to pay if you’re set of making your lib available inside GAS.
If you know any other ways, please drop them in the comment section below.