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 señalarme en la dirección correcta de dónde me he equivocado, sería apreciado.
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.
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}
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