fix(cli-internal): externalize Gen1 Lambda layer /opt/* requires in gen2-migration#14955
Draft
sarayev wants to merge 1 commit into
Draft
fix(cli-internal): externalize Gen1 Lambda layer /opt/* requires in gen2-migration#14955sarayev wants to merge 1 commit into
sarayev wants to merge 1 commit into
Conversation
…en2-migration
Gen1->Gen2 migration dropped Lambda layer handling entirely: migrated
functions that require '/opt/<layer>' (a Lambda layer runtime path) had
no corresponding layers config, so esbuild could not resolve '/opt/*' at
CDK asset-bundling time and the deploy failed with FailedToBundleAsset
(observed on customer app bpedsys, ticket V2205182405).
FunctionGenerator now scans the Gen1 function source for
require()/import of '/opt/<layer>' specifiers, normalizes them to their
layer root, and emits a defineFunction({ layers }) map keyed by each
'/opt/<layer>' module. In Gen2 the layers key is used to externalize the
module during esbuild bundling, so the build succeeds. The layer ARN is
unknown at migration time, so a REPLACE_WITH_LAYER_VERSION_ARN
placeholder is emitted with a TODO comment, and a migration warning is
surfaced in the plan summary and via the logger.
Scope note: this fixes the build-breaking externalization gap. Full
migration of the Gen1 layer package into a Gen2 custom LayerVersion is a
larger, separate change and is left as a documented follow-up.
Adds unit tests using real on-disk Gen1 function fixtures that exercise
the actual detection path (no mocking).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Gen1→Gen2 migration dropped Lambda layer handling entirely. When a Gen1 function's code references a Lambda layer via a
/opt/<layer>runtime path (e.g.require('/opt/GQLUtilities')), the migration tool:/opt/*requires in the generateddefineFunctionconfig.As a result the generated Gen2 app fails at CDK asset bundling — esbuild cannot resolve
/opt/*and the deploy fails withFailedToBundleAsset. Observed on customer app bpedsys (ticket V2205182405), whose migrated functions containedrequire("/opt/GQLUtilities").Root cause (exact gap)
packages/amplify-cli/src/commands/gen2-migration/generate/amplify/function/function.generator.ts—FunctionGenerator.plan()built theFunctionRenderOptions(env vars, runtime, schedule, triggers, IAM grants…) but never inspected the function source for/opt/*layer imports and never emitted alayersmap. There was zerolayer//opt/handling anywhere undergen2-migration/.@aws-amplify/backend-function's factory computes esbuild externals asexternalModules = Object.keys(props.layers), so populatingdefineFunction({ layers })with a/opt/<layer>key is exactly what externalizes the module and unblocks bundling.Fix (this PR — minimal, build-unblocking)
FunctionGenerator.detectLayerModules()scans the Gen1 function source (amplify/backend/function/<name>/src, recursive, skipsnode_modules,.js/.jsx/.ts/.tsx/.mjs/.cjs) forrequire()/import()/import … from '/opt/<layer>'and normalizes each to its layer root/opt/<layer>(deduped).FunctionRenderer.renderLayers()emits alayersmap insidedefineFunction, keyed by each/opt/<layer>module, with aREPLACE_WITH_LAYER_VERSION_ARNplaceholder value and a// TODOcomment (link to the layers docs). The key makes esbuild externalize the module → the build now succeeds.describe()) and vialogger.warnduring execution, telling the developer to replace the placeholder ARN(s) and noting that the Gen1 layer package itself is not migrated automatically.Scope / follow-up (honest boundaries)
This PR fixes the build-breaking externalization gap so migrated apps build with a single, clearly-documented manual step (supply the layer ARN). It does not migrate the Gen1 layer code (
function/<layer>/opt/*) into a Gen2 custom CDKLayerVersionand auto-wire it — that is a larger, riskier change recommended as a follow-up PR.Tests
Added unit tests in
function.generator.test.tsusing real on-disk Gen1 function fixtures (temp cwd, no mocking of the detection path):/opt/*requires via thelayersmap (and asserts it renders insidedefineFunction, before the escape-hatch fn);/opt/*imports to unique layer roots (no duplicate keys);describe();/opt/*imports (nolayersmap, no warning).Local results
function.generator.test.ts: 27 passed (23 pre-existing + 4 new), no snapshot changes.gen2-migration/generatesuite: 233 passed / 21 suites, zero regressions.tsc --noEmiton the package: clean.🤖 Draft PR opened via Roko.