Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

244
Vistas
NodeJS 14.x: soporte nativo de importación/exportación de AWS Lambda

Estoy buscando hacer uso de la importación/exportación nativa que viene con ES6.

Estoy usando contenedores sin servidor dentro de AWS Lambda.

Tengo mi Dockerfile que se ve así:

 FROM public.ecr.aws/lambda/nodejs:14 COPY app ./ RUN npm install CMD [ "app.handler" ]

Luego tengo un directorio de app con mi código de aplicación. El código app.js se ve así:

 import { success } from './utils/log'; exports.handler = async () => { success('lambda invoked'); const response = 'Hello World'; return { statusCode: 200, body: JSON.stringify(response), isBase64Encoded: false, }; };

Como puede ver en esta línea, import { success } from './utils/log'; Estoy haciendo uso de importaciones nativas.

En mi paquete.json especifico esto:

 "type": "module"

Como necesito decirle a mi aplicación que este es un módulo y me gustaría importarlo de forma nativa. Si no especifico esto, obtengo:

 { "errorType": "Runtime.UserCodeSyntaxError", "errorMessage": "SyntaxError: Cannot use import statement outside a module", "stack": [ "Runtime.UserCodeSyntaxError: SyntaxError: Cannot use import statement outside a module", " at _loadUserApp (/var/runtime/UserFunction.js:98:13)", " at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)", " at Object.<anonymous> (/var/runtime/index.js:43:30)", " at Module._compile (internal/modules/cjs/loader.js:1063:30)", " at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)", " at Module.load (internal/modules/cjs/loader.js:928:32)", " at Function.Module._load (internal/modules/cjs/loader.js:769:14)", " at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)", " at internal/main/run_main_module.js:17:47" ] }

Entonces, lo especifico y le digo a Lambda que este es un módulo. Sin embargo, por mi vida, no puedo hacer que funcione, estoy viendo este error:

 { "errorType": "Error", "errorMessage": "Must use import to load ES Module: /var/task/app.js\nrequire() of ES modules is not supported.\nrequire() of /var/task/app.js from /var/runtime/UserFunction.js is an ES module file as it is a .js file whose nearest parent package.json contains \"type\": \"module\" which defines all .js files in that package scope as ES modules.\nInstead rename app.js to end in .cjs, change the requiring code to use import(), or remove \"type\": \"module\" from /var/task/package.json.\n", "code": "ERR_REQUIRE_ESM", "stack": [ "Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /var/task/app.js", "require() of ES modules is not supported.", "require() of /var/task/app.js from /var/runtime/UserFunction.js is an ES module file as it is a .js file whose nearest parent package.json contains \"type\": \"module\" which defines all .js files in that package scope as ES modules.", "Instead rename app.js to end in .cjs, change the requiring code to use import(), or remove \"type\": \"module\" from /var/task/package.json.", "", " at Object.Module._extensions..js (internal/modules/cjs/loader.js:1080:13)", " at Module.load (internal/modules/cjs/loader.js:928:32)", " at Function.Module._load (internal/modules/cjs/loader.js:769:14)", " at Module.require (internal/modules/cjs/loader.js:952:19)", " at require (internal/modules/cjs/helpers.js:88:18)", " at _tryRequire (/var/runtime/UserFunction.js:75:12)", " at _loadUserApp (/var/runtime/UserFunction.js:95:12)", " at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)", " at Object.<anonymous> (/var/runtime/index.js:43:30)", " at Module._compile (internal/modules/cjs/loader.js:1063:30)" ] }

Parece que /var/runtime/UserFunction.js está llamando a mi controlador de aplicaciones como un requisito y un módulo. Sin embargo, no tengo control sobre /var/runtime/UserFunction.js (¿no lo creo?). En mi Dockerfile he especificado Node14 . No sé muy bien dónde me he equivocado.

Lo que busco hacer es ejecutar el último y mejor de Node14 (como las importaciones) sin Babel/Transpiler que "inflan" mi código. Si alguien pudiera indicarme la dirección correcta de dónde me he equivocado, sería apreciado.

over 4 years ago · Santiago Trujillo
4 Respuestas
Responde la pregunta

0

Si alguien ve esto, se encuentra con el mismo problema. Consulte lo siguiente del soporte técnico oficial de AWS:

"Sus instrucciones para usar package.json { "type": "module" } son correctas, pero los módulos ECMAScript no son compatibles con el tiempo de ejecución de Lambda Node.js 14 en este momento".

Publicaré una actualización de esta publicación cuando escuche más sobre cuándo hay soporte disponible. Dejo esta pregunta aquí en caso de que otras personas tengan el mismo problema.

over 4 years ago · Santiago Trujillo Denunciar

0

AWS Lambda no es compatible oficialmente con ESM, pero con las siguientes soluciones funciona sin problemas.

