简体   繁体   中英

Can I use ES modules in IBM Cloud Functions (node.js) or is only Common JS supported?

When I create a Node.js v16 function action from a zip file containing a simple estest.js :

function main(params) {
    return { message: 'Hello World' };
}

and package.json containing "type": "module" I get:

{
  "error": "Initialization has failed due to: Error [ERR_REQUIRE_ESM]: require() of ES Module /nodejsAction/1AfjbP59/estest.js from /nodejsAction/runner.js not supported.estest.js is treated as an ES module file as it is a .js file whose nearest parent package.json contains \"type\": \"module\" which declares all .js files in that package scope as ES modules.\nInstead rename estest.js to end in .cjs, change the requiring code to use dynamic import() which is available in all CommonJS modules, or change \"type\": \"module\" to \"type\": \"commonjs\" in /nodejsAction/1AfjbP59/package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead).\n\n    at eval (eval at <anonymous> (/nodejsAction/runner.js:51:31), <anonymous>:1:1)\n    at /nodejsAction/runner.js:51:31"
}

I have not found any IBM Cloud documentation which states that only the legacy Common JS style is supported.

EDIT:

Action created using:

ibmcloud fn action create test/estest estest.zip --kind nodejs:16

After some more research I've concluded the action itself can't be an ES Module.

I tried renaming it to estest.mjs (without "type":"module" in package.json ) which gave:

{"error": "Initialization has failed due to: Error [ERR_REQUIRE_ESM]: require() of ES Module /nodejsAction/azrfHRlh/estest.mjs not supported.\nInstead change the require of /nodejsAction/azrfHRlh/estest.mjs to a dynamic import() which is available in all CommonJS modules.\n    at eval (eval at <anonymous> (/nodejsAction/runner.js:51:31), <anonymous>:1:1)\n    at /nodejsAction/runner.js:51:31"}

which I believe is due to this require() in runner.js (the IBM Cloud / OpenWhisk implementation which tries to load my estest.mjs ES Module):

//  The module to require.
let whatToRequire = index !== undefined ? path.join(moduleDir, index) : moduleDir;
let handler = eval('require("' + whatToRequire + '").' + main);

require() does not support ES modules: https://nodejs.org/api/esm.html#esm_require .

Solution

As the error message suggests, the solution was to create a CommonJS wrapper ( estest.cjs ) which does a dynamic import() of my ES module estest.mjs and use "main": "estest.cjs" in package.json :

estest.cjs
async function main(params) {
    const { mjstest } = await import('./estest.mjs');
    return mjstest(params);
}

exports.main = main;
estest.mjs
export const mjstest = (params) => {
    return { message: `Hello ${params.name || 'World'}` };
}
package.json
{
    "name": "estest",
    "version": "1.0.0",
    "main": "estest.cjs"
}

I think the clue is in the error message:

supported.estest.js is treated as an ES module file as it is a .js file

have you tried changing the extension to supported.estest.mjs ?

It might also be worth specifying the node version in package.json eg.

  "engines": {
    "node": ">=16.x"
  },

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM