Giter VIP home page Giter VIP logo

apps-script-starter's Introduction

Amit Agarwal

๐Ÿ‘‹๐Ÿป ย  I am the founder of Digital Inspiration - we build bespoke solutions that use the capabilities and the features of Google services for automating business processes and driving business productivity.

๐ŸŽ‰ ย  Google awarded me the Google Developer Expert title for Google Workspace (GSuite) and Google Apps Script. Microsoft awarded me the Most Valuable Professional award for five years in a row.

๐Ÿข ย  I have developed several popular Google add-ons, including Mail Merge for Gmail and Document Studio, that are deployed in some of the biggest companies and universities worldwide with several million downloads.

โœ๏ธ ย  I author a hugely popular technology blog where I publish how-to guides and tutorials around consumer software and apps.

๐ŸŒฑ ย  My development tech stack includes JavaScript, React.js, Node.js, Gatsby, Docker and the Google Cloud Platform - that includes Firebase, Cloud Functions, Cloud Run, Cloud SQL, Cloud Storage and GSuite.

๐Ÿข ย  You can follow me on Twitter and Youtube. Or send me an email at [email protected]

apps-script-starter's People

Contributors

contributorpw avatar dependabot[bot] avatar irregularshed avatar jwermuth avatar labnol avatar lucaslarson avatar mattwilkinsonn avatar oshliaer avatar tigerjoy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apps-script-starter's Issues

How/Where can I add a reference to an existing project?

Hi, I already have a few projects that I'd like to continue develop using your starter kit.
At the end of your video you show how we can deploy to a specific web app.

But can I use clasp pull, or something similar, to grab the current existing code into your starter kit structure?
I obviously don't want to create new projects, as some are already used by a lot of people.

Typescript support

I'm struggling with using Typescript for GAS together with Babel and Webpack. Was wondering if you have any experience with this related to creating this starter? @labnol

(Feel free to close this issue if not, since it isn't an issue with the project, it's more just for discussion about Typescript support)

clasp Push failed. Errors: Project contents must include a manifest file named appsscript.

I'm confused.

npm run deploy is finished with the error:

...
Push failed. Errors:
Project contents must include a manifest file named appsscript.
Files to push were:
โ””โ”€ dist/code.js
โ””โ”€ dist/index.html
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] deploy: `npm run build && ls -ah ./dist && clasp push`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] deploy script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/user/.npm/_logs/2018-08-02T09_56_54_294Z-debug.log

If I run clasp push directly it works fine.

I've checked CopyWebpackPlugin it works fine too.

Also I tracked files in the directory. I'm on Linux

package.json

 "scripts": {
    "deploy_test": "npm run build && ls -ah ./dist && clasp push"
  },

output

...
.  ..  appsscript.json  code.js  index.html
Push failed. Errors:
Project contents must include a manifest file named appsscript.
Files to push were:
โ””โ”€ dist/code.js
โ””โ”€ dist/index.html

As can you see the file is there.

Any ideas how to fix this?

npm run deploy not sending the code from src to build

Hi @labnol and team

I followed this tutorial: https://www.labnol.org/es6-google-apps-script-v8-200206. Thank you very much for it.

During it I encountered this issue:

npm run deploy causes error

    ERROR in ./src/index.js
    Module build failed (from ./node_modules/babel-loader/lib/index.js):
    Error: Cannot find module '@babel/core'

I googled and ran the following command:
541 20-02-22 14:00:42 npm install -D babel-loader @babel/core @babel/preset-env

And then my npm run deploy command ran without errors.

But my code.js file remains as:

function myFunction() {
  
}

My dist folder code-4.0.0.js appears as follows:

function doGet() {
}
function getEmailAddress() {
}
function sendmail(email = '[email protected]') {
}(function(e, a) { for(var i in a) e[i] = a[i]; }(this, /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony import */ var _server_webapp__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var _es6__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
/* harmony import */ var _email__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14);



global.doGet = _server_webapp__WEBPACK_IMPORTED_MODULE_0__["default"];
global.getEmailAddress = _email__WEBPACK_IMPORTED_MODULE_2__["default"];

global.sendmail = (email = '[email protected]') => {
  GmailApp.sendEmail(email, 'Apps Script Starter', 'Hello Google Apps Script');
}; // global.doGet = e => {
//   const text = '<b>I love appsScript</b>';
//   const output = HtmlService.createHtmlOutput(text);
//   output.setTitle(text);
//   output.addMetaTag('viewport', 'width=device-width, initial-scale=1');
//   output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
//   return output;
// };
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))

/***/ }),
/* 1 */
/***/ (function(module, exports) {

var g;

// This works in non-strict mode
g = (function() {
	return this;
})();

try {
	// This works if eval is allowed (see CSP)
	g = g || new Function("return this")();
} catch (e) {
	// This works if the window reference is available
	if (typeof window === "object") g = window;
}

// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}

module.exports = g;


/***/ }),
/* 2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
const doGet = () => {
  const title = 'Google Apps Script';
  const fileName = 'index.html';
  return HtmlService.createHtmlOutputFromFile(fileName).setTitle(title).setXFrameOptionsMode(HtmlService.XFrameOptionsMode.DEFAULT);
};

/* harmony default export */ __webpack_exports__["default"] = (doGet);

