I have two folders: shared
and project1
in a folder node
. I am developing several independent Node projects located in the node
folder.
In shared
, I have an index.ts and it contains a default export. The outdir
parameter in tsconfig.json is ./dist
. When built, the directory is like:
node/shared/
src/
index.ts
dest/
index.js
tsconfig.json
...
In project1, I have index.ts, and under "normal" circumstances, when built, the directory is like:
node/project1/
src/
index.ts
dist/
index.js
My intention is to use shared
to contain shared utilities that can be used by different projects in the node
folder.
When I have a statement import shared from "../../shared/src/index.js"
in project1/src/index.ts
, the compiled output in the dest
folder goes crazy:
node/project1/
src/
index.js
dest/
shared/
src/
index.js <- copied from the shared project
project1/
src/
index.js
But it is still not workable, because the node modules installed in the shared
project are not present in project1
.
My intention is to have in the run-time environment something simple, with no duplication of common shared code, like:
node/
shared/
index.js
project1/
index.js <- importing stuff from shared/index
project2/
index.js <- importing stuff from shared/index
Is this possible? Or is converting the shared module into an NPM package the only way to go?
You can use project references.
node/
project1/
dist/
index.js
src/
index.ts
tsconfig.json
shared/
dist/
index.js
index.d.ts
src/
index.ts
package.json
tsconfig.json
This is set up like an ordinary project, except that the composite
setting must be enabled.
shared/tsconfig.json
{
"compilerOptions": {
// Referenced projects must have the composite flag turned on
"composite": true,
"rootDir": "./src",
"outDir": "./dist",
"module": "commonjs"
}
}
shared/package.json
{
"name": "shared",
"version": "0.0.1",
"main": "./dist",
"scripts": {
"build": "tsc"
},
"devDependencies": {
"typescript": "^4.0.3"
}
}
shared/src/index.ts
export default 'foo'
The output shared/dist/index.js
isn't too exciting:
"use strict";
exports.__esModule = true;
exports["default"] = 'foo';
Because of the composite
compiler flag, type definitions are also generated:
shared/dist/index.d.ts
declare const _default: "foo";
export default _default;
project1/tsconfig.json
Here, you specify that you are referencing the shared
module.
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"references": [
{"path": "../shared"}
]
}
project1/package.json
Instead of simply tsc
, you can use tsc --build
(tsc -b
for short). This build mode automatically rebuilds referenced projects if they are out of date. However, note that there are some specific build-only flags and you cannot override compiler options with command-line arguments.
{
"name": "project1",
"version": "0.0.1",
"main": "./dist",
"scripts": {
"build": "tsc -b"
},
"devDependencies": {
"typescript": "^4.0.3"
}
}
project1/src/index.ts
Use the shared module like you normally would.
import foo from '../../shared'
console.log(foo)
project1/dist/index.js
The source compiles down to this:
"use strict";
exports.__esModule = true;
var shared_1 = require("../../shared");
console.log(shared_1["default"]);
As you can see, it correctly imports the shared module from the node/shared
directory, instead of copying the files into dist
.
You do not need to specify the full path of the file (../../shared/dist/index.js
) because the main
field of the shared project's package.json
is set to ./dist
, which resolves to ./dist/index.js
. TypeScript knows that Node.js will resolve the require
to the appropriate file and therefore knows the types of the shared
module.
If you do not provide a main
entry in package.json
, you'll need to use import foo from '../../shared/dist'
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With