Typescript: Support for multiple tsconfig.json per project

Created on 26 Jun 2015  Β·  37Comments  Β·  Source: microsoft/TypeScript

Hi! Is it possible to use multiple tsconfig.json per project, that is some kind of project-wide tsconfig.json located in root directory and additional tsconfig.json files located in sub-directories which may override/tune some options for that dirs? Like .gitignore does.

It would be very usefull when, for instance, developing external module under node-environment. Such modules usually splited into multiple files (internal modules), but would be compiled into one big file during compilation stage.

Question

Most helpful comment

I finally get the solution.

my application structure :
-- app/
-- app/client/ (my client side source code)
-- app/server/ (my server side source code)
-- app/build/ (where I generate the js)
-- app/node-modules/
-- app/package.json
-- app/tsconfig.server.json
-- app/tsconfig.client.json

Content of tsconfig.server.json :
{ "compilerOptions": { ..., "outDir": _"build/server"_ },
"exclude": [ "node_modules", "client"] }

Content of tsconfig.client.json :
{ "compilerOptions": { ..., "outDir": "build/client"},
"exclude": [ "node_modules", "server"] }


Then when I want to compile server source code I use this command from app root directory :

tsc --p tsconfig.server.json


And to compile client source code, also from root app directory :

tsc --p tsconfig.client.json


In order to run both client & server compilation, I added a command in package.json :

"scripts": { ..., "tsc": "tsc --p tsconfig.server.json && tsc --p tsconfig.client.json", ... }

Then to compile both server and client I just run this from my root app directory :

npm run tsc

Hope this comment could help you :-)

All 37 comments

Hey @lazutkin. Currently that's not supported, though I just want to link this issue to #2869 because it is somewhat related.

The compiler picks the closest tsconfig.json to the folder you are building if you are running tsc with no arguments in a folder. so if you have an inner directory with a tsconfig.json it will be picked up before the one in the outer directory.

I do not think we will support integration/overriding configuration from multiple tsconfig.json.

Multiple tsconfig files are indispensable for large enterprise apps.
Suggestion: Everytime tsc find a new tsconfig file in a subdirectory, tsc stopps here and create a new tsc process with its own tsconfig file.

@Eisenspalter this sounds like a build driver job something like grunt, gulp or msbuild.

@mhegazy I agree with @Eisenspalter because we both talk not about building process but about development process including sources writing, testing and other activities we need to complete before build. On all this intermediate steps we need to have support from typescript including intellisense, typechecking etc. Moreover as I said before, for different parts of project we would like to apply different source organizing techniques (external-internal modules, single output file, etc) and here we need some options to be overriden by separate tsconfig.

@mhegazy Why closed? Please reopen.

you can have multiple tsconfig today, each pointing to overlapping set of files. so one at srctsconfig.json, one in teststsconfig.json, etc.. the compiler/tools will locate the file by walking up the directory tree to find the closest one. so you can have a third file at the root to catch all.

This all works today, in the compiler and the different IDEs. the original issue was about allowing a file to inherit from another. i do not think there is enough value there warrants the complexity.

For the second issue:

Everytime tsc find a new tsconfig file in a subdirectory, tsc stopps here and create a new tsc process with its own tsconfig file.

As i mentioned earlier, a tsconfig.json represents a single invocation to tsc.js/tsc.exe if you want to do multiple invocations you should use a build driver.

@lazutkin and @Eisenspalter does this answer the questions

@mhegazy
Couldn't get multiple tsconfig.json to work. At least with TypeScript 1.7.3, only one tsconfig.json is read and that is expected to be in the root directory (or parent) of the project.

@Ziink my comment above was not about multiple tsconfigs in the same project. it was about multiple projects/directories, each with a different tsconfig. this how the ts project is layed out, see https://github.com/Microsoft/TypeScript/tree/master/src, each folder under src, has a different tsconfig.json

