I have the necessity of using moment.js inside a locally developed Apps Script project, which uses google\clasp to convert from TypeScript.
I have already tried adding the js library inside the project as I do when writing normally in .gs, but using clasp doesn't seem to permit me to use that way.
I have already tried, as I read a lot in other Stack Overflow answers, to use eval
like this without success:
eval(UrlFetchApp.fetch('library.min.js url').getContentText());
In all the cases, after I pushed to Apps Script and run the function in the Apps Script Editor, I receive
ReferenceError: "moment" is not defined. (row 6, file "Test")
One can use external libraries like Moment.js via eval
& UrlFetchApp
in the "standard" Apps Script projects because the variables exports
and module
are not defined, so the library installs itself into the global context
Indeed, we can verify the result by inspecting this
in the Apps Script Editor:
var momentURL = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.4/moment.min.js";
function main() {
eval(UrlFetchApp.fetch(momentURL).getContentText());
Logger.log(this["moment"]);
}
Executing main
yields
function e() {
return Qe.apply(null, arguments);
}
For transpiled TypeScript, because exports
and module
are globally defined, the initialization of eval
'd libraries assumes that it has a more recent runtime / package management system than that provided by Google Apps Script.
import * as moment from "moment";
const momentURL = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.4/moment.min.js";
function main() {
eval(UrlFetchApp.fetch(momentURL).getContentText());
Logger.log(`this['moment']: ${this["moment"]}`);
Logger.log(`this.module: ${this.module}`);
for (let key in this.module)
Logger.log(`this.module[${key}]: ${this.module[key]}`);
}
$ clasp push
-->
// Compiled using ts2gas 1.6.0 (TypeScript 3.2.2)
var exports = exports || {};
var module = module || { exports: exports };
//import * as moment from "moment";
var momentURL = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.4/moment.min.js";
function main() {
eval(UrlFetchApp.fetch(momentURL).getContentText());
Logger.log("this['moment']: " + this["moment"]);
Logger.log("this.module: " + this.module);
for (var key in this.module)
Logger.log("this.module[" + key + "]: " + this.module[key]);
}
Which yields a log of
this['moment']: undefined
this.module: [object Object]
this.module[exports]:
function e() {
return Qe.apply(null, arguments);
}
So the eval
is successful, but binds to module.exports
and not moment
. You can (in the transpiled Apps Script) refer to module.exports
instead of moment
:
Logger.log(module.exports().format("YYYY")); // 2019
Probably you will need to use a different method than clasp, since it seems ts2gas
(as of v1.6.0) does not support import / export transpiling. This observed behavior wherein module.exports
in transpiled TS is the eval'd import seems heinously fragile, and will certainly not be easy to work around when writing the actual TypeScript.
Related: