-
Notifications
You must be signed in to change notification settings - Fork 4k
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
fix(lambda-nodejs): unable to use nodeModules
with pnpm
#21911
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your contribution! I don't think we can review this effectively at present. With 395 changes files, this almost certainly contains some unintended changes. I can't tell now many of these would be intentionally added to this PR.
Pull request has been modified.
The large number of files comes from the assets in the integration tests, as I tried to write a test for a scenario which wouldn't have worked prior to this fix. I've removed the integ test for now |
In that case, I'll want that test back in once we've done a review of this. Apologies for assuming it was an unintentional addition. |
@@ -298,13 +299,17 @@ interface BundlingCommandOptions { | |||
class OsCommand { | |||
constructor(private readonly osPlatform: NodeJS.Platform) {} | |||
|
|||
public writeJson(filePath: string, data: any): string { | |||
const stringifiedData = JSON.stringify(data); | |||
public write(filePath: string, data: any): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you provide further context on why this additional function is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have created write()
which takes a string and outputs it to a file. This is required for the pnpm-workspace.yaml
file.
writeJson()
receives any input, stringifies it, then calls write()
.
This way I have avoided duplicate code.
return `echo '${data}' > "${filePath}"`; | ||
} | ||
|
||
public writeJson(filePath: string, data: any): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And why this doesn't need the extra check for OS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OS check has been moved to the write()
function
@@ -39,7 +39,7 @@ export class PackageManager { | |||
case LockFile.PNPM: | |||
return new PackageManager({ | |||
lockFile: LockFile.PNPM, | |||
installCommand: logLevel && logLevel !== LogLevel.INFO ? ['pnpm', 'install', '--reporter', 'silent'] : ['pnpm', 'install'], | |||
installCommand: logLevel && logLevel !== LogLevel.INFO ? ['pnpm', 'install', '--reporter', 'silent', '--shamefully-hoist'] : ['pnpm', 'install', '--shamefully-hoist'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretend I don't know shit about pnpm here (because I don't). What is --shamefully-hoist
doing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm now using --config.node_linker=hoisted
, as explained in the PR description
@@ -219,6 +219,7 @@ export class Bundling implements cdk.BundlingOptions { | |||
|
|||
// Create dummy package.json, copy lock file if any and then install | |||
depsCommand = chain([ | |||
this.packageManager.lockFile === LockFile.PNPM ? osCommand.write(pathJoin(options.outputDir, 'pnpm-workspace.yaml'), ''): '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the only instance where you're using write
has no value for data
, I'm not sure I get why that function takes in two values and why it's being used here. Are you just creating an empty file titled pnpm-workspace.yaml
? Also, why use an empty string instead of undefined for this.packageManager.lockFile if it's not pnpm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes creating an empty pnpm-workspace.yaml
file avoids a problem when using workspaces. I have updated the PR description to explain.
I have created a general write()
function so it could be used by someone else in the future if they need to write a (non-empty) file, rather than creating a writeEmptyFile()
function which seems a bit bespoke.
I am using an empty string as chain()
takes an array of strings. It will be removed then all the commands are joined together into a single command.
Pull request has been modified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pull request linter has failed. See the aws-cdk-automation comment below for failure reasons. If you believe this pull request should receive an exemption, please comment and provide a justification.
✅ Updated pull request passes all PRLinter validations. Dissmissing previous PRLinter review.
I have added the test back, again the large number of files is due to the node_modules included in the snapshot. I have chosen |
This PR has been in the MERGE CONFLICTS state for 3 weeks, and looks abandoned. To keep this PR from being closed, please continue work on it. If not, it will automatically be closed in a week. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cecheta this looks great! I just have a couple of minor comments.
buildspec-pr.yaml
Outdated
@@ -16,6 +16,9 @@ phases: | |||
# Install yarn if it wasn't already present in the image | |||
- yarn --version || npm -g install yarn | |||
|
|||
# Install pnpm if it wasn't already present in the image | |||
- pnpm --version || npm -g install pnpm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buildspec.yaml
Outdated
@@ -16,6 +16,9 @@ phases: | |||
# Install yarn if it wasn't already present in the image | |||
- yarn --version || npm -g install yarn | |||
|
|||
# Install pnpm if it wasn't already present in the image | |||
- pnpm --version || npm -g install pnpm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need this.
}); | ||
|
||
new integ.IntegTest(app, 'PnpmTest', { | ||
testCases: [stack], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
testCases: [stack], | |
testCases: [stack], | |
stackUpdateWorkflow: false, // this will tell the runner to not check in assets. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thank you
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI I ran into a bug when updating the tests, raised #23407
yarn.lock
Outdated
@@ -2668,6 +2668,13 @@ aws4@^1.8.0: | |||
resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" | |||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== | |||
|
|||
axios@0.26.1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this file should have been updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the version of axios to use a version already in the lock file
Pull request has been modified.
// Will be installed, not bundled | ||
// (axios is a package with sub-dependencies, | ||
// will be used to ensure pnpm bundling works as expected) | ||
nodeModules: ['axios'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add forceDockerBundling: true
? I think if we force it to bundle inside docker it removes the need to add any of the dependencies in the repo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I switched to Docker bundling, but doing so demonstrated another issue, which is that when you use Docker bundling, the pnpm store is included in the asset by default. This is also the case on main
.
I've added a tmp directory for the store into the Dockerfile, and added --config.package-import-method=clone-or-copy
when running pnpm install
which resolves this issue
Pull request has been modified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one minor thing and then this is ready to go! 🚀
"@types/jest": "^27.5.2", | ||
"axios": "^0.27.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"axios": "^0.27.2", |
I don't think this is needed anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason, the tests in test/docker.test.js
are now failing
I can see in the logs:
time="2022-12-27T14:51:42.954645757Z" level=info msg="Attempting next endpoint for pull after error: denied: User: arn:aws:sts::464831875156:assumed-role/Ops-cdk-autobuild-prs-AutoBuildv2ProjectRoleC688F4-CY3ZTUL6CY8Q/AWSCodeBuild-b78b1055-51c8-4066-8449-8e563d561d94 is not authorized to perform: ecr:BatchGetImage on resource: arn:aws:ecr:us-east-1:464831875156:repository/library/esbuild because no identity-based policy allows the ecr:BatchGetImage action"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Squashing commits seemed to fix it, not sure why
Pull request has been modified.
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
Fixes aws#21910 By default, pnpm uses symlinks when installing dependencies, and modules only have access to dependencies in their `package.json`. This means when trying to bundle, dependencies of depedencies are not installed. This PR fixes this by using the ` --config.node_linker=hoisted` flag to create a flat `node_modules` structure. [Docs](https://pnpm.io/npmrc#node-linker). The second problem this PR fixes is when using pnpm workspaces. With workspaces, modules are installed within the workspace the command is run in. This means that when installing as part of bundling in a nested directory, no `node_modules` directory is produced at all. By creating a new `pnpm-workspace.yaml` file locally before installing, this essentially creates a new (nested) workspace, and `node_modules` is installed here. An empty file is enough for this to suffice. The PR also removes a `.modules.yaml` file from the `node_modules` after installing. This file contains a datetime of the last install, therefore it would cause the lambda code to change on each deployment if it was included in the bundle. I have tested this fix locally on both Mac and Windows. I have also included an integration test which failed before these changes, however I am not sure if it should be included due to the `node_modules` in the assets. ---- ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Fixes aws#21910 By default, pnpm uses symlinks when installing dependencies, and modules only have access to dependencies in their `package.json`. This means when trying to bundle, dependencies of depedencies are not installed. This PR fixes this by using the ` --config.node_linker=hoisted` flag to create a flat `node_modules` structure. [Docs](https://pnpm.io/npmrc#node-linker). The second problem this PR fixes is when using pnpm workspaces. With workspaces, modules are installed within the workspace the command is run in. This means that when installing as part of bundling in a nested directory, no `node_modules` directory is produced at all. By creating a new `pnpm-workspace.yaml` file locally before installing, this essentially creates a new (nested) workspace, and `node_modules` is installed here. An empty file is enough for this to suffice. The PR also removes a `.modules.yaml` file from the `node_modules` after installing. This file contains a datetime of the last install, therefore it would cause the lambda code to change on each deployment if it was included in the bundle. I have tested this fix locally on both Mac and Windows. I have also included an integration test which failed before these changes, however I am not sure if it should be included due to the `node_modules` in the assets. ---- ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Fixes #21910
By default, pnpm uses symlinks when installing dependencies, and modules only have access to dependencies in their
package.json
. This means when trying to bundle, dependencies of depedencies are not installed. This PR fixes this by using the--config.node_linker=hoisted
flag to create a flatnode_modules
structure. Docs.The second problem this PR fixes is when using pnpm workspaces. With workspaces, modules are installed within the workspace the command is run in. This means that when installing as part of bundling in a nested directory, no
node_modules
directory is produced at all. By creating a newpnpm-workspace.yaml
file locally before installing, this essentially creates a new (nested) workspace, andnode_modules
is installed here. An empty file is enough for this to suffice.The PR also removes a
.modules.yaml
file from thenode_modules
after installing. This file contains a datetime of the last install, therefore it would cause the lambda code to change on each deployment if it was included in the bundle.I have tested this fix locally on both Mac and Windows. I have also included an integration test which failed before these changes, however I am not sure if it should be included due to the
node_modules
in the assets.All Submissions:
Adding new Unconventional Dependencies:
New Features
yarn integ
to deploy the infrastructure and generate the snapshot (i.e.yarn integ
without--dry-run
)?By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license