0

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")

My TS file: enter image description here

tehhowch
  • 9,645
  • 4
  • 24
  • 42
smark91
  • 545
  • 1
  • 5
  • 17
  • Can you please elaborate more? – smark91 Feb 22 '19 at 13:49
  • The screenshot of code is an exemplification of the issue. This is because the issue is not directly related to the code I wrote as you can assume looking at the code. – smark91 Feb 22 '19 at 14:04
  • The important code part is under code tag as rules ask – smark91 Feb 22 '19 at 14:05
  • Writing your code here yields **"Cannot find name 'moment'"**, not **`ReferenceError: "moment" is not defined`**. Have you described this issue properly? https://stackoverflow.com/help/how-to-ask https://stackoverflow.com/help/mcve – tehhowch Feb 22 '19 at 14:28
  • I have modified now the question to be more clear on that step. That error is provided to me on the Google Script page after compiling from TypeScript. – smark91 Feb 22 '19 at 14:34
  • Seem that the issue is caused by the line `var module = module || { exports: exports };` that **ts2gas** add all the time as part of the transpile – smark91 Feb 22 '19 at 14:45

1 Answers1

1

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:

Code.gs

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.

Code.ts

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 -->

Code.gs

// 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);
}

Solutions

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:

tehhowch
  • 9,645
  • 4
  • 24
  • 42