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

fix(lambda-nodejs): esbuild detection with Yarn 2 in PnP mode #13257

Closed
wants to merge 7 commits into from

Conversation

jogold
Copy link
Contributor

@jogold jogold commented Feb 24, 2021

Refactor how esbuild is detected and run: check for a local installation
first and fallback to a global installation.

For local bundling, if a local version is detected, run esbuild using
the right package manager.

In Docker, always run the globally installed version.

Support for PNPM could now easily be added in another PR.

Closes #13179


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

Refactor how `esbuild` is detected and run: check for a local version
first and fallback to a global installation.

For local bundling, if a local version is detected, run `esbuild` using
the right package manager.

In Docker, always run the globally installed version.

Support for PNPM could now easily be added in another PR.

Closes aws#13179
@gitpod-io
Copy link

gitpod-io bot commented Feb 24, 2021

@andreialecu
Copy link
Contributor

andreialecu commented Feb 25, 2021

@jogold I have a question about how this module should be used.

Say I have a lambdas folder underneath my main cdk project. Do I need to create a package.json and lockfile separately within it with dependencies?

That seems to be the case with the current implementation, at least with yarn v2.

It would make it easier if that was not required, but instead it could take dependencies from the main cdk project's package.json. But currently that does not work.

To clarify, the only setup I got to work currently was something like:

cdk/package.json <- lambdas should be able to use deps from here
cdk/yarn.lock
cdk/bin/...
cdk/stacks/... <- stacks here
cdk/stacks/lambdas/package.json
cdk/stacks/lambdas/various-lambdas.ts
cdk/stacks/lambdas/yarn.lock
cdk/stacks/lambdas/node_modules

This is a bit error prone because I need to remember to run yarn install within the lambdas folder when changing dependencies. It also requires a bit of extra consideration to the CI script.

@jogold
Copy link
Contributor Author

jogold commented Feb 25, 2021

@andreialecu

Do I need to create a package.json and lockfile separately within it with dependencies?

No, you can have infra and runtime code next to each other with a single package.json and lock file for your whole project. See examples in https://github.com/jogold/cloudstructs and https://github.com/jogold/cdk-s3-thumbnail. What doesn't work for you when you try this?

@andreialecu
Copy link
Contributor

andreialecu commented Feb 25, 2021

@jogold I just tried this again, and if I delete the package.json and related files from the lambdas directory I'm getting:

 > create-auth-challenge.ts: error: Could not resolve "crypto-secure-random-digit" (mark it as external to exclude it from the bundle)
    3 │ import { randomDigits } from "crypto-secure-random-digit";

The main package.json does include that dependency.

@jogold
Copy link
Contributor Author

jogold commented Feb 25, 2021

@jogold I just tried this again, and if I delete the package.json and related files from the lambdas directory I'm getting:

 > create-auth-challenge.ts: error: Could not resolve "crypto-secure-random-digit" (mark it as external to exclude it from the bundle)
    3 │ import { randomDigits } from "crypto-secure-random-digit";

Can you share a repo with this issue?

@andreialecu
Copy link
Contributor

It seems that the problem is that this plugin would be needed:

https://github.com/yarnpkg/berry/tree/master/packages/esbuild-plugin-pnp

And unfortunately it only works with the build API, which cannot be used due to the aforementioned jsii issues.

I guess this will need to be mentioned as a caveat, that an intermediate package.json that uses plain node_modules needs to be used. Perhaps a CLI setting could be added to esbuild in order to specify plugins that way.

@jogold
Copy link
Contributor Author

jogold commented Feb 25, 2021

It seems that the problem is that this plugin would be needed:

OK, does this means that this PR is currently useless because even if we correctly detect the presence of esbuild, it won't be able to resolve the modules when bundling in a PnP setup?

@andreialecu
Copy link
Contributor

@jogold not necessarily, no.

The setup I described above works. It just needs an additional package.json and node_modules within the lambdas folder.

Also I believe that evanw/esbuild#884 might be a small change and I think it has the potential to be implemented in esbuild.

Alternatively, https://yarnpkg.com/features/protocols/#patch can be used to patch esbuild and force it to load the pnp plugin. It would be a minimal patch.

So this PR would still be a prerequisite for getting either of the two options above to work.

@andreialecu
Copy link
Contributor

andreialecu commented Feb 27, 2021

@jogold would it be feasible to allow overriding the builder, optionally, via a callback?

Here's an example of what I mean:

	import {build} from "esbuild";

    const cognitoEventsLambda = new lambda.NodejsFunction(this, id, {
      entry: path.resolve(__dirname, "cognito-lambdas", filename),
      handler: "handler",
      role: lambdaRole,
      builder: async (config) => {
         return await build({
           ...config,
           plugins: [pnpPlugin()],
         });
      }
    });

builder can be optional, and if specified, it is used instead of spawning the CLI here: https://github.com/aws/aws-cdk/pull/13257/files#diff-cd86fbd4f2bbefcbcffc2143adccabafa1debe5981edbcdfcc766b5a705fe770R154-R171

It would pass the esbuild config as a parameter, which the client side function can just pass along to esbuild (or further modify).

This way it delegates to user land - and because esbuild is running there a peer dependency is no longer necessary, so everything would still work.

this.packageManager = PackageManager.fromLockFile(props.depsLockFilePath);

Bundling.esbuildInstallation = Bundling.esbuildInstallation ?? EsbuildInstallation.detect();
const runsLocally = !!Bundling.esbuildInstallation?.version.startsWith(ESBUILD_VERSION);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe esbuildInstallation?.isLocal

Copy link
Contributor Author

@jogold jogold Mar 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are too many locals... this runsLocally here means local bundling (vs Docker bundling). The isLocal of the esbuildInstallation means is locally installed (vs globally installed).

try {
try {
// Check local version first
const version = getModuleVersion('esbuild');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this have to throw if the module doesn't exist? Can this be tryGetModuleVersion?

@jogold
Copy link
Contributor Author

jogold commented Mar 1, 2021

@jogold would it be feasible to allow overriding the builder, optionally, via a callback?

We could maybe let the user implement tryBundle() (or a esbuild bundling options enriched version of it) here

tryBundle(outputDir: string) {

(but it will have to be sync)

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject89A8053A-LhjRyN9kxr8o
  • Commit ID: 6b99302
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@eladb
Copy link
Contributor

eladb commented Apr 13, 2021

@jogold sorry for the delay... Can you update this branch and let me know if it's ready for a review?

@eladb
Copy link
Contributor

eladb commented May 2, 2021

@jogold closing for now. reopen when ready to continue.

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

Successfully merging this pull request may close these issues.

(aws-lambda-nodejs): does not properly detect esbuild when used with Yarn 2+ in PnP mode
4 participants