I have project that is written in TypeScript and I want to target both:

  1. browser (let's say files in /browser) with ES5/AMD and
  2. nodejs (files in server) with CommonJS and generators (and async/await in TS).

There are some shared files let's say in (/common) folder and there are imports from common to browser and server.
How can I achieve such config preserving IDE support, all the errors etc? I'm not sure if the discussion answered my doubts.

@bartq With TS 1.8, I would create two tsconfig files, one for browser, and one for server, and add ///references in your files in both sub-projects to the common ones. give it a try and let us know if this addresses the scenario or there are still missing pieces.

actually I'm using those two tsconfig.json files, WebStorm discovers them and runs the compilation automatically. To be precise, backend code imports some classess from frontend code (instead using common concept), but it all works fine.

I finally get the solution.

my application structure :
-- app/
-- app/client/ (my client side source code)
-- app/server/ (my server side source code)
-- app/build/ (where I generate the js)
-- app/node-modules/
-- app/package.json
-- app/tsconfig.server.json
-- app/tsconfig.client.json

Content of tsconfig.server.json :
{ "compilerOptions": { ..., "outDir": _"build/server"_ },
"exclude": [ "node_modules", "client"] }

Content of tsconfig.client.json :
{ "compilerOptions": { ..., "outDir": "build/client"},
"exclude": [ "node_modules", "server"] }


Then when I want to compile server source code I use this command from app root directory :

tsc --p tsconfig.server.json


And to compile client source code, also from root app directory :

tsc --p tsconfig.client.json


In order to run both client & server compilation, I added a command in package.json :

"scripts": { ..., "tsc": "tsc --p tsconfig.server.json && tsc --p tsconfig.client.json", ... }

Then to compile both server and client I just run this from my root app directory :

npm run tsc

Hope this comment could help you :-)

I don't understand what the problem is here. Why can't we support configs with different file names? It's a pain having to create subFolders JUST to have a different tsconfig file in.

You can. --p argument ca be a file name.

The different file names won't work with the Visual Studio typescript compiler extension (not talking about CLI) out of the box though. Only way to do that is to put each tsconfig.json in a dummy directory, and have it link back to the typescripts you want with the files option.

for example

--src/target/search/tsconfig.json
--src/target/core/tsconfig.json
--src/target/users/tsconfig.json

target/search/tsconfig.json would look something like:

{
  "compilerOptions": {
    "outFile": "../../../build/app/search.js"
  },
  "files": [
    "../../src/common",
    "../../src/search"
  ]
}

And the others would be similar.

This would produce 3 javascript files, each with its own configuration of files, bundled into one.

Of course, your could use a different solution of bundling/minimizing/packaging than the Typescript compiler itself.

It's just that the Typescript compiler does a really good job with optimization - that's one of the biggest draws to using Typescript.

So, it would be nice if a single tsconfig.json could support multiple configurations by just changing it to be an array of tsconfigs:

[
  {
    "compilerOptions": {
      "outFile": "../../build/search.js"
    },
    "files": [
      "src/common",
      "src/search"
    ],
    "compileOnSave": true
  },
  {
    "compilerOptions": {
      "outFile": "../../build/core.js"
    }
    "files": [
      "src/common",
      "src/core"
    ],
    "compileOnSave": true
  }
]

This is what it sounds like is being requested in the later comments of this issue, although I agree, the original issue was more about inheritance and overriding configs.

@mhegazy @bartq I cannot make it work with tsc command.
I have a following directory structure

-- app/
-- app/server  -- here I want es6/commonjs
-- app/server/tsconfig.json
-- app/client    -- here I want es6/es6 
-- app/client/tsconfig.json
-- app/tsconfig.json

Yet, when I run tsc only config from app/tsconfig.json is used, rest is ignored. I'm trying to make it work in VSCode :/

@tomitrescak I'm using WebStorm and it's intelligent enough to find closest tsconfig.json and use it when you edit a file. Probably there isn't any cmd tool that supports watching multiple tsconfig.json's. You can roll it out using for example FB watchman.

Yeah, I'd love to have something like this in VS Code. I'm running the compilation in the terminal. Works as well. VS Code correctly identifies errors anyways.

Multiple configs would be great. I am working on a React-Native project and basically I have two builds that I want to do:

  1. the scripts of my React-Native project
  2. the scripts used in the HTML for the React-Native WebViews (charts).

Configuration inheritance has been added in TS 2.1, and should be available in typescript@next today. see https://github.com/Microsoft/TypeScript/issues/9876 for more details. With that you can have a "master" tsconfig.json and override ones that inherit configurations from it. you still need to create multiple tsconfig.json files, but your IDE should pick these up.

I have a following directory structure:

β”œβ”€β”€ examples
β”‚   β”œβ”€β”€ files...
β”‚   └── tsconfig.json
β”œβ”€β”€ src
β”‚   └──files...
└── tsconfig.json

Root tsconfig.json have:

{
  "compilerOptions": {
    "target": "es2015",
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "dist",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "declaration": true,
    "allowJs": false
  },
  "include": [
    "./src"
  ],
  "compileOnSave": false,
  "buildOnSave": false,
  "atom": { "rewriteTsconfig": false }
}

examples/tsconfig.json have same value except:

  "include": [
    "./hello-world"
  ],

When I do:

cd examples
tsc

It compiles:

