express icon indicating copy to clipboard operation
express copied to clipboard

Typescript Support?

Open Schavras opened this issue 5 years ago • 13 comments

Greetings and thanks for this awesome component.

Quick question. How I could use this with TypeScript?

I tried changing the input/src of the serverless.yml to the output of the compliled js, but on sls deploy, the node_modules was not deployed to the lambda.

Any thoughts on that?

Schavras avatar May 12 '20 11:05 Schavras

@Schavras only whatever you point your src input to will be available in your lambda. Anything outside that is excluded. In your case, if your node_modules is outside the folder containing the compiled js, then they're excluded.

To fix this I suggest pointing your src input to the root and exclude the src directory. Something like:

inputs:
  src:
    src: ./ # this is would be the root of your app. the folder containing node_modules
    exclude: # this would exclude your src files. Not super important though.
      - src 

Which would work with the following file structure:

|- src # your TS source
|- dist # your TS compiled files
|- node_modules
|- serverless.yml
|- app.js

where app.js contains a single line:

module.exports = require('./dist/app);

This might not be ideal, but I don't have much experience with TS. So suggestions are welcome!

eahefnawy avatar May 19 '20 08:05 eahefnawy

I tried changing the input/src of the serverless.yml to the output of the compliled js, but on sls deploy, the node_modules was not deployed to the lambda.

Any thoughts on that?

Regarding the node modules not being present, I was wondering if packaging them up in a Lambda Layer can be useful @eahefnawy @Schavras

Also, the part about single line app.js file, so can we use this technique to use any Node+express based framework along with this express component ?

Suedo avatar Jun 22 '20 16:06 Suedo

Might it be possible to solve this using a hook command like the website component does? Then it would be possible to configure the component to use webpack to transpile the TS sources with the contents of the node_modules directory into a ready-to-deploy output as part of serverless deploy?

zackdotcomputer avatar Sep 20 '20 18:09 zackdotcomputer

EDIT: Hey just for future folks who come across this thread - even though I came up with a possible workaround for this problem last year and have merged some fixes to this repo, I'm not a member of the Serverless team and, indeed, don't use the framework much in my day-to-day work anymore. Sorry but I won't be much help here even if you at-mention me in the future.

Ok so - spent the last 3 hours trying to do that and learned some things:

First off: you can indeed use the hook property to compile everything as part of deploy!

With that established, you now have to choose which compiler to use. I tested the vanilla tsc and Webpack's typescript-loader:

If you choose to go the webpack route:

  1. You have to tell Webpack to output a commonjs-module because of how the this component's injected code looks for the resulting handler. This requires using webpack@5, which is still in beta.
  2. You have to tell Webpack to output the file app.js because that's the only entry point this component supports.
  3. By default, you'll get one very small minified file. I don't know how much this affects the lambda response time, though, so it might not be worth it.

If you choose to go the tsc route:

  1. You get a much larger (but much more readable) output directory.
  2. But, as @Schavras noted, the node_modules are missing. I fixed this with the following build command in my package.json, which copies package and package-lock into the build directory, and then tells npm to install the production dependencies in there (which should be fairly quick since they should all be in the cache already):
{
  "scripts": {
    "build": "tsc && npm run build-dependencies",
    "build-dependencies": "cp package*.json build/ && npm i --only=prod --prefix=build"
  }
  // ... rest of file
}

(That bit there at the end is probably what you were looking for in your original question @Schavras - a simple way to copy only the non-dev node_modules into your build directory at the end of the compilation phase, so that it's ready to deploy.)

zackdotcomputer avatar Sep 20 '20 21:09 zackdotcomputer

EDIT: Hey just for future folks who come across this thread - even though I came up with a possible workaround for this problem last year and have merged some fixes to this repo, I'm not a member of the Serverless team and, indeed, don't use the framework much in my day-to-day work anymore. Sorry but I won't be much help here even if you at-mention me in the future and I can't promise that the fork below still works since I haven't touched it in a year.

Since I did all that coding to see if it was possible, I figured I'd PR it to the component. Whether or not the PR is accepted, feel free to check out the templates in my fork if you need something to base your own TS implementations off of.

zackdotcomputer avatar Sep 20 '20 21:09 zackdotcomputer

This is really helpful @zackdotcomputer! I've been trying to make this work with TS for ages. I thought the src in the YML was asking where my app was being exported from but of course I now realise it's asking for the base folder so no node_modules were being sent to Lamdba :(

Is there something I'm missing here? Why would they force us to use app.js in the root as entry?

freddieerg avatar Dec 14 '20 17:12 freddieerg

I'm glad it was helpful @freddieerg. Since this was 3 months ago, I don't remember with 100% accuracy but as I recall the app.js name is hard-coded in the code snippet that the Serverless team injects into lambda as the bootstrap bridge between the AWS APIs and the Serverless ones. Can't fully speak to why they chose to hardcode that rather than make it customizable, though I do get the impression that their team is pretty small and scrappy so they might have just saved that effort for something else.

zackdotcomputer avatar Dec 14 '20 20:12 zackdotcomputer

thanks @zackdotcomputer ...I tried running your example ts repo and ran into this error.

22s » Serverless » Failed running "src.hook": "npm run build" due to the following error: Command failed: npm run build
npm ERR! code ENOSELF
npm ERR! Refusing to install package with name "src" under a package
npm ERR! also called "src". Did you name your project the same
npm ERR! as the dependency you're installing?

I played around with a few different configurations and got some deploys to succeed but either ran into "express missing (node_modules not getting included) or internal server error if I try the approach from @eahefnawy ...i also got this error with his approach.

File 'c:/repos/api-ts/app.ts' is not under 'rootDir' 'c:/repos/api-ts/src'. 'rootDir' is expected to contain all source files.ts

...thinking I'll just stick with js for the time being until there is official ts support...if I keep playing around and get it to deploy correctly I will let you all know. thanks all!

nectarcode avatar Dec 31 '20 07:12 nectarcode

  • You have to tell Webpack to output the file app.js because that's the only entry point this component supports.

Just thought anyone reading this might want to know this is no longer the case, serverless will now honour whatever you have in the "main" of your package.json.

#60

freddieerg avatar Feb 22 '21 21:02 freddieerg

Great news, thanks for the update @freddieerg

zackdotcomputer avatar Feb 22 '21 21:02 zackdotcomputer

@zackdotcomputer this is awesome, thanks!

I've been trying to use your solution, and it deploys my TypeScript build folder successfully.

I can see that my Express server starts to run (a few console logs show up in CloudWatch), but then I get this unsupported framework error from the Serverless Express component's use of serverless-http on my deployed lambda and it stops running:

Error: Unsupported framework
    at getFramework (/var/task/_express/node_modules/serverless-http/lib/framework/get-framework.js:69:9)

My serverless.yml looks like this:

component: express
name: api

inputs:
  src:
    src: ./
    exclude:
      - src
    hook: yarn run build
    dist: dist
  roleName: ${output:permissions.name}
  env:
    DATABASE_URL: ${param:DATABASE_URL}
    STAGE: production
    NODE_ENV: production

And my tsconfig.json is like this:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "lib": ["es2019", "esnext"],
    "outDir": "./dist/",
    "removeComments": true,
    "noImplicitAny": false,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  },
  "include": ["./src"],
  "exclude": ["node_modules", "src/database/seeds"]
}

Finally, I've tried setting my server.js file to both

var app = require('./dist/server').default;
module.exports = app;

and

module.exports = require('./dist/server');

to no avail.

I can run my server from the dist folder locally so I'm not sure why I get this framework error.

Also fwiw, this is built using the Serverless Fullstack component but I figured it was more relevant to share the issue here.

I'm so close to deploying this thing! Anything jump out to you as a potential culprit?

MilesMorel avatar Sep 23 '21 05:09 MilesMorel

@zackdotcomputer this is awesome, thanks!

I've been trying to use your solution, and it deploys my TypeScript build folder successfully.

I can see that my Express server starts to run (a few console logs show up in CloudWatch), but then I get this unsupported framework error from the Serverless Express component's use of serverless-http on my deployed lambda and it stops running:

Error: Unsupported framework
    at getFramework (/var/task/_express/node_modules/serverless-http/lib/framework/get-framework.js:69:9)

...

Fixed. Turns out I had an Aurora Serverless Cluster that was falling asleep and my database wouldn't connect because the cold start time was longer than the Lambda timeout.

Still not sure if that's why I was getting the Unsupported Framework error but in the interest of time I ended up just deploying my server on a container and it worked fine 🤷‍♂️

Hope to come back and use this again soon.

MilesMorel avatar Sep 24 '21 21:09 MilesMorel

@MilesMorel @zackdotcomputer having this same issue 😔 Did you happen to find a fix?

Siyer2 avatar Jan 10 '23 05:01 Siyer2