Reputation: 7397
I'd like to make use of the project references features in TypeScript 3.1. The directory structure of my project originally looks like this after the compilation:
.
├── A
│ ├── a.ts
│ ├── dist
│ │ ├── A
│ │ │ └── a.js
│ │ └── Shared
│ │ └── shared.js
│ └── tsconfig.json
└── Shared
├── dist
│ └── shared.js
├── shared.ts
└── tsconfig.json
Contents of the Shared
directory:
shared.ts
:
export const name = "name";
tsconfig.json
:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "dist",
"strict": true
}
}
Contents of the A
directory:
a.ts
:
import { name } from "../Shared/shared";
console.log(name);
tsconfig.json
:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "dist",
"strict": true
}
}
And I could successfully run it by running node dist/A/a.js
in the A directory.
What I didn't like about this was that everything was getting copied into A's output directory. I thought project references are here to fix this problem.
To enable project references, I added the following line to Shared/tsconfig.json
.
"composite": true
And the following to A/tsconfig.json
:
"references": [
{ "path": "../Shared" }
]
Now when I compile, the directory structure is like the following, which is what I expected:
.
├── A
│ ├── a.ts
│ ├── dist
│ │ └── a.js
│ └── tsconfig.json
└── Shared
├── dist
│ ├── shared.d.ts
│ └── shared.js
├── shared.ts
└── tsconfig.json
However, when I run the node dist/a.js
in the A
directory, I get the following Error:
module.js:538
throw err;
^
Error: Cannot find module '../Shared/shared'
The reason is that in the generated a.js
file, the reference to the imported module is not resolved properly:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var shared_1 = require("../Shared/shared");
console.log(shared_1.name);
Is there a way to get it working without putting all output files into the same directory?
Or, is there a better way to organize my project to make use of project references?
Upvotes: 7
Views: 4130
Reputation: 31
The official recommendation, if I understand it correctly, is to set up a master output directory for the entire composite project and have Shared and A subdirectories inside it, so the source files and output files can have the same relative layout.
Matt's answer is great. Following up on the comment above, here is one way to reconfigure A
and Shared
so the imported module works properly.
A/tsconfig.json
:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "dist/A",
"strict": true
},
"references": [
{ "path": "../Shared" }
]
}
Shared/tsconfig.json
:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "../A/dist/Shared",
"composite": true,
"strict": true
}
}
The project structure after tsc --build
:
To run A
, call node dist/A/a.js
.
Upvotes: 0
Reputation: 30959
Indeed, getting relative import paths to work for both your source files and your output files is a pain. The official recommendation, if I understand it correctly, is to set up a master output directory for the entire composite project and have Shared
and A
subdirectories inside it, so the source files and output files can have the same relative layout. I don't know if that's what you meant you didn't want to do.
The only other option I know of is to have each component import the other components (in your case, you just have A
importing Shared
) using non-relative imports that point to output files (i.e., A/a.ts
would import a path like Shared/dist/shared
). Since you are using non-relative imports, the same import path appearing in either a source file or the corresponding output file resolves to the same target output file. Imports will not resolve in your IDE until you've built the composite project: this is a known limitation. Since tsc
doesn't rewrite imports, you'll need to set up your runtime environment and/or use a bundler to handle the non-relative imports and, if necessary, set the baseUrl
and paths
TypeScript compiler options to match.
I'll be happy to help you through the details of either approach if needed; just let me know where you get stuck.
Upvotes: 11