Esta respuesta es un resumen de diferentes soluciones inspiradas en las respuestas/comentarios de Evan Sosenko y Dan Kantor y algunas ideas adicionales mías. Esto incluye un manejo más agradable para proyectos mecanografiados, pero partes de él también se pueden usar para proyectos simples de javascript.

Asumo lo siguiente:

  1. Se utiliza la versión 14 de Node.js: FROM public.ecr.aws/lambda/nodejs:14
  2. Se utilizan contenedores sin servidor: FROM public.ecr.aws/lambda/nodejs:14
  3. Las importaciones locales deberían funcionar sin que finalice el archivo: import { success } from './utils/log';
  4. Las importaciones desde libs deben usar la sintaxis de ESM: import AWS from 'aws-sdk';
  5. La lambda está escrita en mecanografiado: (.ts es el sufijo del archivo).

(También proporciono información para .js simple en lugar de mecanografiado al final)

Dockerfile

 FROM public.ecr.aws/lambda/nodejs:14 # copy only package.json + package-lock.json COPY package*.json ./ # install all npm dependencies including dev dependencies RUN npm install # copy all files not excluded by .dockerignore of current directory to docker container COPY . ./ # build typescript RUN tsc # remove npm dev dependencies as they are not needed anymore RUN npm prune --production # remove typescript sources # RUN rm -r src # rename all .js files to .mjs and fix imports except for handler.js RUN find ./dist -type f -name "*.js" -exec sed -i 's/\.js/\.mjs/g' {} \; RUN find ./dist -type f -name -and -not -name "handler.js" "*.js" -exec sh -c 'mv "$0" "${0%.js}.mjs"' {} \; # allow local imports without file ending - see: https://nodejs.org/api/esm.html ENV NODE_OPTIONS="--experimental-specifier-resolution=node" # set handler function CMD ["dist/lambda/handler.handler"]

Explicación

Dado que AWS Lambda solo admite commonJS, el punto de entrada de Lambda es un archivo commonJS. Esto se especifica mediante un paquete.json vacío que sobrescribe el paquete.json desde la raíz del proyecto. Como este archivo está vacío, no contiene: "type":"module" y por defecto todos los archivos en esa carpeta y subcarpetas son commonJS. Un archivo commonJS puede acceder a los archivos ESM si tiene la extensión .mjs, pero como el mecanografiado se compila en .js, uso algunos comandos de Unix para cambiar el nombre de todos los archivos con ".*js" después de llamar a tsc. El handler.js tiene que permanecer como ".js", así que le cambio el nombre de .mjs.
Más sobre ".js/.mjs"

Estructura de carpetas

 - src - - lambda - - - handler.ts (commonJS) - - - package.json (contains only: `{}`) - - app.ts (ESM) - - services - - - (other .ts files ESM) - package.json (contains `{"type": "module"}`, but also other settings) - Dockerfile - tsconfig.json

manejador.ts

 exports.handler = async (event) => { const {App} = await import('../app.js'); const app = new App(); return await app.run(event); };

aplicación.ts

 // example import library import AWS from 'aws-sdk'; // example import local file import {FileService} from './services/file.service'; class App { constructor() { } async run(event) { // write your logic here return { 'statusCode': 200, 'body': JSON.stringify({'message': 'hello world'}) } } } export {App};

tsconfig.json

 { "compilerOptions": { "module": "ESNext", "moduleResolution": "Node", "esModuleInterop": true, "declaration": true, "removeComments": true, "allowSyntheticDefaultImports": true, "target": "es6", "sourceMap": true, "outDir": "./dist", "baseUrl": "./src", "lib": [ "es6", "dom" ] }, "include": [ "src/**/*" ] }

Diferencias si no se usa mecanografiado

Supongamos que no está utilizando mecanografiado, pero javascript como se menciona en la pregunta que cambia lo siguiente:

  • no use el comando tsc en Dockerfile
  • no tiene un archivo tsconfig.json
  • todos los archivos deben tener el nombre *.js en lugar de *.ts
  • obviamente no use ninguna escritura mecanografiada (en mi ejemplo no hay ninguna)
over 4 years ago · Santiago Trujillo Denunciar

0

Esto funcionó para mí en Lambda Node 14.x -

en aplicación.js

 exports.lambdaHandler = async (event, context) => { const { App } = await import('./lib/app.mjs'); return new App(event, context); }

Y luego en lib/app.mjs -

 class App { constructor(event, context) { return { 'statusCode': 200, 'body': JSON.stringify({ 'message': 'hello world' }) } } } export {App}
over 4 years ago · Santiago Trujillo Denunciar

0

Parece que desde ayer finalmente hay soporte nativo para la sintaxis del módulo ES6 en Node 14 lambdas - consulte https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level -esperar-en-aws-lambda

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda