Create-react-app: Add a way to specify an alternate tsconfig for production builds

Created on 11 Dec 2018  路  12Comments  路  Source: facebook/create-react-app

Is this a bug report?

No. This is a feature request. Our team is now using CRA with TS and it is great! One thing we can't seem to find is any information on is having different TS compiler settings when doing a production build. Simply adding a tsconfig.prod.json appears to have no effect. I can't seem to find a documented way to add this and it would be super useful!

Did you try recovering your dependencies?

N/A

Which terms did you search for in User Guide?

TypeScript https://reactjs.org/docs/static-type-checking.html#typescript

Environment

Environment Info:

  System:
    OS: macOS 10.14.1
    CPU: x64 Intel(R) Core(TM) i7-7920HQ CPU @ 3.10GHz
  Binaries:
    Node: 10.14.0 - /usr/local/bin/node
    Yarn: 1.12.3 - /usr/local/bin/yarn
    npm: 6.4.1 - ~/Projects/cirrus-admin-webapp/node_modules/.bin/npm
  Browsers:
    Chrome: 70.0.3538.110
    Firefox: 63.0.3
    Safari: 12.0.1
  npmPackages:
    @types/react: 16.7.7 => 16.7.7
    @types/react-dom: 16.0.11 => 16.0.11
    react: 16.6.3 => 16.6.3
    react-dom: 16.6.3 => 16.6.3
    react-scripts: 2.1.1 => 2.1.1
  npmGlobalPackages:
    create-react-app: Not Found

Steps to Reproduce

  1. Add TS to your project as outlined in the docs.
  2. Attempt to add a tsconfig.prod.json with different settings than tsconfig.json:
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "noUnusedLocals": true
  }
}
  1. Run yarn build or whatever you have configured to do a production build with react-scripts
  2. Notice the settings aren't applied.

Expected Behavior

It would honor the tsconfig.prod.json

Actual Behavior

It honors the original tsconfig.json.

Reproducible Demo

N/A. I can add one later if people have any issues reproducing.

proposal

Most helpful comment

@alexkuz
Add a tsconfig.production.json:

{
    "extends": "./tsconfig.json",  
    "compilerOptions": {
      "noUnusedLocals": true,
      "skipLibCheck": true
    },
  "exclude": ["**/*.test.ts", "*.test.tsx"]
}

and change your build script in package.json:

...
  "scripts": {
    "start": "react-scripts start",
    "build": "tsc -p tsconfig.production.json && react-scripts build",
    "deploy": "npm run build && firebase deploy",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
...

All 12 comments

Sorry, this isn't possible and we have no plans to add support for this.
It would be better to accomplish this via linting, e.g. TSLint.

@Timer I agree that unused variables is linter's job. But currently TSLint considers this rule deprecated, since it's quite hard for them to maintain it and tsc already has this feature (https://github.com/palantir/tslint/issues/4100).

I don't think it's "impossible" to support this (create-react-app-typescript did that somehow), but I understand if it goes against zero-config policy. Still it would be nice to find some appropriate solution.

Ultimately, it comes down to being a foot-gun IMO. Users may accidentally configure their tsconfig.json differently between development and production (besides "linting" rules) and be really confused when their bundle is broken in production.

If this is necessary, I'd suggest modifying tsconfig.json on-the-fly before your CI tests run.

Since I only need that unused variable checking, I ended up just running tsc -p tsconfig.prod.json before an actual build with "skipLibCheck": true for better performance.

Since I only need that unused variable checking, I ended up just running tsc -p tsconfig.prod.json before an actual build with "skipLibCheck": true for better performance.

Would you @alexkuz mind elaborating a bit more how you did this?

@alexkuz
Add a tsconfig.production.json:

{
    "extends": "./tsconfig.json",  
    "compilerOptions": {
      "noUnusedLocals": true,
      "skipLibCheck": true
    },
  "exclude": ["**/*.test.ts", "*.test.tsx"]
}

and change your build script in package.json:

...
  "scripts": {
    "start": "react-scripts start",
    "build": "tsc -p tsconfig.production.json && react-scripts build",
    "deploy": "npm run build && firebase deploy",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
...

@Timer Why would this not be possible? To me it looks like it would simply involve changing:

appTsConfig: resolveApp('tsconfig.json'),

in packages/react-scripts/config/paths.js to something "env-based" using the Advanced Configuration "way".

I 100% need this feature.

We need to use "jsx": "react" in our production builds, but react-scripts start is overwriting the line to "jsx": "preserve". 馃槮馃槙

This behaviour is _breaking_ our production builds and could be avoided by allowing me to specify a different tsconfig.json when doing quick local development.

Update: I've worked around this by creating three files:

tsconfig.base.json
tsconfig.development.json        // inherits from base config
tsconfig.production.json         // inherits from base config

I added some extra steps to the build to copy the correct config to tsconfig.json before building. Now I can use multiple typescript configurations for different builds.

For example, here is what I added to package.json to copy the files:

  "scripts": {
    // ...
    "start": "cp -f ./typescript/tsconfig.development.json ./tsconfig.json && npm install && react-scripts start",
    "build": "cp -f ./typescript/tsconfig.production.json ./tsconfig.json && npm install && webpack --config webpack/webpack.config.js --mode development",
    // ...
  },

I can "work around" nearly everything, because JS got' eval() but this is not the point. :) @byxor We used nearly the same approach; however such a standard feature should not be worked around, but supported natively.

Support for multiple tsconfigs is a fundamental requirement for any build tool that claims to support TypeScript. Not having it is the real footgun.

The reason is that, in order for intellisense in editors like VSCode to work, your root tsconfig.json must include every source file and dependency in your app. I.e. all your app's source files, all the .test.ts files, the .stories.tsx files, etc. And the types/libs must reference things like Storybook, node, Jest, etc. as well.

However, when building your app, you obviously don't want to include everything. In fact, it is very dangerous to do so. If one of your app's components accidentally imported something from Storybook or node, you wouldn't get an error and build/type-check time. Therefore, you need to create a separate tsconfig.app.json that extends from the root tsconfig.json but which narrows the list of included files and allowed dependencies. You create a similar tsconfig file for your tests, Storybook, Cypress, etc.

This is how other tools like Angular CLI work, and it is how it is supposed to work. It's the whole reason TypeScript supports multiple tsconfig files and extending from each other.

FWIW adding tsc -p tsconfig.production.json before react-scripts build does work, but also adds time to the build process. Best we can do for now, IMO.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adrice727 picture adrice727  路  3Comments

oltsa picture oltsa  路  3Comments

xgqfrms-GitHub picture xgqfrms-GitHub  路  3Comments

alleroux picture alleroux  路  3Comments

ap13p picture ap13p  路  3Comments