Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using ES Modules breaks when a directory with the same name as the module exists #93

Open
dantman opened this issue Dec 13, 2023 · 1 comment

Comments

@dantman
Copy link

dantman commented Dec 13, 2023

If you setup a project with the following structure:

  1. "type": "module" in package.json
  2. A hello-world.js file
  3. A hello-world/ folder
  4. Use hello-world.lambdaHandler as your module/handler
  5. Enable verbose mode, e.g. with ENV AWS_LAMBDA_RUNTIME_VERBOSE 1 in a Docker container using public.ecr.aws/lambda/nodejs:20, so you can see the verbose messages

This is the resulting log.

START RequestId: 99e7b316-ab71-4bd2-8aed-85df8b0aeaaf Version: $LATEST
2023-12-13T01:13:42.274Z        undefined       INFO    RUNTIME LOADER Try loading as commonjs:  hello-world  with paths: , /var/task 
2023-12-13T01:13:42.275Z        undefined       INFO    RUNTIME LOADER Try loading as commonjs: /var/task/hello-world
2023-12-13T01:13:42.276Z        undefined       INFO    RUNTIME LOADER globalPaths ["/opt/nodejs/node20/node_modules","/opt/nodejs/node_modules","/var/runtime/node_modules","/var/runtime","/var/task","/root/.node_modules","/root/.node_libraries","/var/lang/lib/node"]
2023-12-13T01:13:42.276Z        undefined       ERROR   Uncaught Exception      {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module '/var/task/hello-world'\nRequire stack:\n- /var/runtime/index.mjs","stack":["Runtime.ImportModuleError: Error: Cannot find module '/var/task/hello-world'","Require stack:","- /var/runtime/index.mjs","    at _loadUserApp (file:///var/runtime/index.mjs:1087:17)","    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"]}
13 Dec 2023 01:13:42,288 [ERROR] (rapid) Init failed error=Runtime exited with error: exit status 129 InvokeID=
2023-12-13T01:13:42.351Z        undefined       INFO    RUNTIME LOADER Try loading as commonjs:  hello-world  with paths: , /var/task 
2023-12-13T01:13:42.352Z        undefined       INFO    RUNTIME LOADER Try loading as commonjs: /var/task/hello-world
2023-12-13T01:13:42.353Z        undefined       INFO    RUNTIME LOADER globalPaths ["/opt/nodejs/node20/node_modules","/opt/nodejs/node_modules","/var/runtime/node_modules","/var/runtime","/var/task","/root/.node_modules","/root/.node_libraries","/var/lang/lib/node"]
2023-12-13T01:13:42.353Z        undefined       ERROR   Uncaught Exception      {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module '/var/task/hello-world'\nRequire stack:\n- /var/runtime/index.mjs","stack":["Runtime.ImportModuleError: Error: Cannot find module '/var/task/hello-world'","Require stack:","- /var/runtime/index.mjs","    at _loadUserApp (file:///var/runtime/index.mjs:1087:17)","    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"]}
END RequestId: a879dd58-2f3f-458a-9911-dbb92b552019
REPORT RequestId: a879dd58-2f3f-458a-9911-dbb92b552019  Init Duration: 0.29 ms  Duration: 156.42 ms       Billed Duration: 157 ms Memory Size: 128 MB     Max Memory Used: 128 MB
{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module '/var/task/hello-world'\nRequire stack:\n- /var/runtime/index.mjs","trace":["Runtime.ImportModuleError: Error: Cannot find module '/var/task/hello-world'","Require stack:","- /var/runtime/index.mjs","    at _loadUserApp (file:///var/runtime/index.mjs:1087:17)","    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"]}

Cause

Before trying to load a module an extensionless import is attempted. Because fs.existsSync does not differentiate between a directory and a file it returns true and a require on the directory is attempted without any try catch.

/**
* Attempt to load the user's module.
* Attempts to directly resolve the module relative to the application root,
* then falls back to the more general require().
*/
async function _tryRequire(appRoot, moduleRoot, module) {
verbose(
'Try loading as commonjs: ',
module,
' with paths: ,',
appRoot,
moduleRoot,
);
const lambdaStylePath = path.resolve(appRoot, moduleRoot, module);
// Extensionless files are loaded via require.
const extensionless = _tryRequireFile(lambdaStylePath);
if (extensionless) {
return extensionless;
}
// If package.json type != module, .js files are loaded via require.
const pjHasModule = _hasPackageJsonTypeModule(lambdaStylePath);
if (!pjHasModule) {
const loaded = _tryRequireFile(lambdaStylePath, '.js');
if (loaded) {
return loaded;
}
}
// If still not loaded, try .js, .mjs, and .cjs in that order.
// Files ending with .js are loaded as ES modules when the nearest parent package.json
// file contains a top-level field "type" with a value of "module".
// https://nodejs.org/api/packages.html#packages_type
const loaded =
(pjHasModule && (await _tryAwaitImport(lambdaStylePath, '.js'))) ||
(await _tryAwaitImport(lambdaStylePath, '.mjs')) ||
_tryRequireFile(lambdaStylePath, '.cjs');
if (loaded) {
return loaded;
}

return fs.existsSync(path) ? require(path) : undefined;

Background

I was working on a project using multiple ESModules based lambda functions. The code was transpiled from TypeScript and because some code needed to be shared between functions I had a hello-world.js in the root that was export * from './dist/hello-world/src/app.js'; to so the lambda function ran off the transpiled code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants