If you write any Apps Script using HtmlService – and that’s pretty much everyone nowadays, you probably write client side JavaScript as Html files with <script> tags, and server side as .gs files.

But Apps Script is JavaScript, so why treat them differently? You also sometimes end up duplicating useful bits of code for .js purposes that you’ve already written once for .gs.

Here’s how to use the same code for both, or to write code intended to be run client side using the server side .gs IDE environment. Not only does this avoid duplication, it allows you to easily delegate compute intensive things to the client where they tend to run much faster.

Example

Let’s say I have a useful set of functions I’m using in .gs to generate unique strings, and I want to also do something like that with something I’m planning to do on the client side. 

Here’s my web app. Nothing unusual here.

function doGet() {
    return HtmlService.createTemplateFromFile('clientHtml')
            .evaluate()
            .setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

Here’s my clientHtml file. There’s no JavaScript code, aside from a call to doTheClientWork(); 

<p>
Sharing the same code both server and client side
</p>
client:
server:
<?!= requireGs (&#91;'usefulThings' , 'clientJs'&#93;); ?>

Notice the templating of the requireGs() function. This is going to go off to pick up code that is being managed, and potentially used in the .gs server environment, and insert it into the client environment to be run there.

 

requireGs()

Here’s how it works. The ScriptApp.getResource() function returns a Blob that is the code for a .gs file. Using that we can inject it into the HtmlOutput stream, and reuse or manage all out client side JavaScript as if it were server side.

/**
* given an array of .gs file names, it will get the source and return them concatenated for insertion into htmlservice
* like this you can share the same code between client and server side, and use the Apps Script IDE to manage your js code
* @param {string[]} scripts the names of all the scripts needed
* @return {string} the code inside script tags
*/
function requireGs (scripts) {
    return 'n';
}

So all you have to do is give a list in your html template of the scripts you’d like included to run on the client, like this.

<?!= requireGs (&#91;'usefulThings' , 'clientJs'&#93;); ?>

Client side

This code is expected to only run client side, but I’m managing it as a .gs file which means I can use the regular Apps Script IDE. The fact that it refers to things that don’t exist in apps script such as the document object is irrelevant, since we never actually execute it server side. Note that it runs the same function on both the client and the server.

/**
* this is stuff I only want to run on the client, but I'll manage it with the apps script IDE
*/
function doTheClientWork () {
    // i'll call getUniqueString, which is shared between both client and server
    document.getElementById("client").innerHTML += generateUniqueString();
    // and we'll run the same thing server side
    google.script.run
        .withSuccessHandler( function (data) {
            document.getElementById("server").innerHTML += data;
        })
        .withFailureHandler ( function (error) {
            document.getElementById("server").innerHTML += error;
        })
        .generateUniqueString();
}

Shared code

Here’s the code I want to be able to run both server and client side. Like this it only needs to exist in one place – as a .gs script file. For the purposes of this discussion, it’s not important what it does.

oh… and here’s the output

 


 For some more discussion and additional ideas on this, take a look at More client server code sharing

For more like this see Google Apps Scripts Snippets

Why not join our community, follow the blog an or follow me on Twitter