Typescript: tsserver (vscode) does not recognize multiple tsconfig.json in the same directory

Created on 3 May 2016  ·  16Comments  ·  Source: microsoft/TypeScript

Example of file organization:

app/feature1/model.ts
             model.spec.ts
             controller.ts
             controller.spec.ts
             template.html
             documentation.md
    feature2/model.ts
             model.spec.ts
             controller.ts
             controller.spec.ts
             template.html
             documentation.md
    tsconfig.json      <-- list *.ts files + third-party *.d.ts (ex: angular.d.ts)
    tsconfig.spec.json <-- list *.spec.ts files + third-party *.d.ts (ex: jasmine.d.ts)

tsc works fine. However vscode does not properly highlight files listed in tsconfig.spec.json (like #5828).

Using TypeScript 1.8.10 and vscode 1.0

By Design

Most helpful comment

This is an incredibly annoying problem.

I understand the argument that tsc shouldn't be used as a build tool, and tsconfig.json shouldn't be used as build configuration. But it is because MS is using tsc as a linter that this issue is a problem for us.

Real-world example:

  • compiler options in /tsconfig.json
  • source code in /src/**/*.ts
  • tests in /src/**/*.spec.ts
  • /tsconfig.json obviously excludes *.spec.ts so they aren't compiled into /lib and distributed to npm.
  • something.spec.ts uses decorators (mocha-typescript) - VSCode gives many "Experimental support for decorators is a feature that is subject..."

We will not put our tests in a separate /tests folder because they are not visible. When specs are beside the files they're testing, it is easy to see when tests are missing or haven't been updated. So with the spec files in the same folder as the source code, how exactly would one go about telling tsc/VSCode that there are different requirements for spec files?

I have tried putting a spec-specific tsconfig.json in the /src/ folder and leaving the main tsconfig.json in the root. That didn't work.

I can see that this isn't necessarily a typescript issue - for me it's more of a VS Code configuration issue - I should be able to specify which tsconfig matches which files - but I think the request here is that it "just work" because the files themselves already have the matchers needed to decide which config to use. There would just need to be some way to register all the config files or some naming convention, etc.

I'm more in favor of a VSCode config file that would register my two tsconfig.json files and based on the include/exclude settings in the file choose the proper config to pass to tsc for the file I'm looking at.

I don't have the perfect solution, but I know that putting things like this at the top of all my spec files:

// - tests require packages from devDependencies
// - mocha has side-effects
// - chai has odd syntax
/* tslint:disable no-implicit-dependencies no-import-side-effect no-unused-expression function-name max-classes-per-file no-any */

shouldn't be necessary. And looking at this makes the problems panel in VS Code useless.

image

All 16 comments

This behaves as intended. there is only one special tsconfig.json. the other ones can be passed explicitly to tsc, but when automatic search is done, either in tsc or in tsserver, only tsconfig.json is looked up.

Ok, so with tsserver

  • you cannot have source code and tsconfig.json in separate directories (#5828)
  • you cannot have multiple tsconfig.*.json in the same directory (this issue)

then how can you organize code by features/components in a simple way? It is a valid use case.

TypeScript very first description line:

TypeScript is a language for application-scale JavaScript

then how can you organize code by features/components?

not sure i understand what you mean by this. if you have a tsconfig per feature/component it is going to work. what is not, is having multiple build configurations for the same feature/component in the IDE.

@mhegazy

not sure i understand what you mean by this

by features/components/modules:

app/feature1/model.ts
             model.spec.ts
             controller.ts
             controller.spec.ts
             template.html
             style.css
             feature.png
             README.md
    feature2/model.ts
             model.spec.ts
             controller.ts
             controller.spec.ts
             template.html
             style.css
             feature.png
             README.md

vs by type of files:

src/models/feature1_model.ts
           feature2_model.ts
    controllers/feature1_controller.ts
                feature2_controller.ts
    templates/feature1_template.html
              feature2_template.html

doc/feature1.md
    feature2.md

styles/feature1.css
       feature2.css

img/feature1.png
    feature2.png

test/feature1_model.spec.ts
     feature2_model.spec.ts
     feature1_controller.spec.ts
     feature2_controller.spec.ts

Link from my previous comment: https://www.google.fr/search?q=organize+code+by+feature
Examples of AngularJS articles:

Note: most articles don't mention where the tests should go because most people don't write tests and thus don't mention it.
Obviously you want your tests as close as possible to the code they test, not at the other side of your hard drive, same for your code documentation (you've recognized the 'by file type' organization here).
Writing tests and documentation is no fun, your code organization should not make it even harder else you can be sure your team won't never update the tests nor the documentation.

I still do not understand why you can not do this with one tsconfig.json per folder.

why you can not do this with one tsconfig.json per folder

Nobody wants to ship something bundled with the tests on a website, so you need 2 tsconfig.json :)

Also having 1 build for the app and 1 build for the tests helps: you can easily experiment/hack with the app code without having compile errors about the now outdated tests. (typical workflow: hack -> looks good? -> clean things up + write tests).

Sure you can have 3 tsconfig.json instead of 2:

  • one to please the IDE/tsserver
  • one to build the app code
  • one to build the tests

=> More things to maintain :/

Nobody wants to ship something bundled with the tests on a website, so you need 2 tsconfig.json :)

so why not two tsconfig.json files in two folders, i.e. src\tsconfig.json and test\tsconfig.json?

srctsconfig.json and testtsconfig.json

Does not solve the problem, see #5828 (my first attempt before TypeScript 1.8 came out with the tsc -project fullpath feature).

I think allowing a tsconfig.json to reference other tsconfig.json (TypeScript 2.1) will simplify things:

  • tsconfig.test.json => build the tests
  • tsconfig.app.json => build the app
  • tsconfig.json => pleases the IDE/tsserver, references tsconfig.test.json and tsconfig.app.json

You have 3 tsconfig.json files but the one for the IDE is just an empty shell that points to the others: easy to maintain.
It still feels awkward: go explain to somebody why you have 3 tsconfig.json files...

Another better (and complementary?) solution can be multiple "targets"/builds/projects inside 1 tsconfig.json file (see #1928):

{
  "compilerOptions": {
    "noImplicitAny": true,
    "removeComments": false,
    "sourceMap": true
  },
  "files": [
    "common/util.ts"
  ]
  "projects": {

    "app": {
      "compilerOptions": {
        "outFile": "app.js"
      },
      "files": [
        "feature1/model.ts",
        "feature1/controller.ts",
        "feature2/model.ts",
        "feature2/controller.ts"
      ]
    },

    "unittests": {
      "compilerOptions": {
        "outFile": "unittests.js"
      },
      "files": [
        "feature1/model.spec.ts",
        "feature1/controller.spec.ts",
        "feature2/model.spec.ts",
        "feature2/controller.spec.ts"
      ]
    },

    "e2etests": {
      "compilerOptions": {
        "outFile": "e2etests.js"
      },
      "files": [
        "feature1/e2e.spec.ts",
        "feature2/e2e.spec.ts"
      ]
    },

    "app-es3-amd": {
      "compilerOptions": {
        "target": "es3",
        "module": "amd",
        "outFile": "app-es3-amd.js"
      },
      "files": [
        "feature1/model.ts",
        "feature1/controller.ts",
        "feature2/model.ts",
        "feature2/controller.ts"
      ]
    }
  }
}
  • Only one tsconfig.json file \o/
  • IDE/tsserver always happy \o/
  • Easy to understand and scalable
  • Pass the target name to tsc otherwise all targets are compiled (default behavior)

This is not the intended use of tsconfig.json. it is not meant to be a build orchestration tool nor a solution file. a single tsconfig.json represents a single invocation to tsc.exe/tsc.js. and that is that. for more interesting build/configuration consider using other build tools e.g. MSBuild, grunt or gulp.

my recommendations for this scenario are:

  • use two tsconfig.json files, one in sources and one in tests.
  • use a build tool to ensure building the tests will build the sources, e.g. grunt/gulp
  • in your editor, once you open a file from the test directory and a file from the source directory, two projects will be loaded in memory, with https://github.com/Microsoft/TypeScript/pull/7353, you get the global operations like find all references, and rename working on both projects. and no need for an uber project that unify them.

consider using other build tools e.g. MSBuild, grunt or gulp [...] use a build tool to ensure building the tests will build the sources

Obviously, how can you do without? sass/less, minification, launch a server, move files around, call tsc -p...

use two tsconfig.json files, one in sources and one in tests.

Does not please the IDE, see #5828. You can check for yourself: https://github.com/tkrotoff/vscode-tsconfig.conf-issue

Anyway...

use two tsconfig.json files, one in sources and one in tests.

This is the one I'd recommend as well. The test file should be in a folder _above_ the src. TSServer will work as it is

Project pitch

I'll work on improving the _set project_ in alm to take more than files by tsconfig.json name at some point so it shows more than just tsconfig.json exact matches https://github.com/alm-tools/alm/blob/master/docs/features/omni-search.md#project-search
:rose:

Does not please the IDE, see #5828. You can check for yourself: https://github.com/tkrotoff/vscode-tsconfig.conf-issue

I see now, so you want the tests to be next to your app, but not in the production release. so why not have two tsconfig.json, at the root, one tsconfig.json (includes all files, tests and sources), and another one tsconfig.production.json that excludes the test files?

you want the tests to be next to your app, but not in the production release

YES! :-)

one tsconfig.json (includes all files, tests and sources), and another one tsconfig.production.json that excludes the test files?

Exactly what I do now

no need for an uber project that unify them

Multiple "targets"/builds/projects inside 1 tsconfig.json has already been proposed: #1928.
This + allowing tsconfig.json to reference other tsconfig.json files cleanly solved all use cases.

Multiple "targets"/builds/projects inside 1 tsconfig.json has already been proposed: #1928.

I do not think we will be parametrizing tsconfig.json any time soon, for the same reason i listed earlier. tsconfig.json is just an easy way to call tsc.exe with a punch of parameters. if you want to do something fancier, you should use a build system/ solution file (whatever that would be in your editor).

This + allowing tsconfig.json to reference other tsconfig.json files cleanly solved all use cases.

you can see my argument against using tsconfig.json as a build manager in https://github.com/Microsoft/TypeScript/issues/3469#issuecomment-111254952.

extends works for maintaining multiple build files, but there's still an editor issue. Jetbrains (IntelliJ / WebStorm) recently implemented IDE support for selecting the appropriate tsconfig file by exclude / include / files: see the blog post and bug

A rough description, they have configurable file name patterns for config files, expanding the lookup for tsconfig.json (say, to tsconfig.*.json - it seems they reverted the default pattern list since the post to just tsconfig.json again), and for each edited file select the first found config where the paths match.

Therefore, you could have, for example:

  • tsconfig-base.json with common settings (not directly used)
  • tsconfig.web.json with lib: ['dom'], types: [] and include: ['src'], exclude: ['*.test.ts', '**/__mocks__']
  • tsconfig.test.json with types: ['node', 'jest'] and include: ['src/**/*.test.ts', 'src/**/__mocks__']
  • tsconfig.scripts.json with types: ['node'] and exclude: ['node_modules', 'src']

And have the editor know that, e.g. describe() is invalid in scripts/start.ts, and window.location is invalid in src/App.test.ts

This is an incredibly annoying problem.

I understand the argument that tsc shouldn't be used as a build tool, and tsconfig.json shouldn't be used as build configuration. But it is because MS is using tsc as a linter that this issue is a problem for us.

Real-world example:

  • compiler options in /tsconfig.json
  • source code in /src/**/*.ts
  • tests in /src/**/*.spec.ts
  • /tsconfig.json obviously excludes *.spec.ts so they aren't compiled into /lib and distributed to npm.
  • something.spec.ts uses decorators (mocha-typescript) - VSCode gives many "Experimental support for decorators is a feature that is subject..."

We will not put our tests in a separate /tests folder because they are not visible. When specs are beside the files they're testing, it is easy to see when tests are missing or haven't been updated. So with the spec files in the same folder as the source code, how exactly would one go about telling tsc/VSCode that there are different requirements for spec files?

I have tried putting a spec-specific tsconfig.json in the /src/ folder and leaving the main tsconfig.json in the root. That didn't work.

I can see that this isn't necessarily a typescript issue - for me it's more of a VS Code configuration issue - I should be able to specify which tsconfig matches which files - but I think the request here is that it "just work" because the files themselves already have the matchers needed to decide which config to use. There would just need to be some way to register all the config files or some naming convention, etc.

I'm more in favor of a VSCode config file that would register my two tsconfig.json files and based on the include/exclude settings in the file choose the proper config to pass to tsc for the file I'm looking at.

I don't have the perfect solution, but I know that putting things like this at the top of all my spec files:

// - tests require packages from devDependencies
// - mocha has side-effects
// - chai has odd syntax
/* tslint:disable no-implicit-dependencies no-import-side-effect no-unused-expression function-name max-classes-per-file no-any */

shouldn't be necessary. And looking at this makes the problems panel in VS Code useless.

image

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kyasbal-1994 picture kyasbal-1994  ·  3Comments

wmaurer picture wmaurer  ·  3Comments

fwanicka picture fwanicka  ·  3Comments

CyrusNajmabadi picture CyrusNajmabadi  ·  3Comments

bgrieder picture bgrieder  ·  3Comments