Closed8

Node.js Lambda で exports is not defined in ES module scope エラー。 mjs と cjs

hirenhiren

ランタイムに Node.js 22.x を指定した Lambda を作成

hirenhiren

自動生成されていたindex.mjsファイルに以下のコードを上書きして「Deploy」

index.mjs
exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const uri = request.uri;
  console.log("request URI: "+ uri);
  return request;
};
hirenhiren

CloudFront に紐づけて Lambda@edge として実行したところ、以下のエラーが発生(Test 実行の CloudFront 形式の event でも可)

CloudWatch Logs で Lambda のログを見ると以下のエラーが出力されていた

2025-02-05T11:42:40.089Z	undefined	ERROR	Uncaught Exception 	{
    "errorType": "ReferenceError",
    "errorMessage": "exports is not defined in ES module scope",
    "stack": [
        "ReferenceError: exports is not defined in ES module scope",
        "    at file:///var/task/index.mjs:3:1",
        "    at ModuleJob.run (node:internal/modules/esm/module_job:268:25)",
        "    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:543:26)",
        "    at async _tryAwaitImport (file:///var/runtime/index.mjs:1008:16)",
        "    at async _tryRequire (file:///var/runtime/index.mjs:1057:86)",
        "    at async _loadUserApp (file:///var/runtime/index.mjs:1081:16)",
        "    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)",
        "    at async start (file:///var/runtime/index.mjs:1282:23)",
        "    at async file:///var/runtime/index.mjs:1288:1"
    ]
}
hirenhiren

参考:ES モジュールとしての関数ハンドラーの指定:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-nodejs.html#designate-es-module

デフォルトで、Lambda は .js サフィックスが付いたファイルを CommonJS モジュールとして扱います。
オプションで、コードを ES モジュールとして指定できます。.mjs のファイル名拡張子を使用する方法で実行できます。


参考:Node.js ハンドラーの基本:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/nodejs-handler.html#nodejs-handler-basics

それぞれ、ハンドラー関数の定義の仕方が異なる

ES module handler の場合

export const handler = async (event, context) => {
  console.log("EVENT: \n" + JSON.stringify(event, null, 2));
  return context.logStreamName;
};

CommonJS module handler の場合

exports.handler = async function (event, context) {
  console.log("EVENT: \n" + JSON.stringify(event, null, 2));
  return context.logStreamName;
};
hirenhiren

CommonJS モジュールでのみ動作するコードだったため、実行時エラーが発生していた

hirenhiren

Lambda 作成時に自動作成されていたindex.mjsファイルを削除し、index.jsファイルを新規作成。
同コードを貼り付けて「Deploy」することで、エラーは解消された

hirenhiren

Node.js 公式ドキュメントにも同じ事が書いてある

https://nodejs.org/api/packages.html#determining-module-system

Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements or import() expressions:

  • Files with an .mjs extension.
  • Files with a .js extension when the nearest parent package.json file contains a top-level "type" field with a value of "module".
  • Strings passed in as an argument to --eval, or piped to node via STDIN, with the flag --input-type=module.
  • Code containing syntax only successfully parsed as ES modules, such as import or export statements or import.meta, with no explicit marker of how it should be interpreted. Explicit markers are .mjs or .cjs extensions, package.json "type" fields with either "module" or "commonjs" values, or the --input-type flag. Dynamic import() expressions are supported in either CommonJS or ES modules and would not force a file to be treated as an ES module. See Syntax detection.

Node.js will treat the following as CommonJS when passed to node as the initial input, or when referenced by import statements or import() expressions:

  • Files with a .cjs extension.
  • Files with a .js extension when the nearest parent package.json file contains a top-level field "type" with a value of "commonjs".
  • Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=commonjs.
  • Files with a .js extension with no parent package.json file or where the nearest parent package.json file lacks a type field, and where the code can evaluate successfully as CommonJS. In other words, Node.js tries to run such "ambiguous" files as CommonJS first, and will retry evaluating them as ES modules if the evaluation as CommonJS fails because the parser found ES module syntax.
このスクラップは2025/02/12にクローズされました