flowaccount / nx-plugins

Nx plugins built by FlowAccount team, helps deploy systems to the cloud
115 stars 34 forks source link

Allow for a serverless.ts file #85

Open ubergeoff opened 3 years ago

ubergeoff commented 3 years ago

FEATURE Allow for the use of a serverless.ts file instead of a serverless.yml file

SOLUTION I WOULD LIKE As per serverless nodejs examples - it is already possible to make use of a serverless.ts replacement for you serverless.yml file.

I would like to make use of the same serverless.ts functionality that is made is available in the serverless examples: https://github.com/serverless/serverless/tree/master/lib/plugins/create/templates/aws-nodejs-typescript

Check which provider is affected: [X] AWS [] Azure [] Google Cloud Platform

Check which framework is affected: [] Angular [] Nodejs [X] Serverless [] Lambda [] Infrastructure as a code

Additional context I find that it is far, far easier to make use of Typescript serverless.ts file instead of a serverless.yml file - as I can make simple constant references within my serverless.ts file.

Example:

import { environment } from './environment';
import { AuctionsTable } from './src/resources';
import { auctionTableIam } from './src/iam';
import { createAuction, getAuction, getAuctions, placeBid } from './src/functions';

...
...

provider: {
        name: 'aws',
        runtime: environment.runtime,
        region: environment.region,
        stage: environment.currentStage,
        memorySize: environment.memorySize,
        apiGateway: {
            minimumCompressionSize: 1024,
            shouldStartNameWithService: true
        },
        environment: {
            AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
            AUCTIONS_TABLE_NAME: AuctionsTable.Properties.TableName
        },
        lambdaHashingVersion: '20201221',
        iamRoleStatements: [auctionTableIam]
    },
    // import the function via paths
    functions: { createAuction, getAuctions, getAuction, placeBid },
    package: { individually: environment.prod, excludeDevDependencies: true },
    resources: {
        Resources: {
            AuctionsTable
        }
    }

Also I don't need to make references to serverless pseudo names or symbols - I can just use simple imports of constants within my project.

The implementation can stay as-is for the current configuration - but - just make use of the serverless.ts file.

Example:

 "deploy": {
                    "builder": "@flowaccount/nx-serverless:deploy",
                    "options": {
                        "buildTarget": "myapi:build:production",
                        "config": "apps/myapi/serverless.ts",
                        "location": "dist/apps/myapi",
                        "package": "dist/apps/myapi",
                        "stage": "dev"
                    }
                },

I tried the above but I get the following error:

An unhandled exception occurred: Cannot parse "serverless.yml": File not found

Would this be possible --? I think it would be an awesome addition to the work you have done so far..?

wickstargazer commented 3 years ago

sounds like awesomeness, would you like to open a pr? i can walk you through the code 🚀

ubergeoff commented 3 years ago

OK. Can do... whats the effort involved? (if you have to guess) ..?

wickstargazer commented 3 years ago

These are the two main places you need to fix

  1. Change all the configs to use .ts instead of .yaml
  2. rename the template file
  3. revisit the spec.ts and make sure it checks for .ts instead of .yaml
  4. Make sure the serverless.ts has the right initial code so that when schematics are generated it works out of the box

Tips:

  1. use yarn link to do local testing
  2. in https://github.com/flowaccount/nx-plugins/blob/master/libs/nx-serverless/src/utils/serverless.ts change import on the first line to be import * as Serverless from '/node_modules/serverless/lib/Serverless.js'; instead of 'serverless/lib/Serverless'; for local testing to work.

https://github.com/flowaccount/nx-plugins/blob/master/libs/nx-serverless/src/schematics/utils.ts#L18 https://github.com/flowaccount/nx-plugins/blob/master/libs/nx-serverless/src/schematics/api/files/serverless.yml.template

See whts comfortable :) we can review the code once its done :)

ubergeoff commented 3 years ago

Side note: The solution should be backwards compatible, correct?

i.e. users/devs should have the choice to choose between the serverless.yml file for the serverless.ts file - are you happy with this..?

ubergeoff commented 3 years ago

++ Serverless has this code in it: (when reading the serverless config file)

case '.ts': {
      if (!process[Symbol.for('ts-node.register.instance')]) {
        const tsNodePath = await (async () => {
          try {
            return await resolveTsNode(path.dirname(configurationPath));
          } catch (error) {
            throw new ServerlessError(
              `Cannot parse "${path.basename(
                configurationPath
              )}": Resolution of "ts-node" failed with: ${error.message}`,
              'CONFIGURATION_RESOLUTION_ERROR'
            );
          }
        })();
        try {
          require(tsNodePath).register();
        } catch (error) {
          throw new ServerlessError(
            `Cannot parse "${path.basename(
              configurationPath
            )}": Register of "ts-node" failed with: ${error.message}`,
            'CONFIGURATION_RESOLUTION_ERROR'
          );
        }
      }
    }
    // fallthrough
    case '.js': {
      const configurationEventuallyDeferred = (() => {
        try {
          return require(configurationPath);
        } catch (error) {
          if (isModuleNotFoundError(error, configurationPath)) {
            throw new ServerlessError(
              `Cannot load 1 "${path.basename(configurationPath)}": File not found`,
              'CONFIGURATION_NOT_FOUND'
            );
          }
          console.log(error);

          throw new ServerlessError(
            `Cannot load 2 "${path.basename(configurationPath)}": Initialization error: ${
              error && error.stack ? error.stack : error
            }`,
            'CONFIGURATION_INITIALIZATION_ERROR'
          );
        }
      })();
      try {
        return await configurationEventuallyDeferred;
      } catch (error) {
        throw new ServerlessError(
          `Cannot load "${path.basename(configurationPath)}": Initialization error: ${
            error && error.stack ? error.stack : error
          }`,
          'CONFIGURATION_INITIALIZATION_ERROR'
        );
      }
    }

However - it never seems to run to the .ts path - it always lands up in the "fall through" .js path... Any idea's why that might happen..?

The error I get is:

An unhandled exception occurred: Cannot load 2 "serverless.ts": Initialization error: C:\t2-online\t2\apps\myapi\serverless.ts:1
import { environment } from './environment';
^^^^^^

SyntaxError: Cannot use import statement outside a module
wickstargazer commented 3 years ago

Side note: The solution should be backwards compatible, correct?

i.e. users/devs should have the choice to choose between the serverless.yml file for the serverless.ts file - are you happy with this..?

I agree, as for the .js file i think its because the code is compiled into '.js' before the serverless commands are run? ... I am not sure when those switches are executed if before webpack-compile it should be ok but i am suspecting its after... Do you have a branch i can jump into?

wickstargazer commented 2 years ago

@ubergeoff We have released 1.1.0 that supports serverless.ts but there is sitll a bug when using import statements in the file itself. havent figured that out

kevb10 commented 1 year ago

any update on this?