Skip to content

Commit 7becd79

Browse files
authored
fix(lambda): can't find entry file under ESM module system (#35797)
### Issue # (if applicable) Closes #21630. ### Reason for this change In the ESM module system, callsites returns filenames prefixed with 'file://'. This is not compatible with the NodeJS file utility functions such as fs.existsSync(). ### Description of changes Remove 'file://' prefix. ### Describe any new or updated permissions being added No new IAM permissions are added. ### Description of how you validated changes Unit tests. Integration test cannot be added as the integration test system uses CommonJS, it will be impossible to replicate the error which only happens under an ESM system. ### Credits This is mostly inspired by @okko for [his PR](#21802). He found the root cause and fix for this issue, but it didn't get merged due to a lack of integration tests. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 3a6f307 commit 7becd79

File tree

2 files changed

+26
-7
lines changed

2 files changed

+26
-7
lines changed

packages/aws-cdk-lib/aws-lambda-nodejs/lib/function.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,5 +292,8 @@ function findDefiningFile(scope: Construct): string {
292292
throw new ValidationError('Cannot find defining file.', scope);
293293
}
294294

295-
return sites[definingIndex].getFileName();
295+
// Fixes issue #21630.
296+
// ESM modules return a 'file://' prefix to the filenames, this should be removed for
297+
// compatibility with the NodeJS filesystem functions.
298+
return sites[definingIndex].getFileName().replace(/^file:\/\//, '');
296299
}

packages/aws-cdk-lib/aws-lambda-nodejs/test/function.test.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ let stack: Stack;
3737
beforeEach(() => {
3838
stack = new Stack();
3939
jest.clearAllMocks();
40+
// pretend the calling file is in a fake file path
41+
mockCallsites.mockImplementation(() => [
42+
{ getFunctionName: () => 'NodejsFunction' },
43+
{ getFileName: () => bockPath`function.test.ts` },
44+
]);
4045
});
4146

4247
// We MUST use a fake file system here.
@@ -57,12 +62,6 @@ bockfs({
5762
});
5863
const bockPath = bockfs.workingDirectory('/home/project');
5964

60-
// pretend the calling file is in a fake file path
61-
mockCallsites.mockImplementation(() => [
62-
{ getFunctionName: () => 'NodejsFunction' },
63-
{ getFileName: () => bockPath`function.test.ts` },
64-
]);
65-
6665
afterAll(() => {
6766
bockfs.restore();
6867
});
@@ -231,6 +230,23 @@ test('throws when entry is not js/ts', () => {
231230
})).toThrow(/Only JavaScript or TypeScript entry files are supported/);
232231
});
233232

233+
test('NodejsFunction with .js handler in an ESM package', () => {
234+
// pretend the calling file is in a fake file path
235+
// In ESM, callsites are prepended with 'file://'
236+
mockCallsites.mockImplementation(() => [
237+
{ getFunctionName: () => 'NodejsFunction' },
238+
{ getFileName: () => `file://${bockPath`function.test.ts`}` },
239+
]);
240+
241+
// WHEN
242+
new NodejsFunction(stack, 'handler2');
243+
244+
// THEN
245+
expect(Bundling.bundle).toHaveBeenCalledWith(stack, expect.objectContaining({
246+
entry: expect.stringContaining('function.test.handler2.js'), // Automatically finds .ts handler file
247+
}));
248+
});
249+
234250
test('accepts tsx', () => {
235251
const entry = bockPath`handler.tsx`;
236252

0 commit comments

Comments
 (0)