typescript - NestJS și Serverless - handlerul 'handler' nu este o funcție


Încerc să implementez NestJS ca o funcție AWS Serverless folosind serverless-framework.

Urmăream această documentație oficială și codul meu este exact ca în documentație. Totuși, când îl rulez, primesc eroarea Failure: offline: handler 'handler' in [..] is not a function.

Dacă intru în codul meu sursă compilat din main.js și schimb linia exports.handler=handler; în module.exports.handler=handler;, începe să funcționeze.

Am încercat, de asemenea, să modific codul din main.ts pentru a acomoda acest lucru, dar nu ajută deoarece webpack îl compilează diferit atunci.

// main.ts
const handler ...;
module.exports.handler = handler;

Iată main.ts meu

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);
};

Iată serverless.yml al meu

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+}'

Iată fișierul meu webpack.config.js

return {
  ...options,
  externals: [],
  output: {
    ...options.output,
    libraryTarget: 'commonjs2',
  },
  // ... the rest of the configuration
};

Și în final, aici este fișierul 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
  }
}

Îmi lipsește vreo configurație pe webpack? Sau poate o schimbare în fișierele de configurare TypeScript? Nu am nici cea mai mică idee și documentația spune că ar trebui să funcționeze pur și simplu, totuși nu funcționează.

Teoretic, tot ce am nevoie este să fie module.exports.handler=handler în loc de exports.handler=handler în fișierul meu compilat pentru că, așa cum am spus, l-am schimbat și a început să funcționeze corect.

Aceasta este soluția provizorie pe care o folosesc, dar evident că aceasta este o modalitate greșită de a aborda problema.

"build": "nest build --webpack && sed -i 's/exports.handler = handler;/module.exports.handler = handler;/g' dist/main.js",

Răspuns #1

Am rezolvat acest lucru creând și asigurându-mă că ieșirea webpack are un libraryTarget de commonjs2. Creează (sau editează) un fișier webpack.config.js în rădăcina proiectului cu următorul conținut, asigurându-te că setăm libraryTarget la commonjs2:

module.exports = (options) => {
  return {
    ...options,
    output: {
      ...options.output,
      libraryTarget: 'commonjs2',
    },
  };
};

În fișierul meu serverless.yml am definit următoarele pentru funcția mea lambda:

...

functions:
  example:
    handler: "./dist/apps/example/main.js.handler"
...

Vă rugăm să rețineți că main.js.handler ar trebui să fie schimbat dacă punctul dvs. de intrare/funția este diferit. De exemplu, dacă ar fi fost entrypoint, acest șir ar fi dist/apps/example/main.js.entrypoint

Răspunsul #2

Am găsit soluția :) pentru aceeași problemă, dar cu serverless-plugin-typescript în workspace-ul nx

este totul despre tsconfig cu modul: commonjs

"compilerOptions": {  
  "module": "commonjs",
},

și apoi văd în folderul ./build

...
exports.main = main;