Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for project references #10695

Open
kentcdodds opened this issue Mar 16, 2021 · 6 comments
Open

Support for project references #10695

kentcdodds opened this issue Mar 16, 2021 · 6 comments

Comments

@kentcdodds
Copy link
Contributor

Is your proposal related to a problem?

I'm using create-react-app for my React workshops. Each project has an exercise file (the unfinished code) and a final file (the finished code). I'm rewriting them all to TypeScript. I don't want to enable strict mode for the exercise files because it can be difficult for people new to TypeScript. However I do want the final version of the exercise to be type checked with strict mode (for my own sake).

Having different configs for different files in a project can be accomplished using project references configuration. Here's what I've done to make this "work": kentcdodds/react-fundamentals@84eb9ed

tsconfig.json

{
  "files": [],
  "references": [
    {"path": "config/tsconfig.exercise.json"},
    {"path": "config/tsconfig.final.json"}
  ]
}

config/tsconfig.exercise.json

{
  "extends": "./tsconfig.shared.json",
  "include": ["../src/exercise/"],
  "compilerOptions": {
    "strict": false
  }
}

config/tsconfig.final.json

{
  "extends": "./tsconfig.shared.json",
  "exclude": ["../src/exercise/"],
  "include": ["../src"],
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true
  }
}

config/tsconfig.shared.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "noFallthroughCasesInSwitch": true
  }
}

Running tsc -b will typecheck all the files with the expected configuration.

However, as soon as I run react-scripts start, my tsconfig.json gets changed:

{
  "files": [],
  "references": [
    {
      "path": "config/tsconfig.exercise.json"
    },
    {
      "path": "config/tsconfig.final.json"
    }
  ],
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

With those changes, when I try to run tsc (or tsc -b), I get several errors, for example:

tsconfig.json:4:5 - error TS6306: Referenced project '/Users/kentcdodds/code/epic-react/react-fundamentals/config/tsconfig.exercise.json' must have setting "composite": true.

4     {
      ~
5       "path": "config/tsconfig.exercise.json"
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6     },
  ~~~~~

tsconfig.json:7:5 - error TS6310: Referenced project '/Users/kentcdodds/code/epic-react/react-fundamentals/config/tsconfig.final.json' may not disable emit.

By setting "noEmit": false and "composite": true to the config/tsconfig.shared.json, I get a little further, but can't get rid of this error:

error TS6305: Output file '/Users/kentcdodds/code/epic-react/react-fundamentals/src/final/07.extra-3.d.ts' has not been built from source file '/Users/kentcdodds/code/epic-react/react-fundamentals/src/final/07.extra-3.tsx'.
  The file is in the program because:
    Matched by include pattern 'src' in '/Users/kentcdodds/code/epic-react/react-fundamentals/tsconfig.json'

  tsconfig.json:33:5
    33     "src"
           ~~~~~
    File is matched by include pattern specified here.

I've tried all combinations of options I can think of and nothing I can think of will make TypeScript happy + accomplish my goal of having a different config for different files in my create-react-app project.

Describe the solution you'd like

I would like support for references directly. I did notice ts-loader's page on references.

Short of that, I would be happy with an environment variable (similar to SKIP_PREFLIGHT_CHECK) which opts-out of updating the tsconfig.json and just trusts that the config works as-is.

Describe alternatives you've considered

I've thought about switching off of create-react-app or using one of the off-shoot projects that are flexible, but I'd really prefer to not do that.

Additional context

I think I've said everything that needs to be said 😅

@kentcdodds
Copy link
Contributor Author

Did a little investigation and noticed that create-react-app actually uses https://github.com/TypeStrong/fork-ts-checker-webpack-plugin for TypeScript checking. That actually does support references, but CRA has an older version which I don't think supports references.

Unfortunately when I tried to upgrade to the latest version I got an error (without any stack trace): Cannot read property 'tap' of undefined. I'm guessing this is because fork-ts-checker-webpack-plugin uses APIs in the v5 of webpack, but CRA is using webpack v4.

Upgrading to v5 would probably be pretty involved, so I stopped investigating there.

For the time being, I've just decided to use patch-package. My patch simply does an early exit in verifyTypeScriptSetup:

diff --git a/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
index 949f34a..0b3b54e 100644
--- a/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
+++ b/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
@@ -58,6 +58,7 @@ function verifyNoTypeScript() {
 }
 
 function verifyTypeScriptSetup() {
+  return
   let firstTimeSetup = false;
 
   if (!fs.existsSync(paths.appTsConfig)) {

It "works" in that CRA doesn't update my tsconfig anymore, but I don't get any output in the terminal or in the error overlay when there's a TS error. This actually works out better for my use case, so this workaround works for me.

@cmcnicholas
Copy link

Also interested in this, we have a large project that I would like to "drop in" a react native app alongside other projects and leverage all the code we have. This issue references another with other investigations #6799

@ArnieGA
Copy link

ArnieGA commented Jul 4, 2022

Yes, it seems pretty awkward that at this point in time CRA still hasn't solved this issue.

Development
├── Common Framework
│   └── tsconfig.json
└── MyApp
    ├── NodeProject
    │   └── tsconfig.json -> references: [ { path: "../../Common Framework/tsconfig.json" } ]
    ├── CRA Project
    │   └── tsconfig.json -> references: [ { path: "../../Common Framework/tsconfig.json" } ]
    └── Electron Project
        └── tsconfig.json -> references: [ { path: "../../Common Framework/tsconfig.json" } ]

In the CRA Project, everything works well in the editor (VS Code) but the project won't start.

@adameichelkraut
Copy link

+1 mono repos with Typescript would really benefit here

@bengouss
Copy link

+1, been hoping for that feature for years now 🙏

@danbachar
Copy link

+1 can't believe this issue is already +3 years old

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants