Corrección de errores 'Could not resolve' para dependencias de funciones Lambda en AWS Amplify Gen 2.

Consola de AWS Amplify con un despliegue fallido y el error de empaquetado could not resolve @aws-sdk/client-cognito-identity-provider

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:

  1. Generados durante ampx sandbox o ampx pipeline-deploy
  2. Ignorados en git (contienen valores específicos del despliegue)
  3. Referenciados vía el alias de ruta $amplify/* en amplify/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.json con dependencias
  • Cada función tiene un package-lock.json (comprometido en git)
  • amplify.yml tiene una fase preBuild que instala dependencias de funciones
  • El tsconfig.json raíz excluye amplify/**/*
  • amplify/tsconfig.json tiene 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.

  • Los Atributos de AWS Cognito User Pool No Pueden Ser Cambiados: Un Análisis Profundo.

    Los atributos del pool de usuarios no pueden ser cambiados después de que se ha creado un pool de usuarios porque los atributos de Cognito User Pool son inmutables después de la creación. Fusionar ramas con diferentes configuraciones de autenticación rompe los despliegues. Solución Rápida: Elimina la pila de CloudFormation (aws cloudformation delete-stack --stack-name YOUR-STACK) y redespliega. Advertencia: esto elimina todos los usuarios. Prevenlo: Define todos los atributos de usuario y grupos antes de tu primer despliegue en producción. Usa aplicaciones Amplify separadas por entorno en lugar de despliegues basados en ramas.

  • Corrección de errores de dependencia circular de CloudFormation en AWS Amplify Gen 2.

    Cuando tu función Lambda necesita acceso a Cognito Y se usa como controlador de datos, usa resourceGroupName: 'auth' en tu definición de función para evitar dependencias circulares.

  • No se puede resolver amplify_outputs.json

    Para corregir el error de compilación "no se puede resolver amplify_outputs.json", añade npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID a la configuración de compilación y adjunta la política AdministratorAccess-Amplify