/***/ }),
/* 3 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _arrow_functions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
/* harmony import */ var _arrow_functions__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_arrow_functions__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _block_scopes__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* harmony import */ var _block_scopes__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_block_scopes__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _destructuring__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
/* harmony import */ var _es6_classes__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7);
/* harmony import */ var _es6_classes__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_es6_classes__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _export_import__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8);
/* harmony import */ var _filter_map_reduce__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9);
/* harmony import */ var _filter_map_reduce__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_filter_map_reduce__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _let_const__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(10);
/* harmony import */ var _let_const__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_let_const__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var _spread_rest_operators__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(11);
/* harmony import */ var _spread_rest_operators__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_spread_rest_operators__WEBPACK_IMPORTED_MODULE_7__);
/* harmony import */ var _template_literals__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(12);
/* harmony import */ var _template_literals__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_template_literals__WEBPACK_IMPORTED_MODULE_8__);
/* harmony import */ var _optional_chaining__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(13);
/* harmony import */ var _optional_chaining__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(_optional_chaining__WEBPACK_IMPORTED_MODULE_9__);











/***/ }),
/* 4 */
/***/ (function(module, exports) {

const add = (a, b) => a + b;

Logger.log(`The sum of 2 and 3 is ${add(2, 3)}`);

const max = (a, b) => {
  if (a > b) return a;
  return b;
};

Logger.log(`The bigger of 10 and 12 is ${max(10, 12)}`);
/* default arguments in functions */

const multiply = (value, factor = 2) => value * factor;

Logger.log(`2*10 = ${multiply(2, 10)}`);
Logger.log(`3*2 = ${multiply(3, 2)}`);

/***/ }),
/* 5 */
/***/ (function(module, exports) {

const name = 'Amit Agarwal';
let country = 'USA';
country = 'India';
Logger.log(`${name} lives in ${country}`);

/***/ }),
/* 6 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
const person = {
  name: 'Amit Agarwal',
  website: 'https://digitalinspiration.com/',
  email: '[email protected]'
};
const {
  name,
  email,
  country = 'unknown'
} = person;
Logger.log(`${name}'s email address is ${email}. Their country is ${country}`);
/* harmony default export */ __webpack_exports__["default"] = (person);

/***/ }),
/* 7 */
/***/ (function(module, exports) {

/* eslint-disable max-classes-per-file */
class Person {
  constructor(name = 'Anonymous', gender = 'Unknown') {
    this.name = name;
    this.gender = gender;
  }

  printDetails() {
    return `${this.name} is ${this.gender}`;
  }

}

const person = new Person('Amit Agarwal', 'male');
Logger.log(person.printDetails());

class Employee extends Person {
  constructor(name, gender, role) {
    super(name, gender);
    this.role = role;
  }

  printRole() {
    return `${this.name} is ${this.role}`;
  }

}

const employee = new Employee('Amit', 'male', 'Google Developer');
Logger.log(employee.printDetails());
Logger.log(employee.printRole());

/***/ }),
/* 8 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SCRIPT_TIMEOUT", function() { return SCRIPT_TIMEOUT; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getCurrentTime", function() { return getCurrentTime; });
/* harmony import */ var _destructuring__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);

const SCRIPT_TIMEOUT = 1000 * 60 * 5;
const getCurrentTime = () => Date.now();
Logger.log(_destructuring__WEBPACK_IMPORTED_MODULE_0__["default"]);

