Skip to content

Commit 635f745

Browse files
authored
Merge pull request #817 from andrewbranch/project-references
Support project references
2 parents ff2da73 + ca2c576 commit 635f745

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1614
-174
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ sudo: required
99
install:
1010
- yarn install
1111
- yarn build
12+
- yarn lint
1213
- yarn add $TYPESCRIPT
1314
env:
1415

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# Changelog
22

3+
## 5.2.0
4+
5+
* [feat: Initial support for project references - `projectReferences`](https://github.com/TypeStrong/ts-loader/pull/817) - thanks @andrewbranch!
6+
37
## 5.1.1
8+
49
* [fix(getTranspilationEmit): pass the raw path to transpileModule](https://github.com/TypeStrong/ts-loader/pull/835) - thanks @Brooooooklyn
510

611
## 5.1.0

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ Extending `tsconfig.json`:
543543

544544
Note that changes in the extending file while not be respected by `ts-loader`. Its purpose is to satisfy the code editor.
545545

546-
### experimentalFileCaching _(boolean) (default=false)_
546+
#### experimentalFileCaching _(boolean) (default=false)_
547547

548548
By default whenever the TypeScript compiler needs to check that a file/directory exists or resolve symlinks it makes syscalls.
549549
It does not cache the result of these operations and this may result in many syscalls with the same arguments ([see comment](https://github.com/TypeStrong/ts-loader/issues/825#issue-354725524) with example).
@@ -552,6 +552,32 @@ In some cases it may produce performance degradation.
552552
This flag enables caching for some FS-functions like `fileExists`, `realpath` and `directoryExists` for TypeScript compiler.
553553
Note that caches are cleared between compilations.
554554

555+
#### projectReferences _(boolean) (default=false)_
556+
557+
**TL;DR:** Using project references currently requires building referenced projects outside of ts-loader. We don’t want to keep it that way, but we’re releasing what we’ve got now. To try it out, you’ll need to pass `projectReferences: true` to `loaderOptions`.
558+
559+
ts-loader has partial support for [project references](https://www.typescriptlang.org/docs/handbook/project-references.html) in that it will _load_ dependent composite projects that are already built, but will not currently _build/rebuild_ those upstream projects. The best way to explain exactly what this means is through an example. Say you have a project with a project reference pointing to the `lib/` directory:
560+
561+
```
562+
tsconfig.json
563+
app.ts
564+
lib/
565+
tsconfig.json
566+
niftyUtil.ts
567+
```
568+
569+
And we’ll assume that the root `tsconfig.json` has `{ "references": { "path": "lib" } }`, which means that any import of a file that’s part of the `lib` sub-project is treated as a reference to another project, not just a reference to a TypeScript file. Before discussing how ts-loader handles this, it’s helpful to review at a really basic level what `tsc` itself does here. If you were to run `tsc` on this tiny example project, the build would fail with the error:
570+
571+
```
572+
error TS6305: Output file 'lib/niftyUtil.d.ts' has not been built from source file 'lib/niftyUtil.ts'.
573+
```
574+
575+
Using project references actually instructs `tsc` _not_ to build anything that’s part of another project from source, but rather to look for any `.d.ts` and `.js` files that have already been generated from a previous build. Since we’ve never built the project in `lib` before, those files don’t exist, so building the root project fails. Still just thinking about how `tsc` works, there are two options to make the build succeed: either run `tsc -p lib/tsconfig.json` _first_, or simply run `tsc --build`, which will figure out that `lib` hasn’t been built and build it first for you.
576+
577+
Ok, so how is that relevant to ts-loader? Because the best way to think about what ts-loader does with project references is that it acts like `tsc`, but _not_ like `tsc --build`. If you run ts-loader on a project that’s using project references, and any upstream project hasn’t been built, you’ll get the exact same `error TS6305` that you would get with `tsc`. If you modify a source file in an upstream project and don’t rebuild that project, `ts-loader` won’t have any idea that you’ve changed anything—it will still be looking at the output from the last time you _built_ that file.
578+
579+
**“Hey, don’t you think that sounds kind of useless and terrible?”** Well, sort of. You can consider it a work-in-progress. It’s true that on its own, as of today, ts-loader doesn’t have everything you need to take advantage of project references in Webpack. In practice, though, _consuming_ upstream projects and _building_ upstream projects are somewhat separate concerns. Building them will likely come in a future release. For background, see the [original issue](https://github.com/TypeStrong/ts-loader/issues/815).
580+
555581
### Usage with Webpack watch
556582

557583
Because TS will generate .js and .d.ts files, you should ignore these files, otherwise watchers may go into an infinite watch loop. For example, when using Webpack, you may wish to add this to your webpack.conf.js file:

appveyor.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ install:
1515
- ps: Install-Product node $env:nodejs_version
1616
- yarn install
1717
- yarn build
18+
- yarn lint
1819
- yarn add %TYPESCRIPT%
1920
test_script:
2021
- node --version

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
{
22
"name": "ts-loader",
3-
"version": "5.1.1",
3+
"version": "5.2.0",
44
"description": "TypeScript loader for webpack",
55
"main": "index.js",
66
"types": "dist/types/index.d.ts",
77
"scripts": {
88
"build": "tsc --version && tsc --project \"./src\"",
9+
"lint": "tslint --project \"./src\"",
910
"comparison-tests": "tsc --project \"./test/comparison-tests\" && npm link ./test/comparison-tests/testLib && node test/comparison-tests/run-tests.js",
1011
"comparison-tests-generate": "node test/comparison-tests/stub-new-version.js",
1112
"execution-tests": "npm i -g pnpm && node test/execution-tests/run-tests.js",
@@ -78,6 +79,8 @@
7879
"mocha": "^5.0.0",
7980
"prettier": "^1.11.1",
8081
"rimraf": "^2.6.2",
82+
"tslint": "^5.11.0",
83+
"tslint-config-prettier": "^1.15.0",
8184
"typescript": "^3.0.1",
8285
"webpack": "^4.5.0",
8386
"webpack-cli": "^2.1.2"

src/after-compile.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import * as path from 'path';
2-
import { collectAllDependants, formatErrors } from './utils';
2+
33
import * as constants from './constants';
4+
import { getEmitOutput } from './instances';
45
import {
6+
TSFile,
57
TSFiles,
68
TSInstance,
79
WebpackCompilation,
810
WebpackError,
9-
WebpackModule,
10-
TSFile
11+
WebpackModule
1112
} from './interfaces';
12-
import { getEmitOutput } from './instances';
13+
import {
14+
collectAllDependants,
15+
formatErrors,
16+
isUsingProjectReferences
17+
} from './utils';
1318

1419
export function makeAfterCompile(
1520
instance: TSInstance,
@@ -60,6 +65,7 @@ export function makeAfterCompile(
6065

6166
instance.filesWithErrors = filesWithErrors;
6267
instance.modifiedFiles = null;
68+
instance.projectsMissingSourceMaps = new Set();
6369

6470
callback();
6571
};
@@ -171,7 +177,7 @@ function provideErrorsToWebpack(
171177
otherFiles
172178
} = instance;
173179

174-
let filePathRegex = !!compilerOptions.checkJs
180+
const filePathRegex = !!compilerOptions.checkJs
175181
? constants.dtsTsTsxJsJsxRegex
176182
: constants.dtsTsTsxRegex;
177183

@@ -181,6 +187,15 @@ function provideErrorsToWebpack(
181187
}
182188

183189
const sourceFile = program && program.getSourceFile(filePath);
190+
191+
// If the source file is undefined, that probably means it’s actually part of an unbuilt project reference,
192+
// which will have already produced a more useful error than the one we would get by proceeding here.
193+
// If it’s undefined and we’re not using project references at all, I guess carry on so the user will
194+
// get a useful error about which file was unexpectedly missing.
195+
if (isUsingProjectReferences(instance) && !sourceFile) {
196+
continue;
197+
}
198+
184199
const errors = program
185200
? [
186201
...program.getSyntacticDiagnostics(sourceFile),

src/compilerSetup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import * as typescript from 'typescript';
21
import * as semver from 'semver';
2+
import * as typescript from 'typescript';
33

44
import * as constants from './constants';
5-
import * as logger from './logger';
65
import { LoaderOptions } from './interfaces';
6+
import * as logger from './logger';
77

88
export function getCompiler(loaderOptions: LoaderOptions, log: logger.Logger) {
99
let compiler: typeof typescript | undefined;

src/config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import * as typescript from 'typescript';
2-
import * as path from 'path';
31
import { Chalk } from 'chalk';
2+
import * as path from 'path';
3+
import * as typescript from 'typescript';
4+
import { LoaderOptions, Webpack, WebpackError } from './interfaces';
45
import * as logger from './logger';
56
import { formatErrors } from './utils';
6-
import { LoaderOptions, Webpack, WebpackError } from './interfaces';
77

88
interface ConfigFile {
99
config?: any;

src/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ export const ScriptTargetES2015 = 2;
1111

1212
export const ModuleKindCommonJs = 1;
1313

14+
export const extensionRegex = /\.[^.]+$/;
15+
export const tsxRegex = /\.tsx$/i;
1416
export const tsTsxRegex = /\.ts(x?)$/i;
1517
export const dtsDtsxOrDtsDtsxMapRegex = /\.d\.ts(x?)(\.map)?$/i;
1618
export const dtsTsTsxRegex = /(\.d)?\.ts(x?)$/i;
1719
export const dtsTsTsxJsJsxRegex = /((\.d)?\.ts(x?)|js(x?))$/i;
1820
export const tsTsxJsJsxRegex = /\.tsx?$|\.jsx?$/i;
1921
export const jsJsx = /\.js(x?)$/i;
2022
export const jsJsxMap = /\.js(x?)\.map$/i;
23+
export const jsonRegex = /\.json$/i;
2124
export const nodeModules = /node_modules/i;

0 commit comments

Comments
 (0)