2

I'm trying to call an async function using top-level await.

//index.ts

import serverless from 'serverless-http';

let handler;
const server = express();
const start = async (): Promise<void> => {
    
    //some function calls with await
    
    //server.use()

    handler = serverless(server);
};

await start(); //trying to use await here.
console.log(handler) //Without await the handler is undefined

module.exports.handler = handler;

To enable the top-level await, I have changed the "module" in tsconfig.json from "commonjs" to "esnext" and added "type": "module" in the top-level package.json.

//tsconfig.json

{
    "compilerOptions": {
        "module": "esnext",
        "esModuleInterop": true,
        "preserveConstEnums": true,
        "strictNullChecks": true,
        "sourceMap": true,
        "allowJs": true,
        "target": "es2017",
        "outDir": ".build",
        "moduleResolution": "node",
        "lib": [
            "es2015"
        ],
        "rootDir": "./"
    }
}
//package.json (removed unrelated parts)

{
    "main": "src/index",
    "scripts": {
        "start": "sls offline"
    },
    "type": "module"
    "dependencies": {
        "express": "4.17.1",
        "serverless-http": "^2.7.0"
    },
    "devDependencies": {
        "serverless-offline": "^7.0.0",
        "serverless-plugin-typescript": "^1.1.9",
        "ts-node": "9.1.1",
        "ts-node-dev": "1.1.6",
        "typescript": "4.2.4"
    }
}

When I run the application I'm getting the below error.

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: D:\project\.build\src\index.js
require() of ES modules is not supported.
require() of D:\project\.build\src\index.js from D:\project\node_modules\serverless-offline\dist\lambda\handler-runner\in-process-runner\InProcessRunner.js is an ES module file as it is a 
.js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.       
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from D:\project\.build\package.json.

And I can't remove "type": "module" from package.json because then I'm getting Can not use import statement outside a module like here.

Every package in the node_modules has its own package.json. So I'm not clear why I'm getting this error. Any help would be highly appreciated.

PS: I'm trying to convert a nodejs+express server to serverless by wrapping the express server with the help of serverless-http package. I tried this using another API where I don't have to use any async method and it worked fine. So the issue I'm currently having shouldn't be related to that.

Rukshan Jayasekara
  • 1,945
  • 1
  • 6
  • 26
  • It sounds like the `node_modules\serverless-offline\package.json` is missing? – Bergi Jun 25 '21 at 09:40
  • Yes @Bergi sound like it, but when I check, there were no issues with the `package.json` inside `serverless-offline`, and the `"type": "commonjs"` was there too. – Rukshan Jayasekara Jun 25 '21 at 09:46
  • 1
    Oh, wait, it's the other way round: "*require() of index.js **from** InProcessRunner.js*". The serverless library is requiring your index.js module. I guess it's impossible to make that an esm and use top-level await then. – Bergi Jun 25 '21 at 09:54
  • `module.exports` object is a part of CommonJS. ESM doesn't have that, it has `export` keyword. – Parzh from Ukraine Jul 03 '21 at 19:41
  • Also, it's pretty inconvenient and error-prone (and just weird) to export something asynchronously. What if `handler` is imported _before_ it gets initialized? Best case, it is `undefined`. I'd recommend exporting (synchronously, right away) an async function, that returns a promise that resolves to `handler`. That way, you at least don't have to deal with top-level `await`. Doesn't fix CommonJS/ESM problem, though. – Parzh from Ukraine Jul 03 '21 at 19:44

0 Answers0