/***/ }),
/* 9 */
/***/ (function(module, exports) {

/* Array functions */
const numbers = [10, 20, 30];
/* Print the nubmers */

numbers.forEach(number => {
  Logger.log(number);
});
/* Double the numbers */

const doubleIt = numbers.map(number => number * 2);
Logger.log(doubleIt);
/* Only numbers > 10 */

const bigNumbers = numbers.filter(number => number > 10);
Logger.log(bigNumbers);
/* Add the numbers */

const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
Logger.log(`The sum of ${numbers.join(', ')} is ${sum}`);
/* Remove duplicates with reduce */

const arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
const result = arr.sort().reduce((accumulator, current) => {
  const {
    length
  } = accumulator;

  if (length === 0 || accumulator[length - 1] !== current) {
    accumulator.push(current);
  }

  return accumulator;
}, []);
Logger.log(result); // [1,2,3,4,5]

/***/ }),
/* 10 */
/***/ (function(module, exports) {

/* let and const */
const name = 'Amit Agarwal';
Logger.log(`The name is ${name}`);

for (let i = 0; i < 5; i += 1) {
  Logger.log(`The count is ${i}`);
}

/***/ }),
/* 11 */
/***/ (function(module, exports) {

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

const animals = ['Monkey', 'Lion', 'Zebra'];
const birds = ['Sparrow', 'Pigeon', 'Parrot'];
const species = [...animals, ...birds];
Logger.log(species);
const person = {
  name: 'Amit Agarwal',
  email: '[email protected]'
};
const website = {
  url: 'https://digitalinspiration.com/'
};

const personDetails = _objectSpread({}, person, {}, website, {
  twitter: '@labnol'
});

Logger.log(personDetails);
/* Update the email address only */

const emailUpdated = _objectSpread({}, personDetails, {
  email: '[email protected]'
});

Logger.log(emailUpdated);
const stack = ['Google Apps Script', 'JavaScript', 'Firebase', 'Node.js', 'Webpack', 'Babel'];
const [gas, js, ...others] = stack;
Logger.log(`${gas} is similar to ${js}`);
Logger.log(others);
const newPerson = {
  name: 'Amit Agarwal',
  email: '[email protected]',
  website: 'https://digitalinspiration.com/'
};
const {
  name,
  age = 'unknown'
} = newPerson;
Logger.log(`${name} is ${age} years old`);

/***/ }),
/* 12 */
/***/ (function(module, exports) {

const name = 'Amit Agarwal';
Logger.log(`${name} has ${name.length} characters`);
Logger.log(`${name} in uppercase is  ${name.toUpperCase()}`);
Logger.log(`The date is ${new Date().toUTCString()}`);

/***/ }),
/* 13 */
/***/ (function(module, exports) {

var _person$address, _person$address2;

const person = {
  name: 'Amit Agarwal',
  gender: 'Male',
  address: {
    country: 'India'
  }
};
Logger.log((person === null || person === void 0 ? void 0 : person.gender) || 'Data not available'); // Access deeply nested  properties

Logger.log((person === null || person === void 0 ? void 0 : (_person$address = person.address) === null || _person$address === void 0 ? void 0 : _person$address.country) || 'Unknown Location');
Logger.log(((_person$address2 = person.address) === null || _person$address2 === void 0 ? void 0 : _person$address2.country) || 'Unknown Location');

/***/ }),
/* 14 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
// email.js
const getEmailAddress = () => {
  const userEmail = Session.getActiveUser().getEmail();
  const aliases = GmailApp.getAliases();
  const emails = [userEmail, ...aliases];
  Logger.log(`Your emails are: ${emails.join(', ')}`);
};

/* harmony default export */ __webpack_exports__["default"] = (getEmailAddress);

/***/ })
/******/ ])));

I tried it twice with the same result too.

Any suggestions on what I am missing?

Thanks in advance

How to setup a menu in bound google doc

@labnol

Thank you very much for this awesome repo.
Works like a charm!

I am new to webpack and babel and am trying to figure out how to setup a menu in my bound google doc.
Typically its onOpen () => { getUi; createMenu; createMenuItem } etc.

I tried adding it in a number of places, but it only works if I manually run the onOpen from the script editor. Also read about adding a trigger, but feel that is only a workaround.

Any help would be really appreciated.
Thanks in advance.

Babel uses reserved keyword `default` when compiling

When installing additional npm packages, some of them get transpiled using .default to access an object. However, in GAS default is a reserved keyword resulting in an error.

Expected Behavior

Webpack should use Babel to transpile Object property accessing using the bracket notation instead of the dot notation.

Current Behavior

clasp push throws error

{
errors: [
    {
      message: 'Syntax error: Missing name after . operator. line: XXX file: bundle.js',
      domain: 'global',
      reason: 'badRequest'
    }
  ]
}

bundle.js:

//...
Object.defineProperty(exports, "DataFrame", {
  enumerable: true,
  get: function get() {
    return _dataframe.default;
  }
});
//...

index.js:

import DataFrame from 'dataframe-js';
//...
const response = () => {
  return JSON.parse(UrlFetchApp.fetch(url, { method: 'get' }));
}
DataFrame.fromJSON(response()).then(df => {
  Logger.log(df);
 });

Possible Solution

Beginner friendly explanation for installing additional packages that might conflict with the default keyword or include babel-preset-gas in your project setup.

Steps to Reproduce

  1. clone apps-script-starter
  2. cd to project, npm install dataframe-js
  3. use dataframe-js functionality
  4. npm run deploy

Context (Environment)

I am a beginner wanting to set up an environment to develop in GAS using JavaScript. Since I'm handling data from APIs to be pushed to a Google Sheet, I would like to work with data frames to make data handling easier.

Error: Cannot find module '@babel/core'

After the latest commit to integrate V8 Runtime Support "npm run build" gives the above error even for the initial build as well. This can be resolved by re-adding the @bable/core module (which was removed in the V8 runtime support commit) but I don't think it will accomplish the V8 integration.

npm run build failed

Hello!
Excuse me Sir, but i'm a newbie with this git project and i'm trying to learn following your youtube video example and i got this error when i type: npm run build

`jjavi@KIRAHP MINGW64 /d/jjavi/Documents/git clones/apps-script-starter
$ npm run build

[email protected] build D:\jjavi\Documents\git clones\apps-script-starter
webpack

Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.

  • configuration.optimization.minimize should be a boolean.
    -> Enable minimizing the output. Uses optimization.minimizer.
    npm ERR! code ELIFECYCLE
    npm ERR! errno 1
    npm ERR! [email protected] build: webpack
    npm ERR! Exit status 1
    npm ERR!
    npm ERR! Failed at the [email protected] build script.
    npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\jjavi\AppData\Roaming\npm-cache_logs\2020-03-28T09_22_27_027Z-debug.log
`
the complete log:

