2

I am unable to use the package p-map in my Azure Function. I get the following error:

Worker failed to load function: 'serverless' with function id: '<id>'.
Result: Failure
Exception: Worker was unable to load function serverless: 'Error [ERR_REQUIRE_ESM]: require() of ES Module <es-module> from /usr/local/Cellar/azure-functions-core-tools@4/4.0.4483/workers/node/worker-bundle.js not supported.
Instead change the require of index.js in /usr/local/Cellar/azure-functions-core-tools@4/4.0.4483/workers/node/worker-bundle.js to a dynamic import() which is available in all CommonJS modules.'

The project is created by following the steps in Azure's documentation. The following is in the index.ts:

import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import pMap from "p-map";
import got from "got";

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    const sites = [
        'https://avajs.dev',
        'https://github.com'
    ];

    const mapper = async site => {
        const {requestUrl} = await got.head(site);
        return requestUrl;
    };

    const result = await pMap(sites, mapper, {concurrency: 2});
    

    context.res = {
        // status: 200, /* Defaults to 200 */
        body: result
    };

};

export default httpTrigger;

My tsconfig.json looks like following:

{
  "compilerOptions": {
    "module": "es2020",
    "target": "es2020",
    "outDir": "dist",
    "rootDir": ".",
    "sourceMap": true,
    "strict": false,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true
  }
}

Lastly, this is my package.json:

{
  "name": "azure-functions-test",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "prestart": "npm run build",
    "start": "func start",
    "test": "echo \"No tests yet...\""
  },
  "dependencies": {
    "got": "^12.0.4",
    "p-map": "^5.3.0"
  },
  "devDependencies": {
    "@azure/functions": "^3.0.0",
    "typescript": "^4.0.0"
  }
}

p-map is strictly an ES Module and cannot be used in CommonJS projects.

Am I missing something or is it just not possible to use ES Module packages in Azure Functions? Thanks in advance.

GitHub repository of aforementioned code to test things out locally: azure-functions-test

2 Answers2

1

According to the docs on Node.js' website, specifying "type": "module" in your package.json should also indicate if Node should use ESM.

Here's what I did to get ESM working for my functions in my Function App:

tsconfig.json

{
  "compilerOptions": {
    "module": "ESNext",
    "target": "ESNext",
    "moduleResolution": "Node",
    "outDir": "dist",
    "rootDir": ".",
    "sourceMap": true,
    "strict": false,
    "noImplicitAny": true,
    "noUnusedLocals": true
  }
}

Some relevant function app settings:

WEBSITE_NODE_DEFAULT_VERSION: ~16 (To run using Node.js 16 runtime) FUNCTIONS_EXTENSION_VERSION: ~4

Then make sure to import your ES-style exports with a .js extension if your original extension is .ts. So if you have a file called custom.ts that has exports, then you should import them as `import { something } from "custom.js;".

And for any npm packages that use default exports (CommonJS style), you should import the package using its default export, i.e. import * as pkg from "pkg";.

Relevant links:

https://github.com/Azure/azure-functions-nodejs-worker/issues/104

https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?tabs=v2-v3-v4-export%2Cv2-v3-v4-done%2Cv2%2Cv2-log-custom-telemetry%2Cv2-accessing-request-and-response%2Cwindows-setting-the-node-version#ecmascript-modules (Note that this doc talks about importing your ESM exports with a .mjs extension but I didn't have to do that.)

praneetloke
  • 1,953
  • 1
  • 14
  • 15
0

I resolved my issue by renaming my index.ts file to index.mts. This built a index.mjs file (after running npm run build) in my dist folder which fixed the issue.

One thing to note is that you also have to edit your function.json's scriptFile key so it uses your .mjs file instead of non-existing .js file.