14

I'm deploying a dockerized typescript app on AWS. When I run the app container I get a ts-node error Error: Cannot find module 'typescript' which is not clear to me because typescript is defined as a devDependency. These are my package.json dependencies

{
 "name": "app-server",
 "version": "0.0.0",
 "description": "description",
 "author": "Marcello Bardus",
 "license": "MIT",
 "scripts": {
   "build": "tsc -p tsconfig.build.json",
   "format": "prettier --write \"src/**/*.ts\"",
   "start": "ts-node -r tsconfig-paths/register src/main.ts",
   "start:dev": "nodemon",
   "start:debug": "nodemon --config nodemon-debug.json",
   "prestart:prod": "rimraf dist && tsc",
   "start:prod": "node dist/main.js",
   "lint": "tslint -p tsconfig.json -c tslint.json",
   "test": "jest",
   "test:watch": "jest --watch",
   "test:cov": "jest --coverage",
   "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
 },
 "dependencies": {
   "@nestjs/common": "^5.4.0",
   "@nestjs/core": "^5.4.0",
   "@nestjs/typeorm": "^5.3.0",
   "@types/mongoose": "^5.3.18",
   "elliptic": "^6.4.1",
   "mongoose": "^5.4.14",
   "object-hash": "^1.3.1",
   "pg": "^7.8.0",
   "randomstring": "^1.1.5",
   "reflect-metadata": "^0.1.12",
   "rimraf": "^2.6.2",
   "rxjs": "^6.2.2",
   "sha2": "^1.0.2",
   "typeorm": "^0.2.13",
   "typescript": "^3.0.1"
 },
"devDependencies": {
  "@nestjs/testing": "^5.1.0",
  "@types/express": "^4.16.0",
  "@types/jest": "^23.3.1",
  "@types/node": "^10.7.1",
  "@types/supertest": "^2.0.5",
  "jest": "^23.5.0",
  "nodemon": "^1.18.10",
  "prettier": "^1.14.2",
  "supertest": "^3.1.0",
  "ts-jest": "^23.1.3",
  "ts-loader": "^4.4.2",
  "ts-node": "^7.0.1",
  "tsconfig-paths": "^3.5.0",
  "typescript": "^3.0.1",
  "tslint": "5.11.0"
},
"jest": {
  "moduleFileExtensions": [
    "js",
    "json",
    "ts"
  ],
"rootDir": "src",
"testRegex": ".spec.ts$",
"transform": {
  "^.+\\.(t|j)s$": "ts-jest"
},
"coverageDirectory": "../coverage",
"testEnvironment": "node"
  }
}

And the Dockerfile

FROM node
WORKDIR /usr/src/app

COPY . /usr/src/app

RUN npm install -g ts-node nodemon
RUN npm install
RUN npm install typescript

EXPOSE 8085

CMD ["nodemon", "."]

I suppose that typescript is installed locally once the container has been built but it's not. Thanks in advance