0 info it worked if it ends with ok 1 verbose cli [ 1 verbose cli 'C:\\Program Files\\nodejs\\node.exe', 1 verbose cli 'C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js', 1 verbose cli 'run', 1 verbose cli 'build' 1 verbose cli ] 2 info using [email protected] 3 info using [email protected] 4 verbose run-script [ 'prebuild', 'build', 'postbuild' ] 5 info lifecycle [email protected]~prebuild: [email protected] 6 info lifecycle [email protected]~build: [email protected] 7 verbose lifecycle [email protected]~build: unsafe-perm in lifecycle true 8 verbose lifecycle [email protected]~build: PATH: C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\node-gyp-bin;D:\jjavi\Documents\git clones\apps-script-starter\node_modules\.bin;C:\Users\jjavi\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\local\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\Users\jjavi\bin;C:\Python27;C:\Python27\Scripts;C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\intel64_win\compiler;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0;C:\WINDOWS\System32\OpenSSH;C:\Program Files\Git\cmd;C:\Users\jjavi\AppData\Local\Programs\Python\Python37-32\Scripts;C:\Users\jjavi\AppData\Local\Programs\Python\Python37-32;C:\Users\jjavi\AppData\Local\Microsoft\WindowsApps;C:\Users\jjavi\AppData\Local\Programs\Microsoft VS Code\bin;C:\Mingw-w64\mingw64\bin;C:\adb;C:\Program Files (x86)\Universal Extractor;C:\Program Files (x86)\Universal Extractor\bin;C:\Program Files\nodejs;C:\ProgramData\chocolatey\bin;C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\intel64_win\compiler;C:\Users\jjavi\AppData\Local\Programs\Python\Python37-32\Scripts;C:\Users\jjavi\AppData\Local\Programs\Python\Python37-32;C:\Users\jjavi\AppData\Local\Microsoft\WindowsApps;C:\Users\jjavi\AppData\Local\Programs\Microsoft VS Code\bin;C:\Mingw-w64\mingw64\bin;C:\Users\jjavi\AppData\Roaming\npm;C:\Program Files\Git\usr\bin\vendor_perl;C:\Program Files\Git\usr\bin\core_perl 9 verbose lifecycle [email protected]~build: CWD: D:\jjavi\Documents\git clones\apps-script-starter 10 silly lifecycle [email protected]~build: Args: [ '/d /s /c', 'webpack' ] 11 silly lifecycle [email protected]~build: Returned: code: 1 signal: null 12 info lifecycle [email protected]~build: Failed to exec build script 13 verbose stack Error: [email protected] build: webpack13 verbose stack Exit status 1 13 verbose stack at EventEmitter.<anonymous> (C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\index.js:332:16) 13 verbose stack at EventEmitter.emit (events.js:311:20) 13 verbose stack at ChildProcess.<anonymous> (C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\lib\spawn.js:55:14) 13 verbose stack at ChildProcess.emit (events.js:311:20) 13 verbose stack at maybeClose (internal/child_process.js:1021:16) 13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5) 14 verbose pkgid [email protected] 15 verbose cwd D:\jjavi\Documents\git clones\apps-script-starter 16 verbose Windows_NT 10.0.18363 17 verbose argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "run" "build" 18 verbose node v12.16.1 19 verbose npm v6.13.4 20 error code ELIFECYCLE 21 error errno 1 22 error [email protected] build:webpack22 error Exit status 1 23 error Failed at the [email protected] build script. 23 error This is probably not a problem with npm. There is likely additional logging output above. 24 verbose exit [ 1, true ]

Could you help me please?
Thank you in advance!

Performance Issue [IMPORTANT]

When the number of files and number of code line getting increased in the project. Performance getting worst.

Even for a simple request it takes more than 5 seconds to complete the client request. [Need to check the network call from the browser side]

global.getCurrentUser = () => { return Session.getActiveUser().getEmail(); };

When above method calls from UI, it is taking around 5.73 seconds. (When there are another 15 methods available)

Unusable build output with fresh project

Steps to reproduce

Run the following commands:

  1. git clone https://github.com/labnol/apps-script-starter test-apps-script
  2. cd test-apps-script
  3. npm install
  4. npm run build

Expected Result

The built code.js file to contain the functions from the three imported files in src/index.js which can be run in Google Apps Script after pushing, which includes:

  • src/server/mail

sendmail()

  • src/server/menu

showHelp()
showCredits()
onOpen()

  • src/server/webapp

doGet()

Actual Result

Empty functions are written to the built file with all the actual code contained in an anonymous function.

