Pesquisa de site

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;

Artigos relacionados