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._pile (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:
{
"pilerOptions": {
"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/mon/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-mit": "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
() defers the need to use tslib as a prod dependency somehow.
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._pile (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:
{
"pilerOptions": {
"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/mon/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-mit": "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./package/backpack-core) defers the need to use tslib as a prod dependency somehow.
- 1 You can't. It's "a runtime library". Note that the install instructions don't show it being installed as a dev dependency. But why do you want to? – jonrsharpe Commented Mar 28, 2022 at 11:26
- 1 Looks like a bug in those boilerplate templates… – Bergi Commented Mar 28, 2022 at 11:27
- 1 Yes, and that's wrong. So why don't you just move it to the correct category? – jonrsharpe Commented Mar 28, 2022 at 11:35
- 1 Then raise this with whoever maintains the boilerplate – jonrsharpe Commented Mar 28, 2022 at 11:40
-
3
According to the docs of
tslib
that you've linked, using"importHelpers": false,
means that the generated code will no longer depend ontslib
and you can remove the dependency entirely (both dev and prod). Either way, raise this issue with the boilerplate template. – Bergi Commented Mar 28, 2022 at 12:23
1 Answer
Reset to default 5I had a similar issue and I fixed it by setting pilerOptions.importHelpers = false
in tsconfig.json
as @Bergi suggests in the ments. 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._pile (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
setpilerOptions.importHelpers = false
- Rebuild the project
- Check that
build/server/src/app.js
doesn'trequire("tslib")
anymore - Rebuild the Docker image
- Run a container based on the new Docker image
- Enjoy