function sendmail() {}
function showHelp() {}
function showCredits() {}
function onOpen() {}
function doGet() {}
(() => {
  var e = {
      173: (e, t, r) => {
        r.g.sendmail = () => {
          const e = Session.getActiveUser().getEmail(),
            t =
              '\n    <p>This email was sent using the <a href="https://www.labnol.org/internet/google-apps-script-developers/32305/">Google Apps Script Starter kit</a>.</p>\n    <p> The starter kit is used by <a href="https://digitalinspiration.com/">Digital Inspiration</a> for building popular Google Workspace add-on including <a href="https://workspace.google.com/marketplace/app/mail_merge_with_attachments/223404411203">Gmail Mail Merge</a> and <a href="https://workspace.google.com/marketplace/app/document_studio/429444628321">Document Studio</a>. </p>\n    <p>For assistance, please contact <a href="https://twitter.com/labnol">@labnol</a></p>',
            r = t.replace(/<[^>]+>/g, " ");
          GmailApp.sendEmail(e, "Hello from Google Apps Script", r, {
            htmlBody: t,
          }),
            Logger.log(`Email message sent to${e}`);
        };
      },
      933: (e, t, r) => {
        (r.g.showHelp = () => {
          Browser.msgBox(
            "Develop Google Apps Script project locally inside VS Code"
          );
        }),
          (r.g.showCredits = () => {
            SpreadsheetApp.getActiveSpreadsheet().toast(
              "Developed by Amit Agarwal @labnol"
            );
          }),
          (r.g.onOpen = () => {
            try {
              SpreadsheetApp.getUi()
                .createMenu("Apps Script Starter")
                .addItem("Help", "showHelp")
                .addSeparator()
                .addItem("Credits", "showCredits")
                .addToUi();
            } catch (e) {
              Logger.log(e.message);
            }
          });
      },
      540: (e, t, r) => {
        r.g.doGet = () =>
          HtmlService.createHtmlOutputFromFile("index.html")
            .setTitle("Google Apps Script")
            .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.DEFAULT);
      },
    },
    t = {};
  function __webpack_require__(r) {
    var o = t[r];
    if (void 0 !== o) return o.exports;
    var a = (t[r] = { exports: {} });
    return e[r](a, a.exports, __webpack_require__), a.exports;
  }
  (__webpack_require__.n = (e) => {
    var t = e && e.__esModule ? () => e.default : () => e;
    return __webpack_require__.d(t, { a: t }), t;
  }),
    (__webpack_require__.d = (e, t) => {
      for (var r in t)
        __webpack_require__.o(t, r) &&
          !__webpack_require__.o(e, r) &&
          Object.defineProperty(e, r, { enumerable: !0, get: t[r] });
    }),
    (__webpack_require__.g = (function () {
      if ("object" == typeof globalThis) return globalThis;
      try {
        return this || new Function("return this")();
      } catch (e) {
        if ("object" == typeof window) return window;
      }
    })()),
    (__webpack_require__.o = (e, t) =>
      Object.prototype.hasOwnProperty.call(e, t)),
    (() => {
      "use strict";
      __webpack_require__(173),
        __webpack_require__(933),
        __webpack_require__(540);
    })();
})();

Environment

> node -v

v16.13.0

> npm -v

8.1.0

> npm ls

