Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing tslib as a production dependency

I've created a TypeScript project (tsconfig at the end) and I've seen on several boilerplate templates for TypeScript projects that tslib library is added as a devDependency, and I've seen the Dockerfile for these as:

# STAGE: Development
FROM node:14-alpine3.13 AS dev
EXPOSE 8000

WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install

COPY . /app/
CMD ["yarn", "local"]

  
# STAGE: Builder
FROM node:14-alpine3.13 AS builder
WORKDIR /app
COPY --from=dev /app /app
RUN yarn build


# STAGE: Prod Dependencies Builder
FROM node:14-alpine3.13 AS prod-dependencies
WORKDIR /app
COPY ["package.json", "yarn.lock", "./"]
RUN yarn install --prod


# STAGE: Prod Deploy Ready Image
FROM node:14-alpine3.13 AS prod
EXPOSE 8000
WORKDIR /app
COPY public /app/public
COPY --from=builder /app/dist /app/dist
COPY --from=prod-dependencies /app/node_modules /app/node_modules
CMD ["node", "dist/index.js"]

so, essentially, we can see that all the devDependencies are being removed(and note tslib) was a dev dependency.

So, my question is, after a TypeScript project is transpiled to a JavaScript project, there should be no need for tslib to run the project, right?

Yet, why do I get the following error when I run app.js inside of the dist folder with the prod dependencies installed:

node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module 'tslib'
Require stack:
- /Users/myComputer/Desktop/newproject1/myproject-backend/dist/app.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (/Users/myComputer/Desktop/newproject1/myproject-backend/dist/app.js:3:15)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/Users/myComputer/Desktop/newproject1/myproject-backend/dist/app.js'
  ]
}

My tsconfig file is as follows:

