SyntaxError: Cannot use import statement outside a module
I am new to make scripts in Node.js environment. I started to develope GAS application in the environment created by Apps Script in IDE (ASIDE). As I need to use the library Dayjs, I installed that and make scripts according to the official documentation. Then I got the error message "SyntaxError: Cannot use import statement outside a module". If anyone has any information that can help solve this please let me know. More information is below:
index.ts:
import dayjs from 'dayjs';
const now = dayjs();
const date_str = now.format('YYYY/MM/DD HH:mm:ss');
console.log(date_str);
appsscript.json:
{
"timeZone": "Asia/Tokyo",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"webapp": {
"executeAs": "USER_DEPLOYING",
"access": "ANYONE_ANONYMOUS"
}
}
package.json:
{
"name": "gas-sample-2",
"version": "0.0.0",
"description": "",
"main": "build/index.js",
"license": "Apache-2.0",
"keywords": [],
"type": "module",
"scripts": {
"clean": "rimraf build dist",
"lint": "npm run license && eslint --fix --no-error-on-unmatched-pattern src/ test/",
"bundle": "rollup --no-treeshake -c rollup.config.mjs",
"build": "npm run clean && npm run bundle && ncp appsscript.json dist/appsscript.json",
"license": "license-check-and-add add -f license-config.json",
"test": "jest test/ --passWithNoTests --detectOpenHandles",
"deploy": "npm run lint && npm run test && npm run build && ncp .clasp-dev.json .clasp.json && clasp push -f && source .env && clasp deploy $DEV_DEPLOYMENT_ID",
"deploy:prod": "npm run lint && npm run test && npm run build && ncp .clasp-prod.json .clasp.json && clasp push && source .env && clasp deploy $PROD_DEPLOYMENT_ID"
},
"engines": {
"node": ">=12"
},
"dependencies": {
"@google/clasp": "^2.4.2",
"@types/google-apps-script": "^1.0.83",
"@types/jest": "^29.5.12",
"@typescript-eslint/eslint-plugin": "^7.11.0",
"dayjs": "^1.11.11",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"gts": "^5.3.0",
"jest": "^29.7.0",
"license-check-and-add": "^4.0.5",
"ncp": "^2.0.0",
"prettier": "^3.2.5",
"rimraf": "^5.0.7",
"rollup": "^4.18.0",
"rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-license": "^3.4.0",
"rollup-plugin-prettier": "^4.1.1",
"rollup-plugin-typescript2": "^0.36.0",
"ts-jest": "^29.1.4",
"typescript": "^5.4.5"
}
}
tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"lib": ["ES2022"],
"sourceMap": true,
"moduleResolution": "node",
"outDir": "dist",
"rootDir": ".",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"allowSyntheticDefaultImports": true,
},
"include": ["src/**/*", "test/**/*", "rollup.config.mjs"]
}
I had a simmilar issue while trying to import jsonata.
Good news is that I managed to make it work. Sad news is it looks horrible.
I did the following additional steps:
installing rollup/plugin-commonjs and rollup/plugin-node-resolve via npm.
rollup.config.mjs
[...]
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
[...]
export default [
{
input: 'src/Code.ts',
output: {
dir: 'dist',
format: 'esm',
},
plugins: [
cleanup({ comments: 'none', extensions: ['.ts'] }),
license({
banner: {
content: {
file: fileURLToPath(new URL('license-header.txt', import.meta.url)),
},
},
}),
resolve({
exportConditions: ['import'],
}),
typescript(),
commonjs(),
prettier({ parser: 'typescript' }),
],
context: 'this',
},
[...]
Code.ts:
import jsonata from 'jsonata';
[...]
package.json:
"dependencies": {
"jsonata": "^2.0.5",
"@rollup/plugin-node-resolve": "^15.2.3",
}
Unfortunately jsonata has a const utils = require("./utils"); line. I believe this is the reasion for commonjs. However this also means that the output Code.js file contains 9k+ lines.
If someone would be able to help and find a way to move the dependency modules to a separate file, that would be amazing.
@ocsi01
Here's something I managed to get to work: Create two outputs with Rollup, one for your Code.ts and one for an "external" jsonata lib. Since AppsScript doesn't know modules, we'll have to use some trickery.
Step 1 - Create a jsonata-lib.ts file
jsonata-lib.ts
import 'jsonata';
Step 2 - Treat jsonata as an external library in Code.ts
Code.ts (example)
// import the jsonata type
import type jsonataNS from 'jsonata';
// declare jsonata as a global variable
declare global {
const jsonata: typeof jsonataNS;
}
async function run() {
const data = {
example: [{ value: 4 }, { value: 7 }, { value: 13 }],
};
// use jsonata
const expression = jsonata('$sum(example.value)');
const result = await expression.evaluate(data); // returns 24
console.log(result);
}
Step 3 - Configure Rollup to produce two outputs
rollup.config.mjs
import cleanup from 'rollup-plugin-cleanup';
import license from 'rollup-plugin-license';
import prettier from 'rollup-plugin-prettier';
import typescript from 'rollup-plugin-typescript2';
import nodeResolve from '@rollup/plugin-node-resolve';
import { fileURLToPath } from 'url';
export default [
{
input: 'src/jsonata-lib.ts',
output: {
dir: 'dist',
format: 'es',
},
plugins: [
cleanup({ comments: 'none', extensions: ['.ts'] }),
nodeResolve(),
typescript(),
],
},
{
input: 'src/Code.ts',
output: {
dir: 'dist',
format: 'es',
},
plugins: [
cleanup({ comments: 'none', extensions: ['.ts'] }),
license({
banner: {
content: {
file: fileURLToPath(new URL('license-header.txt', import.meta.url)),
},
},
}),
typescript(),
prettier({ parser: 'typescript' }),
],
context: 'this',
},
];
@k-fujishiro
As @ocsi01 stated, installing and using @rollup/plugin-node-resolve and @rollup/plugin-commonjs should fix this issue. The first will include imported node modules in your bundle, the second will make sure that rollup can handle CommonJS imports.