[email protected] /path/to/test-apps-script
โ”œโ”€โ”€ @babel/[email protected]
โ”œโ”€โ”€ @babel/[email protected]
โ”œโ”€โ”€ @babel/[email protected]
โ”œโ”€โ”€ @babel/[email protected]
โ”œโ”€โ”€ @google/[email protected]
โ”œโ”€โ”€ @types/[email protected]
โ”œโ”€โ”€ @types/[email protected]
โ”œโ”€โ”€ @types/[email protected]
โ”œโ”€โ”€ @types/[email protected]
โ”œโ”€โ”€ [email protected] (git+ssh://[email protected]/googleworkspace/apps-script-oauth2.git#eebdf7884b019dac5160f6554059bf9537fda1cd)
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ””โ”€โ”€ [email protected]

Unit Test & Integration Test

Hey there, it's really glad to see this repo. It's easy to start, especially to me, new to GS. It saves me hours.

But I find there is no test solution in this repo. Is there possible to add unit test for it? Or integration test?

I know it may be out of this repo's scope, but I'd also like to discuss with you.

Missing module

I'm having trouble replicating your steps. I've tried multiple times, and it looks like something with webpack is malfunctioning. It's preventing me from compiling my work:

/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack-cli/bin/cli.js:74
                                throw err;
                                ^

Error: Cannot find module './node_modules/gas-webpack-plugin/node_modules/gas-entry-generator'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:668:15)
    at Function.Module._load (internal/modules/cjs/loader.js:591:27)
    at Module.require (internal/modules/cjs/loader.js:723:19)
    at require (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at Object.<anonymous> (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/gas-webpack-plugin/index.js:3:27)
    at Module._compile (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/v8-compile-cache/v8-compile-cache.js:178:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    at Module.load (internal/modules/cjs/loader.js:685:32)
    at Function.Module._load (internal/modules/cjs/loader.js:620:12)
    at Module.require (internal/modules/cjs/loader.js:723:19)
    at require (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at Object.<anonymous> (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/webpack.config.js:13:19)
    at Module._compile (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/v8-compile-cache/v8-compile-cache.js:178:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    at Module.load (internal/modules/cjs/loader.js:685:32)
    at Function.Module._load (internal/modules/cjs/loader.js:620:12)
    at Module.require (internal/modules/cjs/loader.js:723:19)
    at require (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/v8-compile-cache/v8-compile-cache.js:159:20)
    at WEBPACK_OPTIONS (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack-cli/bin/utils/convert-argv.js:115:13)
    at requireConfig (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack-cli/bin/utils/convert-argv.js:117:6)
    at /Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack-cli/bin/utils/convert-argv.js:124:17
    at Array.forEach (<anonymous>)
    at module.exports (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack-cli/bin/utils/convert-argv.js:122:15)
    at yargs.parse (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack-cli/bin/cli.js:71:45)
    at Object.parse (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/yargs/yargs.js:567:18)
    at /Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack-cli/bin/cli.js:49:8
    at Object.<anonymous> (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack-cli/bin/cli.js:368:3)
    at Module._compile (internal/modules/cjs/loader.js:816:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    at Module.load (internal/modules/cjs/loader.js:685:32)
    at Function.Module._load (internal/modules/cjs/loader.js:620:12)
    at Module.require (internal/modules/cjs/loader.js:723:19)
    at require (internal/modules/cjs/helpers.js:14:16)
    at Object.<anonymous> (/Users/pdavisjones/Documents/Coding/apps-script/honeybee4/node_modules/webpack/bin/webpack.js:156:2)
    at Module._compile (internal/modules/cjs/loader.js:816:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] build: `webpack`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/pdavisjones/.npm/_logs/2019-05-17T22_36_22_012Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] deploy: `npm run build && npm run upload`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] deploy script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/pdavisjones/.npm/_logs/2019-05-17T22_36_22_037Z-debug.log

Error: Nested clasp projects are not supported.

Hi
I am following your step by step guide on youtube to clone this repo, and I am getting stuck on the 5th step, to create a new clasp project.
npx clasp create --title "My Project" --rootDir ./dist --type standalone
Screenshot 2020-10-12 at 1 35 43 PM

Is there any misconfiguration done at my end? Do you happen to have an insight to this problem?

Error : unable to locate after build

Hello,
Someone can help me to resolve this :

After build :
npm run build && npm run upload

[email protected] build C:\Emeric\Polyvalence\gestion-polyvalence
webpack

LOG from copy-webpack-plugin
unable to locate 'C:\Emeric\Polyvalence\gestion-polyvalence\functions*.js' at 'C:\Emeric\Polyvalence\gestion-polyvalence\functions*.js'
unable to locate 'C:\Emeric\Polyvalence\gestion-polyvalence\src**.html' at 'C:\Emeric\Polyvalence\gestion-polyvalence\src**.html'

  • 21 hidden lines

ERROR in unable to locate 'C:\Emeric\Polyvalence\gestion-polyvalence\functions*.js' at 'C:\Emeric\Polyvalence\gestion-polyvalence\functions*.js'

ERROR in unable to locate 'C:\Emeric\Polyvalence\gestion-polyvalence\src**.html' at 'C:\Emeric\Polyvalence\gestion-polyvalence\src**.html'
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! [email protected] build: webpack
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:

clasp create command doesn't create .clasp.json file

Hello Sr. I don't know for sure if this is a bug, but opened this issue in order to report that when running the npx clasp create command, the .clasp.json file is not created in the root folder, as said in your blog.

As illustration:
$~ npx clasp create --type sheets --title "my_sheets" --rootDir ./dist
-> Created new Google Sheet: https://drive.google.com/open?id=11Q...
-> Created new Google Sheets Add-on script: https://script.google.com/d/123...
-> "ENOENT: no such file or directory, open 'dist/.clasp.json'"

I had to manually add the .clasp.json file into the root folder after the dist folder were created with npm run build, and it worked, but I think this would not be the expected behaviour.

Thanks in advance for your time and for this amazing bootstrapping for us newies in apps script.

Unauthenticated for users other than myself

Up until now, only I needed to use and execute the scripts. I followed the instructions (a couple of months ago) to set it up properly, and I can deploy and execute functions without problems. I seem to struggle to have other google accounts to execute the same functions though, and getting the following error from Google each time:

code: 401
message: "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project."
status: "UNAUTHENTICATED"

A screenshot of this same error in the frontend,

CleanShot 2020-06-23 at 08 53 25@2x

Any chance you might know why or what I am doing wrong? My manifest file:

{
  "timeZone": "Europe/Berlin",
  "dependencies": {
    "enabledAdvancedServices": [
      {
        "userSymbol": "Gmail",
        "serviceId": "gmail",
        "version": "v1"
      }
    ],
    "libraries": []
  },
  "webapp": {
    "access": "ANYONE",
    "executeAs": "SERVICE_ACCOUNT"
  },
  "exceptionLogging": "STACKDRIVER",
  "oauthScopes": [
    "https://www.googleapis.com/auth/gmail.send",
    "https://www.googleapis.com/auth/gmail.readonly",
    "https://www.googleapis.com/auth/gmail.settings.basic",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/script.scriptapp",
    "https://www.googleapis.com/auth/script.send_mail",
    "https://www.googleapis.com/auth/script.storage",
    "https://www.googleapis.com/auth/script.webapp.deploy",
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/script.container.ui"
  ]
}

and my Google client is initialised with the following scopes:

const SCOPES = [
  'email',
  'profile',
  'https://mail.google.com/',
  'https://www.googleapis.com/auth/userinfo.email',
  'https://www.googleapis.com/auth/drive.file',
  'https://www.googleapis.com/auth/drive.metadata',
  'https://www.googleapis.com/auth/script.projects',
  'https://www.googleapis.com/auth/script.container.ui',
  'https://www.googleapis.com/auth/script.external_request',
  'https://www.googleapis.com/auth/script.scriptapp',
  'https://www.googleapis.com/auth/script.send_mail',
  'https://www.googleapis.com/auth/script.storage',
  'https://www.googleapis.com/auth/script.webapp.deploy',
  'https://www.googleapis.com/auth/spreadsheets',
];

npm run build - failed

Hello, I tried to run npm run build but failed
image

this is the complete log:
0 info it worked if it ends with ok 1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'run', 'build' ] 2 info using [email protected] 3 info using [email protected] 4 verbose run-script [ 'prebuild', 'build', 'postbuild' ] 5 info lifecycle [email protected]~prebuild: [email protected] 6 info lifecycle [email protected]~build: [email protected] 7 verbose lifecycle [email protected]~build: unsafe-perm in lifecycle true 8 verbose lifecycle [email protected]~build: PATH: /usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/media/ayato/Data/Projects/github/echo-bot/echo-bot/node_modules/.bin:/home/ayato/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin 9 verbose lifecycle [email protected]~build: CWD: /media/ayato/Data/Projects/github/echo-bot/echo-bot 10 silly lifecycle [email protected]~build: Args: [ '-c', 'webpack' ] 11 silly lifecycle [email protected]~build: Returned: code: 2 signal: null 12 info lifecycle [email protected]~build: Failed to exec build script 13 verbose stack Error: [email protected] build: webpack13 verbose stack Exit status 2 13 verbose stack at EventEmitter.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:332:16) 13 verbose stack at EventEmitter.emit (events.js:321:20) 13 verbose stack at ChildProcess.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14) 13 verbose stack at ChildProcess.emit (events.js:321:20) 13 verbose stack at maybeClose (internal/child_process.js:1026:16) 13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5) 14 verbose pkgid [email protected] 15 verbose cwd /media/ayato/Data/Projects/github/echo-bot/echo-bot 16 verbose Linux 5.3.0-26-generic 17 verbose argv "/usr/local/bin/node" "/usr/local/bin/npm" "run" "build" 18 verbose node v13.8.0 19 verbose npm v6.13.6 20 error code ELIFECYCLE 21 error errno 2 22 error [email protected] build:webpack 22 error Exit status 2 23 error Failed at the [email protected] build script. 23 error This is probably not a problem with npm. There is likely additional logging output above. 24 verbose exit [ 2, true ]