{
  "compilerOptions": {
    "target": "es5",
    "sourceMap": true,
    "outDir": "./dist",
    "module": "CommonJS",
    "importHelpers": true,
    "removeComments": true,
    "downlevelIteration": true,
    "lib": ["es2015", "es2016", "es2017", "dom"],

    "strict": true,
    "alwaysStrict": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "strictNullChecks": true,
    "noImplicitReturns": true,
    "noUnusedParameters": true,
    "strictFunctionTypes": true,
    "noFallthroughCasesInSwitch": true,

    "baseUrl": "./src",
    "esModuleInterop": true,
    "preserveSymlinks": true,
    "resolveJsonModule": true,
    "moduleResolution": "node",
    "types": ["node", "express", "reflect-metadata"],
    "allowSyntheticDefaultImports": true,
    "paths": {
      "*": ["node_modules/*", "src/common/types/*", "src/*"]
    },

    "emitDecoratorMetadata": true,
    "experimentalDecorators": true
  },
  "include": ["app.ts", "src", "src/**/*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}

The package.json has the following contents:

{
    "name": "myproject-backend",
    "version": "1.0.0",
    "description": "",
    "main": "app.js",
    "engines": {
        "node": ">= 16.13.1"
    },
    "scripts": {
        "start": "node dist/app.js",
        "start_dev": "nodemon app.ts",
        "lint:check": "eslint .",
        "build": "npx tsc --build",
        "clean": "rm -R dist",
        "rebuild": "npm run clean && npm run build",
        "lint:fix": "eslint --fix .",
        "format:check": "prettier --check .",
        "format:write": "prettier --write .",
        "seedFile1": "ts-node seeds/01_file1.ts",
        "seedFile2": "ts-node seeds/02_file2.ts",
        "seed": "npm run seedFile1 && npm run seedFile2"
    },
    "lint-staged": {
        "*.{ts,js,json}": [
            "eslint --fix {src,scripts,test}/**/*.{ts,js,json} --no-error-on-unmatched-pattern"
        ]
    },
    "husky": {
        "hooks": {
            "pre-commit": "lint-staged"
        }
    },
    "keywords": [
        "api",
        "es6",
        "node",
        "express",
        "javascript",
        "typescript"
    ],
    "author": "",
    "license": "ISC",
    "dependencies": {
        "body-parser": "^1.19.2",
        "cors": "^2.8.5",
        "dotenv": "^16.0.0",
        "express": "^4.17.3",
        "helmet": "^5.0.2",
        "http-status-codes": "^2.2.0",
        "mongoose": "^6.2.6",
        "swagger-jsdoc": "^6.1.0",
        "swagger-ui-express": "^4.3.0",
        "uuidv4": "^6.2.12"
    },
    "devDependencies": {
        "@types/cors": "^2.8.12",
        "@types/dotenv": "^8.2.0",
        "@types/express": "^4.17.13",
        "@types/express-serve-static-core": "^4.17.28",
        "@types/helmet": "^4.0.0",
        "@types/mongoose": "^5.11.97",
        "@types/node": "^17.0.23",
        "@types/reflect-metadata": "^0.1.0",
        "@types/swagger-jsdoc": "^6.0.1",
        "@types/swagger-ui-express": "^4.1.3",
        "eslint": "^8.11.0",
        "eslint-config-prettier": "^8.5.0",
        "eslint-plugin-react": "^7.29.4",
        "husky": "^7.0.4",
        "nodemon": "^2.0.15",
        "prettier": "^2.5.1",
        "ts-node": "^10.7.0",
        "tslib": "^2.3.1",
        "typescript": "^4.6.3"
    }
}

EDIT: Also, do let me know if using a bundler like webpack or backpack(https://www.npmjs.com/package/backpack-core) defers the need to use tslib as a prod dependency somehow.

like image 248
juztcode Avatar asked Nov 28 '25 13:11

juztcode


1 Answers

I had a similar issue and I fixed it by setting compilerOptions.importHelpers = false in tsconfig.json as @Bergi suggests in the comments. So thanks for that @Bergi. I'm posting this answer for fellow coders who stumble upon this page in the future.

In my case, the details were:

Problem

Docker works with dev dependencies (installed using RUN npm install in the Dockerfile). However, ti throws the error below when dependencies are installed using the production way: RUN npm ci --omit=dev

2023-02-26T17:04:13.091231530Z node:internal/modules/cjs/loader:1078
2023-02-26T17:04:13.091314533Z   throw err;
2023-02-26T17:04:13.091321833Z   ^
2023-02-26T17:04:13.091327133Z 
2023-02-26T17:04:13.091332233Z Error: Cannot find module 'tslib'
2023-02-26T17:04:13.091337334Z Require stack:
2023-02-26T17:04:13.091342334Z - /app/server/src/app.js
2023-02-26T17:04:13.091347434Z     at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15)
2023-02-26T17:04:13.091355834Z     at Module._load (node:internal/modules/cjs/loader:920:27)
2023-02-26T17:04:13.091361034Z     at Module.require (node:internal/modules/cjs/loader:1141:19)
2023-02-26T17:04:13.091366135Z     at require (node:internal/modules/cjs/helpers:110:18)
2023-02-26T17:04:13.091371235Z     at Object.<anonymous> (/app/server/src/app.js:3:17)
2023-02-26T17:04:13.091376635Z     at Module._compile (node:internal/modules/cjs/loader:1254:14)
2023-02-26T17:04:13.091381635Z     at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
2023-02-26T17:04:13.091386835Z     at Module.load (node:internal/modules/cjs/loader:1117:32)
2023-02-26T17:04:13.091391835Z     at Module._load (node:internal/modules/cjs/loader:958:12)
2023-02-26T17:04:13.091396836Z     at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
2023-02-26T17:04:13.091402036Z   code: 'MODULE_NOT_FOUND',
2023-02-26T17:04:13.091407136Z   requireStack: [ '/app/server/src/app.js' ]
2023-02-26T17:04:13.091412136Z }
2023-02-26T17:04:13.091417036Z 
2023-02-26T17:04:13.091421837Z Node.js v18.14.2

Source of the problem

File build/server/src/app.js (after being built) requires tslib on line 3. However, tslib is not defined as a dependency in package.json. According to package-lock.json, tslib is just a transitive dependency of some development dependency.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const cors_1 = tslib_1.__importDefault(require("cors"));
const express_1 = tslib_1.__importStar(require("express"));
...

Fix

  • In server/tsconfig.json set compilerOptions.importHelpers = false
  • Rebuild the project
  • Check that build/server/src/app.js doesn't require("tslib") anymore
  • Rebuild the Docker image
  • Run a container based on the new Docker image
  • Enjoy
like image 99
McLayn Avatar answered Dec 01 '25 03:12

McLayn