β”œβ”€β”€ examples
β”‚   β”œβ”€β”€ dist
β”‚   β”‚   β”œβ”€β”€ examples
β”‚   β”‚   └── src
β”‚   β”œβ”€β”€ files...
β”‚   └── tsconfig.json
β”œβ”€β”€ src
β”‚   └──  files...
└── tsconfig.json

(dist wrong incluedes external folder src and compiles as from within the root folder)

Not help this (in examples/tsconfig.json):

  "exclude": [
    "../src"
  ],

What am I doing wrong?

I found problem. If in my examples/hello-world/any-file*.ts this import:

import { SomeClass } from '../../src';

It's produce described above problem. Following import works as expected:

import { SomeClass } from '../../';

But why typescript's directive include not works as expected?

I can't get it working
It insists on "Warning:Cannot find parent tsconfig.json" although I have tsconfig.json in the same folder, don't know what to do with this

@zhukovka please log a new issue with a standalone repro we can run locally

@RyanCavanaugh Oh. thanks, I've figured it out
the problem reproduces only if I have one file open from a test folder (that didn't include tsconfig.json) and the second file opened in an 'src' folder (that included tsconfig.json)
and the file from the test folder imports the one from the src folder. In this case, the file from the src folder doesn't see his 'parent tsconfig.json'

@RyanCavanaugh, support for compiling with several different tsconfig.json's seems to continue be something developers would like to have. For my cases, its generally about changing where the generated output files go. It seems like if the code generations could be controlled by something like the existing paths mapping allowing me to layout my generated code differently from the sources, perhaps the need for multiple projects would be lessened.

My use case is that I have a large legacy codebase which can't withstand the stricter type checking rules, and I want to use it in a new codebase which _does_ have strict checks enabled, and I can't compile the legacy code to a library because it has a million cases where it doesn't import all the types required to name the types for its exports (#9944). So I want to just add the legacy codebase to the new codebase, but compiled according to laxer rules. This can't be 2 different compilation steps; just when the compiler is working on source files under a certain directory it should be using the laxer rules.

For me the use case is having part of the repo that is run using node and needs to compile down to commonjs modules, while the other part needs to be compiled to ES6 modules in order to enable treeshaking in ES6. The experience isn't great, there is a lot of hacking around with TS_NODE_PROJECT environment variables, in my case. It definitely seems like something that could confuse the hell out of the next person maintaining it when I eventually change projects.

I would still love to see this solved. It would be a huge win for larger projects that require different tsconfig.json files per module within a project.

@Robinfr what does the extends feature not solve for you?

It did. I found out about that after this post. One thing to note however is that it didn't work without setting the include to the files which k usually don't have to since it goes through webpack.

Op 15 sep. 2017 9:24 a.m. schreef Kitson Kelly notifications@github.com:

@Robinfrhttps://github.com/robinfr what does the extends featurehttps://www.typescriptlang.org/docs/handbook/tsconfig-json.html#configuration-inheritance-with-extends not solve for you?

β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/Microsoft/TypeScript/issues/3645#issuecomment-329703706, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AD90FLZKcHMJeFU0osJroT_yawlC1oTIks5siiZFgaJpZM4FMc8w.

@kitsonk extending works well, although if I am not doing something wrong, I have to repeat certain settings (excluding my build and node_modules folders) in both configs. for me the biggest pain point is making sure all my tooling knows which configuration file is the correct one too use (typically by means of something like a TS_NODE_PROJECT environment variable. The other is when opening a project with two tsconfigs in VS.code. There is no way (that I know of) to tell VS which project file to use and that means for some files errors will not get correctly underlined, because of different settings for those files in the corresponding tsconfig (say, something like tsconfig.build.json).

@voy may I ask why you have a different tsconfig for building? As far as I've understood, VSCode uses the nearest tsconfig file (tsconfig.json) to the file you're editing. The only issue I've had so far is that you need to have a tsconfig file at the root before VSCode seems to start using the configs at all...

@Robinfr sure. in the same repository I have files that get processed using webpack & babel and use ES6 modules to enable tree-shaking. other files are part of the build process and get executed using node, which is why imports need to get transpiled to requires. not sure how I could work around that.

@voy wouldn't you just have those files in a separate folder however? E.g. 1 folder for all the Babel & webpack files, and 1 for the node files. Then you can just have a tsconfig.json for each of those folders. Wouldn't that work for you?

@Robinfr that would be ideal, but I think it isn't always possible in the real world. for example, we want all our configuration files to be typescript as well, compiled and linted according to the very same rules as all of TypeScript codebase and some files have to be in the root of the project. you could symlink, but that sometimes brings out other problems. that's why I feel something more flexible would be a benefit.

Was this page helpful?
0 / 5 - 0 ratings