Nested clasp projects are not supported.

Trying to follow the instructions from the readme, but fails at the first step, I get "nested clasp projects are not supported"

 ant@xeno ๎‚ฐ ~/Projects/apps-script-starter ๎‚ฐ npx clasp create --title "Hot Garbage" --rootDir ./dist
> Create which script?
standalone

Nested clasp projects are not supported.

functions in file with imports can't be created in webpack production mode

Steps to reproduce

Run the following commands:

git clone https://github.com/labnol/apps-script-starter test-apps-script
cd test-apps-script
add file testimport.js with below content under src/server folder and import it in src/index.js

import { makeQueryString } from './http';

global.testimport = () => {
  const url = makeQueryString('https://google.com');
  Logger.log(`Query string is ${url}`);
};

npm install
npm run build

Actual Result

in code.js, the new function definition is not created. The new function is not created in the apps script after deploy

function sendmail() {}
function showHelp() {}
function showCredits() {}
function onOpen() {}
function doGet() {}
...

Expected Result

function sendmail() {}
function showHelp() {}
function showCredits() {}
function onOpen() {}
function doGet() {}
function testimport() {}
...

Turn the webpack mode to none fix the problem.
Functions in file without imports also do not have this problem in both mode.
Is there a fix to support this in production mode?

npm run deploy fails

npm run deploy fails due to following:

Syntax error: Missing : after property ID. line: 11 file: webpack.config
Files to push were:
โ””โ”€ appsscript.json
โ””โ”€ dist/code.js
โ””โ”€ dist/index.html
โ””โ”€ node_modules/ajv/.tonic_example.js
โ””โ”€ node_modules/gas-entry-generator/.eslintrc.js
โ””โ”€ node_modules/gas-webpack-plugin/.eslintrc.js
โ””โ”€ node_modules/hash.js/.eslintrc.js
โ””โ”€ node_modules/npm/node_modules/ajv/.tonic_example.js
โ””โ”€ webpack.config.js

How to load user-defined js file in html?

Hello, I really like this tool as a beginner of GAS developer. But I have some issue loading a js script in html file. Is there a recommend way to do this? Thank you!

bundle.js via gulp for an add-on/script ui

Hi!

