Corrección de errores 'Could not resolve' para dependencias de funciones Lambda en AWS Amplify Gen 2.
RESUMEN
Las funciones Lambda con su propio package.json necesitan dependencias instaladas antes de que esbuild las empaquete. Agrega una fase preBuild a amplify.yml que ejecute npm ci en cada directorio de función. También excluye amplify/**/* de tu tsconfig.json raíz.
Introducción
Si estás desplegando una aplicación AWS Amplify Gen 2 y obtiene errores como este durante ampx pipeline-deploy:
✘ [ERROR] Could not resolve "@aws-sdk/client-cognito-identity-provider"
amplify/functions/add-user-to-group/handler.ts:5:7:
5 │ } from "@aws-sdk/client-cognito-identity-provider";
╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
No estás solo. Este es un problema común cuando tus funciones Lambda tienen su propio package.json con dependencias.
El problema
Amplify Gen 2 usa esbuild para empaquetar tus funciones Lambda. Cuando defines una función con defineFunction() y tiene dependencias en su propio package.json, esas dependencias necesitan estar instaladas antes de que esbuild pueda empaquetarlas.
Aquí está una estructura típica de función:
amplify/
functions/
my-function/
handler.ts # imports @aws-sdk/client-cognito-identity-provider
resource.ts # defineFunction() config
package.json # declares the dependency
El problema: durante el despliegue en CI/CD, npm ci solo instala dependencias a nivel raíz. La carpeta node_modules de tu función no existe, así que esbuild falla.
La solución
Agrega una fase preBuild a tu amplify.yml que instale dependencias para todas las funciones Lambda:
version: 1
backend:
phases:
preBuild:
commands:
- npm ci --cache .npm --prefer-offline
# Install dependencies for all Lambda functions
- |
for dir in amplify/functions/*/; do
if [ -f "$dir/package.json" ]; then
echo "Installing dependencies in $dir"
(cd "$dir" && npm ci)
fi
done
build:
commands:
- npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
frontend:
phases:
preBuild:
commands:
- npm ci --cache .npm --prefer-offline
build:
commands:
- npm run build
artifacts:
baseDirectory: .next
files:
- "**/*"
cache:
paths:
- .npm/**/*
- node_modules/**/*
- .next/cache/**/*
La clave es el bucle que encuentra cada directorio de función con un package.json y ejecuta npm ci en él.
Bonus: El error "$amplify/env"
También podrías ver este error:
error TS2307: Cannot find module '$amplify/env/my-function' or its corresponding type declarations.
Esto sucede cuando tu tsconfig.json raíz recoge el directorio amplify. La corrección es excluirlo:
{
"exclude": ["node_modules", "amplify/**/*"]
}
Ten en cuenta el patrón amplify/**/* (no solo amplify). Amplify maneja su propia compilación de TypeScript usando amplify/tsconfig.json.
Por qué sucede esto
Amplify Gen 2 genera definiciones de tipo de variable de entorno en .amplify/generated/env/. Estos archivos son:
- Generados durante
ampx sandboxoampx pipeline-deploy - Ignorados en git (contienen valores específicos del despliegue)
- Referenciados vía el alias de ruta
$amplify/*enamplify/tsconfig.json
Durante CI/CD, estos archivos no existen hasta que el comando de despliegue los genera. Si tu tsconfig raíz intenta compilar el directorio amplify primero, falla porque los archivos generados aún no están ahí.
Lista de verificación rápida
- Cada función tiene su propio
package.jsoncon dependencias - Cada función tiene un
package-lock.json(comprometido en git) amplify.ymltiene una fase preBuild que instala dependencias de funciones- El
tsconfig.jsonraíz excluyeamplify/**/* amplify/tsconfig.jsontiene el mapeo de ruta$amplify/*
Ejemplo de package.json de función
{
"name": "my-function",
"version": "1.0.0",
"type": "module",
"dependencies": {
"@aws-sdk/client-cognito-identity-provider": "^3.0.0"
}
}
Mantenlo mínimo - solo incluye lo que la función realmente necesita.
¡Espero que esto te ahorre tiempo de depuración! La experiencia de desarrollo de Amplify Gen 2 es excelente una vez que conoces estos patrones.