typescript - NestJS e Serverless - o handler 'handler' não é uma função
Estou tentando implementar o NestJS como uma função serverless da AWS usando o framework serverless.
Eu estava seguindo esta documentação oficial e meu código está exatamente como na documentação. No entanto, quando eu o executo, recebo o erro Falha: offline: handler 'handler' em [..] não é uma função.
Se eu entrar no meu código-fonte compilado de main.js e alterar a linha exports.handler=handler; para module.exports.handler=handler;, ele começa a funcionar.
Também tentei alterar o código em main.ts para acomodar isso, mas não ajuda, já que o webpack o está compilando de maneira diferente então.
// main.ts
const handler ...;
module.exports.handler = handler;
Aqui está o meu main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { Callback, Context, Handler } from 'aws-lambda';
import serverlessExpress from '@vendia/serverless-express';
import { AppModule } from './app.module';
let server: Handler;
async function bootstrap(): Promise<Handler> {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
}),
);
await app.init();
const expressApp = app.getHttpAdapter().getInstance();
return serverlessExpress({ app: expressApp });
}
export const handler: Handler = async (event: any, context: Context, callback: Callback) => {
server = server ?? (await bootstrap());
return server(event, context, callback);
};
Aqui está o meu serverless.yml
service:
name: serverless-example
plugins:
- serverless-offline
provider:
name: aws
runtime: nodejs12.x
functions:
main:
handler: dist/main.handler
events:
- http:
method: ANY
path: /
- http:
method: ANY
path: '{proxy+}'
Aqui está meu webpack.config.js
return {
...options,
externals: [],
output: {
...options.output,
libraryTarget: 'commonjs2',
},
// ... the rest of the configuration
};
E por último, aqui está o meu tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false,
"esModuleInterop": true
}
}
Estou perdendo alguma configuração no webpack? Ou talvez alguma mudança nos arquivos de configuração do TypeScript? Não faço ideia e a documentação diz que deveria funcionar, mas não funciona.
Teoricamente, tudo o que eu preciso é que seja module.exports.handler=handler em vez de exports.handler=handler no meu arquivo compilado, porque, como eu disse, eu mudei e começou a funcionar corretamente.
Esta é a solução provisória que estou usando, mas obviamente esta é a maneira errada de abordá-la.
"build": "nest build --webpack && sed -i 's/exports.handler = handler;/module.exports.handler = handler;/g' dist/main.js",
Resposta #1
Resolvi isso garantindo que a saída do webpack tenha um libraryTarget de commonjs2. Crie (ou edite) um arquivo webpack.config.js na raiz do projeto com o seguinte conteúdo, garantindo que definimos o libraryTarget como commonjs2:
module.exports = (options) => {
return {
...options,
output: {
...options.output,
libraryTarget: 'commonjs2',
},
};
};
No meu serverless.yml eu tenho o seguinte definido para a minha função lambda:
...
functions:
example:
handler: "./dist/apps/example/main.js.handler"
...
Por favor, note que main.js.handler deve ser alterado se o seu ponto de entrada/função for diferente. Por exemplo, se fosse entrypoint, esta string seria dist/apps/example/main.js.entrypoint
Resposta #2
Encontrei a solução :) para o mesmo problema, mas com serverless-plugin-typescript no workspace nx
há tudo sobre tsconfig com módulo: commonjs
"compilerOptions": {
"module": "commonjs",
},
e então eu vejo na pasta ./build
...
exports.main = main;