I have a not complete solution (it's based on this repo) which generate ui environment for the script via gulp. Please share ideas, how do you see the future of the labnol/apps-script-starter SDK? Have you identified a roadmap so that we can make suggestions and PRs?

Why ES6 code prettily not available after deployed to AppScript Editor

Since Google started supporting ES6 in their Appscript, we can directly move our ES6 code to app script. What is the purpose of converting the code into this type ? Is there any advantage ?

function rePayment() {
}(function(e, a) { for(var i in a) e[i] = a[i]; }(this, // (function(modules) { // webpackBootstrap
/
/ // The module cache

Stuck in Tutorial

I think this may be a bug but I'm not completely sure.

Hey there! I just followed your tutorial and encountered a few discrepancies. After pushing my files, I noticed that the webpack and babel config files were different from what your tutorial showed. Instead of seeing a code file, I found a dist folder with additional files. I also had to manually change the production setting in the constant file since there was no mention of it in the tutorial. Just wanted to give you a heads up and suggest updating that section of the video.

Here is a video with more details.

https://www.loom.com/share/dc3f7892250d463ba2d0cca6a8318130?sid=9441c887-6913-411a-b1f5-ee87fa413525

Add a watch script that auto-deploys on changes

It'd be nice to be able to watch for changes and auto-deploy them. The workflow is a little cumbersome because on every change you need to run npm run deploy.

Here's my current workflow:

  1. Make a change and save the file
  2. Run npm run deploy
  3. Switch to the browser and navigate to the Google Doc with the Add-on installed and enabled with Latest code.
  4. Refresh the page to get newest changes

Coming from other dev workflows, it just feels a little old-school to have to manually deploy and refresh when developing.

It'd be nice to have something like this:

  1. Run npm run watch or npm run dev (watches for changes)
  2. Make a change and save file (auto-deploys)
  3. Auto-reload browser page with Google Doc

Nice work on this, by the way! Everything else is great!

'YouTube' is not defined

I'm trying to use the YouTube Data API and getting this error when trying to deploy :

error 'YouTube' is not defined no-undef

I have included the following on my manifest file, but to no avail :

{ "userSymbol": "YouTube", "serviceId": "youtube", "version": "v3" }

And the line that throws the error is the following:

const results = YouTube.Search.list('id,snippet', options);

Not sure what else I should be doing, can someone help?

Here's my manifest file :

{ "timeZone": "Europe/London", "dependencies": { "enabledAdvancedServices": [{ "userSymbol": "Gmail", "serviceId": "gmail", "version": "v1" }, { "userSymbol": "Drive", "serviceId": "drive", "version": "v2" }, { "userSymbol": "YouTube", "serviceId": "youtube", "version": "v3" } ], "libraries": [{ "userSymbol": "OAuth1", "libraryId": "1CXDCY5sqT9ph64fFwSzVtXnbjpSfWdRymafDrtIZ7Z_hwysTY7IIhi7s", "version": "16" }, { "userSymbol": "OAuth2", "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF", "version": "33" } ] }, "webapp": { "access": "ANYONE", "executeAs": "USER_ACCESSING" }, "exceptionLogging": "STACKDRIVER", "oauthScopes": [ "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/youtube", "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/script.scriptapp", "https://www.googleapis.com/auth/script.storage", "https://www.googleapis.com/auth/script.webapp.deploy", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/script.container.ui" ] }

eslint-config-prettier version 8.x support

The eslint-config-prettier has released version 8.x which supports the simplicity with "All configs have been merged into one!" and updates relating to arrow-body-style and prefer-arrow-callback, so any plan to update the eslint-config-labnol to be compatible with eslint-config-prettier version 8.x?

Using object getter function will fail debugger

When using a getter function the GAS Editor debugging will fail with We're sorry, a server error occurred. The script will run as expected.

Steps to reproduce:

  1. Clone the app-script-starter repo
  2. Add a class with getter function
class Fail {
  constructor() {
    this.log = ['a', 'b', 'c'];
  }

  get latest() {
    return this.log[this.log.length - 1];
  }
}

global.failDebugger = () => {
  const f = new Fail();
  Logger.log(`Fail: ${f.latest}`);
};
  1. Debug failDebugger from GAS Editor

Expected result:

  • be able to debug

Actual result:

  • debugger fails w/ We're sorry, a server error occurred

Few notes:

  • actually it is not needed the functionality Fail to be used for the debugger to fail
  • the starter we where using was inspired (creative copy/paste) from Atlassian Gmail Addon

Pushing with clasp results in badRequest

Following the video on YouTube "Google Apps Script", after running 'npm run build', 'npx clasp push', results in
message: 'Syntax error: Missing : after property ID. line: 11 file: webpack.config'
line 11 in webpack.config is:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
At the end of the console it says:
"Pushed x files."
But when I open the Apps Script online, the files have not been updated.

Cannot get Axios or Fetch to work in Clasp Upload

Hi Labnol,
thanks for the awesome work. I have setup the project as described in your youtube video and the setup works fine.

Now I want to work with Rest APIs and be able to work with the output both in Node.js as well as in the Google Sheets Addon I am building.

In order to do this, I am using Quokka.js + Node within VS Code for prototyping.

Given the following premises:

  • Node doesn't support UrlFetchApp.fetch
  • GAS doesn't support native fetch (due to lack of the window and dom objects)

I decided to test out Fetch Polyfills (like cross-fetch) and axios + use babel-polyfill to handle promises, in order to allow the prototyping in node yet also get the same outcome in the browser.

Within node, everything works as expected, however once I add
const axios = require('axios'); to any .js file in my project I receive the following error when trying to push the code via Clasp.
code: 400, errors: [ { message: 'Syntax error: Missing name after . operator. line: ...., domain: 'global', reason: 'badRequest' } ] }
On the given line throwing the error it states module.exports.default = axios;
Once I comment out this line, the Clasp push works, but axios isn't working in the GAS environment.

Any ideas would be greatly appreciated!
Best regards
Mattis

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.