When using Yarn workspaces with one TS module depending on another, node isn't looking in the /dist
folder, so cannot find the js files it needs to run.
I'm using Yarn workspaces with the following structure:
tsconfig.json
package.json
packages/
shared/
index.ts
package.json
tsconfig.json
interfaces/
index.ts
apps/
server/
index.ts
package.json
tsconfig.json
Within apps/server, I want to import something from shared/interfaces/index.js, so I write import X from 'shared/interfaces'
.
However, the way my typescript is compiled, the shared
package in the node_modules folder once installed looks like this:
dist/
index.js
index.d.ts
interfaces/
index.js
index.d.ts
interfaces/
index.ts
index.ts
index.js
So if I import from just the index i.e. import X from 'shared'
, it's all fine. However, if I try to do import Y from 'shared/interfaces'
I get an ERR_MODULE_NOT_FOUND error (because it seems node is trying to pick up interfaces/index.js
instead of 'knowing' to look for dist/interfaces/index.js
instead.
How can I get node to look in the dist folder for a relative import?
Root package.json
{
"name": "supperclub",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": ["apps/*", "packages/*"],
"devDependencies": {
}
}
Root tsconfig.json
{
"references": [
{
"path": "apps/server"
},
{
"path": "packages/shared"
}
],
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
}
}
Shared package.json
{
"name": "shared",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",
"scripts": {
"compile": "tsc --build"
},
"files": ["dist/"],
"module": "CommonJS"
}
Shared tsconfig.json
{
"compilerOptions": {
"composite": true,
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
}
}
server package.json
{
"name": "server",
"version": "1.0.0",
"main": "dist/index.js",
"license": "MIT",
"type": "module",
"engines": {
"node": ">=14.20.1 <19"
},
"scripts": {
"dev": "nodemon index.js",
},
"devDependencies": {
"typescript": "^4.5.4"
},
"dependencies": {
"supper-club-shared": "*",
},
"references": [
{
"path": "../../packages/supper-club-shared"
}
]
}
server tsconfig.json
{
"compilerOptions": {
"target": "es2017",
"module": "es6",
"moduleResolution": "node",
"baseUrl": "./",
"resolveJsonModule": true,
"sourceMap": true,
"outDir": "./dist",
"esModuleInterop": true,
"strict": true,
"skipLibCheck": true,
"composite": true
},
"references": [{"path": "../../packages/supper-club-shared"}],
"include": ["src/**/*"]
}
Per nodejs docs you can use subpath exports as described here.
"exports": {
".": "./dist/index.js",
"./interfaces": "./dist/interfaces/index.js"
},
so on packages.json you might include the following:
{
"name": "server",
"version": "1.0.0",
"main": "dist/index.js",
"exports": {
".": "./dist/index.js",
"./interfaces": "./dist/interfaces/index.js"
},
"license": "MIT",
"type": "module",
"engines": {
"node": ">=14.20.1 <19"
},
"scripts": {
"dev": "nodemon index.js",
},
"devDependencies": {
"typescript": "^4.5.4"
},
"dependencies": {
"supper-club-shared": "*",
},
"references": [
{
"path": "../../packages/supper-club-shared"
}
]
}
Then you can import:
import .... from '{LIBNAME}/{MODULENAME}'