Typescript: If not all sources are under rootDir, you only get an error message when combined with outDir, not with outFile

Created on 1 Apr 2019  Â·  5Comments  Â·  Source: microsoft/TypeScript

I realize this may be the currently intended behavior — somewhere, I think I saw it explained that rootDir only affects the layout of files under the output directory. However, I argue that its current behavior, when combined with outFile, can be improved.

The issue is this: Suppose you specify a rootDir, and at least one file is NOT under that directory. Then:

  • If you are compiling with --outDir, you get an error message, as expected:

    error TS6059: File '...' is not under 'rootDir' '...'. 'rootDir' is expected to contain all source files.

  • But if you compile with --outFile, you get no error message, and the compiler completely ignores the specified rootDir. This means, for example, that if you have a bug in your tsconfig.json, generated AMD files will have unexpected module names.

TypeScript Version: 3.4.1

Search Terms: rootdir, amd, outfile

Code

A project with two tsconfig files — one targeting commonjs with --outDir, and one targeting amd with --outFile.

tsconfig.commonjs.json:

{
  "compilerOptions": {
    "rootDir": "src",
    "module": "commonjs",
    "outDir": "out"
  },
  "includes": [
    "src/**/*.ts",
    "other-src/**/*.ts"
  ]
}

tsconfig.amd.json:

{
  "compilerOptions": {
    "rootDir": "src",
    "module": "amd",
    "outFile": "out/bundle.js"
  },
  "includes": [
    "src/**/*.ts",
    "other-src/**/*.ts"
  ]
}

src/foo.ts:

export const name = "foo";

other-src/bar.ts:

export const name = "bar";

Expected behavior:

Compile with tsc -p tsconfig.commonjs.json. As expected, you get a TS6059 error, since other-src/bar.ts is not under the rootDir src.

Compile with tsc -p tsconfig.amd.json. I would expect that to get the same error, since.

Actual behavior:

When compiling with tsc -p tsconfig.amd.json, it compiles without complaint. But if you look at the generated out/bundle.js, you see this — notice the module names! They are "other-src/mylib" and "src/foo", completely ignoring the (incorrect) rootDir that I specified.

define("other-src/mylib", ["require", "exports"], function (require, exports) {
    "use strict";
    exports.__esModule = true;
    exports.name = "mylib";
});
define("src/foo", ["require", "exports"], function (require, exports) {
    "use strict";
    exports.__esModule = true;
    exports.name = "foo";
});

Related Issues:

In https://github.com/Microsoft/TypeScript/issues/9858#issuecomment-234379302, @mhegazy explained:

the rootDir is used to build the output folder structure. all files have to be under rootDir for the compiler to know where to write the output. without this constraint, if there are files that are not under rootDir, the compiler has two options 1. either they will be emitted in a totally unexpected place, or 2. not emitted at all. i would say an error message is much better than a silent failure.

I agree with this reasoning; but I think it should apply to outFile scenarios as well as to outDir ones.

Bug

Most helpful comment

My workaround for monorepo:

  1. set references in package1's tsconfig.json
{
  "compilerOptions": {
    "declarationDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"],
  "references": [
    {
      "path": "../package2"
    }
  ]
}

  1. set composite in package2's tsconfig.json
"compilerOptions": {
    "declarationDir": "dist",
    "rootDir": "src",
    "composite": true
}

hopes it works for you guys, good luck!

All 5 comments

The reason this came up, by the way, is that for our project which has a complicated build scenario, e.g. with different build rules for dev vs prod, we sometimes target commonjs and sometimes amd. I was sort of mystified why sometimes I got an error message, and sometimes I didn't. It turned out that when targeting amd, I didn't get an error message, but the generated module names were not what I had intended (because my rootDir was wrong).

My workaround for monorepo:

  1. set references in package1's tsconfig.json
{
  "compilerOptions": {
    "declarationDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"],
  "references": [
    {
      "path": "../package2"
    }
  ]
}

  1. set composite in package2's tsconfig.json
"compilerOptions": {
    "declarationDir": "dist",
    "rootDir": "src",
    "composite": true
}

hopes it works for you guys, good luck!

Just a little contribution to this issue, I had the same issue but with different configuration, my project folder was a symlink from another drive, compiling from the actual project folder did not show the error, but from the other drive did.

The fix by @repairearth above worked for me; I didn't even have to add the "references" part, just the composite: true flag (to package2's tsconfig.json -- see below).

(Old partial-fix I was using: https://stackoverflow.com/a/59050246/2441655)

My case was a bit peculiar, so the above might not work for everyone, but I thought I'd mention it.
==========
My case: Using "npm link" for libraries of mine, which I then imported source files from directly, with ts (through ts-loader) having a strange complaint about package1's source-files not being under the rootDir of package2, despite package2 not importing anything from package1!

I finally found the root of the problem in my project: I was using a single ts-loader rule/instance to load from _multiple paths containing tsconfig.json files_.

See here for details and the solution: https://stackoverflow.com/a/59050246/2441655

Was this page helpful?
0 / 5 - 0 ratings

Related issues

uber5001 picture uber5001  Â·  3Comments

bgrieder picture bgrieder  Â·  3Comments

weswigham picture weswigham  Â·  3Comments

MartynasZilinskas picture MartynasZilinskas  Â·  3Comments

zhuravlikjb picture zhuravlikjb  Â·  3Comments