Marcello Bardus
  • 365
  • 2
  • 4
  • 13
  • try `npm i -g typescript` in your `Dockerfile` – molamk Feb 26 '19 at 22:18
  • Didn’t help, but thanks anyway. – Marcello Bardus Feb 26 '19 at 22:20
  • no problem. Can you include the full `package.json` __in your answer__? – molamk Feb 26 '19 at 22:22
  • Can you try installing `ts-node@^7.0.1` globally? This also matches the version in your `package.json`. Might be related to this issue: https://github.com/TypeStrong/ts-node/issues/765 – Kim Kern Feb 26 '19 at 22:32
  • @molamk Sadly, it's not possible to use ts-node with a globally installed typescript at the moment, see https://github.com/TypeStrong/ts-node/issues/707#issuecomment-457448149 – Kim Kern Feb 26 '19 at 22:34
  • 1
    `ts-node` is not really meant for production use. You should transpile your `Typescript` code into `JavaScript`, then call `node startingPoint.js` – molamk Feb 26 '19 at 22:38
  • 1
    @molamk I agree. In nest.js, you can use `npm run start:prod` which compiles the typescript and then runs the compiled javascript. – Kim Kern Feb 26 '19 at 22:47
  • Ts-nose is being installed globally, I tried to install typescript locally as in the issue but it doesn’t solve my problem – Marcello Bardus Feb 27 '19 at 06:15
  • package.json updated – Marcello Bardus Feb 27 '19 at 06:59
  • Is there a reason why you install ts-node, nodemon globally instead of just installing everything locally with npm install and then running `CMD [ “npm”, “run”, “start:prod” ]`, (or `start:dev` if you really want nodemon to run)? – Kim Kern Feb 27 '19 at 07:30
  • yes, when I install nodemon locally the app container throws "nodemon\": executable file not found in $PATH": unknown – Marcello Bardus Feb 27 '19 at 08:09
  • @KimKern `npm run start:prod` throws `app_1 | > rimraf dist && tsc app_1 | app_1 | sh: 1: rimraf: not found app_1 | npm ERR! file sh app_1 | npm ERR! code ELIFECYCLE app_1 | npm ERR! errno ENOENT app_1 | npm ERR! syscall spawn app_1 | npm ERR! app-server@0.0.0 prestart:prod: rimraf dist && tsc` – Marcello Bardus Feb 27 '19 at 08:18
  • Weird. Sounds like none of your local dependencies are being installed. What does it say when you remove rimraf dist && from your prestart:prod script? – Kim Kern Feb 27 '19 at 08:23
  • When I remove it, it throws `Error: Cannot find module '/usr/src/app/dist/main.js'`. Honestly I don't know how typescript is compiled maybe should I change dist/ to /build? – Marcello Bardus Feb 27 '19 at 08:33
  • `tsc` is the typescript compiler and compiles the javascript into `dist` as defined in your `tsconfig.json`. On your local machine, `npm run start:prod` works? – Kim Kern Feb 27 '19 at 09:06
  • No, throws cannot find module dist/main.ts. It seams that the typescript is not even compiled. What's weird is that when I run a docker container on my local machine using docker desktop everything works fine ... – Marcello Bardus Feb 27 '19 at 10:04

3 Answers3

19

Finally, I got ts-node to work using npx:

  1. Install typescript globally:

    npm i typescript -g
    
  2. Go to your project directory and link typescript to the project:

    cd <my-project>
    
    npm link typescript
    
  3. Execute ts-node using npx:

    npx ts-node <your-ts-script>.ts
    
Ashwin
  • 7,277
  • 1
  • 48
  • 70
3

I have installed typescript globally using - npm i typescript -g

Still getting the issue - Error: Cannot find module ‘@types/node/package.json‘

Then this helped me to resolve the issue - sudo npm install -D tslib @types/node

After this, I was able to run my script file using either of these -

npx ts-node <script-file>.ts 

OR

ts-node <script-file>.ts

You will get detailed explanation on the official npmjs website - https://www.npmjs.com/package/ts-node

Amit Baderia
  • 4,454
  • 3
  • 27
  • 19
1

If you plan to use ts-node and nodemon as starting point of your application, then explicitly define them in package.json dependencies.

Then RUN npm install --production

They'll be accesible in node_modules/.bin/

~/foo/node_modules/.bin

> ls
is-ci@    nodetouch@  rc@      ts-node@         ts-node-transpile-only@
nodemon@  nopt@       semver@  ts-node-script@  ts-script@

Then you can run ./node_modules/.bin/nodemon or npx nodemon as your Docker CMD.

npx

Executes either from a local node_modules/.bin, or from a central cache, installing any packages needed in order for to run.

source: npx


Tip to improve your Dockerfile, the right way to cache node_modules.

COPY package*.json /usr/src/app

Note that, rather than copying the entire working directory, we are only copying the package.json file. This allows us to take advantage of cached Docker layers.

Then copy app files

COPY . /usr/src/app

Don't forget .dockerignore node_modules.

Filip Seman
  • 1,252
  • 2
  • 15
  • 22