How do I deploy my Typescript Node.js app to Heroku?
Asked Answered
A

8

15

When testing locally I was previously running:

"build-live": "nodemon --exec ./node_modules/.bin/ts-node -r dotenv/config -- ./index.ts"

I then figured my Procfile should be something like:

web: ./node_modules/.bin/ts-node -- ./index.ts

But it says module 'typescript' not found, even when it is in package.json. I read in a few places that ts-node is not the way to go to deploy to Heroku, so I am not sure what to do.

UPDATE: I think I am supposed to compile it, so I tried:

web: ./node_modules/.bin/tsc --module commonjs --allowJs --outDir build/ --sourceMap --target es6 index.ts && node build/index.js

This succeeds, however when actually running it, a bunch of the libs I'm using get "Cannot find module '...'".

Aport answered 10/4, 2017 at 8:14 Comment(0)
J
11

The command you've given Heroku is to launch the web "process" by compiling index.ts and dependencies and starting node at index.js. Depending on how things are timed, index.js might or might not exist at the time node starts.

You need to already have your sources compiled by the time you want to start your app. For example, web should just be web: node index.js or similar.

Each build process is different, so you need to figure that out for your own setup. But, suppose you have a classical setup where you push to git and then Heroku picks up that change and updates the app with the new slug. You could just compile things locally and include index.js and any other build output in the repository, for it to be available in the slug for Heroku to use.

A better approach is to use a build server which has an integration with Heroku. After you do the build there, configure it to send the build results to Heroku. Travis has a straighforward setup like this. This way you don't need to include build outputs in your repository, which is considered an anti-pattern.


On a sidenode, try using a tsconfig.json to keep the tsc configuration. It will save you from having to write such long command lines all over the place.

Johnathan answered 10/4, 2017 at 9:14 Comment(2)
Thanks. That makes sense. I borrowed that Procfile from github.com/clundie/hello-world-node-typescript-heroku/blob/…, but it seems this is bad practice, and now would be a great time to learn how to use CI like Travis. I'm now having trouble with tsc blowing out one of my folders, if you have any advice: #43320632Aport
In 2021, Travis starts at 69 USD/month. Relying on third party services like Travis to perform the compile seems suboptimal, even if pre-compiling is an antipattern. Other answers suggest making tsconfig a non-dev dependency and having heroku perform the compile. This also seems suboptimal, but at least it doesn't introduce third party dependencies.Wie
P
64

Alternatively you can have the TypeScript compile as a postinstall hook and run node build/index.js as the only Procfile command:

Your package.json should contain a postinstall hint that gets executed after npm install and before the node process launches:

"scripts": {
  "start": "node build/index.js",
  "build": "tsc",
  "postinstall": "npm run build"
}

You can then leave your Procfile as is:

web: npm start

This 'build on deploy' approach is documented by Heroku here.

Predictory answered 10/9, 2017 at 11:41 Comment(2)
Should we have typescript as a dev dependency or does it have to be a standard dependency?Pleochroism
@Pleochroism you add typescript as a dev dependencyPredictory
J
11

The command you've given Heroku is to launch the web "process" by compiling index.ts and dependencies and starting node at index.js. Depending on how things are timed, index.js might or might not exist at the time node starts.

You need to already have your sources compiled by the time you want to start your app. For example, web should just be web: node index.js or similar.

Each build process is different, so you need to figure that out for your own setup. But, suppose you have a classical setup where you push to git and then Heroku picks up that change and updates the app with the new slug. You could just compile things locally and include index.js and any other build output in the repository, for it to be available in the slug for Heroku to use.

A better approach is to use a build server which has an integration with Heroku. After you do the build there, configure it to send the build results to Heroku. Travis has a straighforward setup like this. This way you don't need to include build outputs in your repository, which is considered an anti-pattern.


On a sidenode, try using a tsconfig.json to keep the tsc configuration. It will save you from having to write such long command lines all over the place.

Johnathan answered 10/4, 2017 at 9:14 Comment(2)
Thanks. That makes sense. I borrowed that Procfile from github.com/clundie/hello-world-node-typescript-heroku/blob/…, but it seems this is bad practice, and now would be a great time to learn how to use CI like Travis. I'm now having trouble with tsc blowing out one of my folders, if you have any advice: #43320632Aport
In 2021, Travis starts at 69 USD/month. Relying on third party services like Travis to perform the compile seems suboptimal, even if pre-compiling is an antipattern. Other answers suggest making tsconfig a non-dev dependency and having heroku perform the compile. This also seems suboptimal, but at least it doesn't introduce third party dependencies.Wie
R
10

Fabian said that we could do something like:

"scripts": {
  "start": "node build/index.js",
  "build": "tsc",
  "postinstall": "npm run build"
}

As of me writing this, I tested this and can state: postinstall is not required since build script is ran by Heroku. If you want to do it without build script, then you can use heroku-postbuild which will run after dependencies are installed there you run tsc to compile.

Retinue answered 22/6, 2019 at 1:47 Comment(0)
H
2

My problem was about missing Typescript npm modules. The Typescript compiler tsc was not found when deployed the app to Heroku.

The Heroku deploy process (rightly) does not install development dependencies, in my case the Typescript module was part of devDependencies and thus the tsc command was not running on the Heroku platform.

Solution 1

Add typescript to dependencies: npm i typescript -s

Solution 2

  • Open Heroku console:

Heroku console

  • Select console type:

Select Heroku console type

  • Run the command npm i typescript && npm run tsc
Horntail answered 26/7, 2020 at 19:23 Comment(1)
@EmirKutlugün awesome brother!!Horntail
K
0

Install typescript as a dev dependency (cf. https://www.typescriptlang.org/download). Once built, your app does not need typescript anymore!

npm install -D typescript

Then in your package.json:

{
  "main": "index.js", // <- file will be generated at build time with `tsc`
  "scripts": {
    "build": "tsc",
    "start": "node ."
    "start:dev": "ts-node index.ts" // idem, install ts-node as a dev dependency
  }
}

The key point here is "build": "tsc".

Why?

Heroku does install all dependencies during build and remove the dev dependencies before the app is deployed (source here).

Node.js deployments will automatically execute an app’s build script during build (since March 11. 2019 source here)

Knowle answered 18/12, 2021 at 15:12 Comment(0)
C
0

In package.json

  "scripts": {
    "tsc": "./node_modules/typescript/bin/tsc",
    "postinstall": "npm run tsc"
  },

Works for me for Heroku deployment. Installing typescript npm install -D typescript and writing tsc in the build script "build": "tsc", does not work for me. Also, try to run npm i typescript && npm run tsc in the Heroku console which also does not work.

Crankpin answered 27/7, 2022 at 17:12 Comment(0)
M
0

This worked for me, I had a file server.ts that I ran through the build script ,see below:

"scripts": {
   "start": "node server.js",
   "build": "tsc",
   "heroku-postbuild": "npm run build",
}
Megaera answered 28/9, 2023 at 13:46 Comment(0)
W
-1

In my case, I remove some dependencies from "devDependencies" to "dependencies", so it goes like this:

"dependencies": {
    // The other dependencies goes here, I don't touch them.
    // But all TS dependencies I remove to here. 
    "ts-node": "^9.1.1",
    "tsconfig-paths": "^3.9.0",
    "typescript": "^4.2.3",
    "ts-loader": "^8.0.18"
},
Woolery answered 13/5, 2021 at 8:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.