79

I'm currently using create-react-app to bootstrap one of my projects. Basically, I'm trying to set up paths in tsconfig.json by adding these to the default tsconfig.json generated by create-react-app:

"baseUrl": "./src",
"paths": {
  "interfaces/*": [
    "common/interfaces/*",
  ],
  "components/*": [
    "common/components/*",
  ],
},

However, every time I run yarn start which basically runs react-scripts start, it deletes my changes and generates the default configurations again.

How can I tell create-react-app to use my custom configs?

CodeIntern
  • 1,370
  • 2
  • 11
  • 15
  • From the docs, > You are not required to make a tsconfig.json file, one will be made for you. You are allowed to edit the generated TypeScript configuration. – Agney Dec 15 '18 at 16:36
  • 19
    Unfortunately, if you edit the file, it gets overwritten by yarn start, throwing away any changes. – Glenn Jan 02 '19 at 21:38
  • 3
    https://github.com/facebook/create-react-app/issues/5118#issuecomment-464025389 – kenberkeley Jul 10 '20 at 22:34
  • As @Glenn said, the tsconfig files resets. Even though when used 'extends' in tsconfig.json file, intellisence issue got resolved, but compilation failed. So I tried, https://www.thetopsites.net/article/58558041.shtml steps and found working – MishkuMoss Oct 13 '20 at 07:43

9 Answers9

44

I was able to do this by using advice from this issue.

Put the configuration options react scripts likes to remove in a separate file (e.g. paths.json) and reference it from tsconfig.json via the extends directive.

paths.json:

{
  "compilerOptions": {
  "baseUrl": "./src",
  "paths": {
    "interfaces/*": [ "common/interfaces/*"],
    "components/*": [ "common/components/*"],
    }
  }
}

tsconfig.json

{
  "extends": "./paths.json"
   ...rest of tsconfig.json
}
Glenn
  • 1,996
  • 2
  • 24
  • 32
  • 15
    It seems as though this no longer works with newer versions of react-scripts – TranquilMarmot Mar 16 '20 at 03:46
  • 39
    Why the f### would they do that? It's do damn annoying. @TranquilMarmot did you find a solution? – glemiere Mar 24 '20 at 21:37
  • did someone find an alternative ? – TheChix Apr 17 '20 at 23:09
  • 12
    Looks like the only option is to downgrade or eject. The contempt the CRA maintainers show for the community is very frustrating – 3stacks May 09 '20 at 06:15
  • 3
    I just did eject because of this. Anyone has a PR out or should I start to dig into the code to find where to change it? –  Jul 03 '20 at 03:08
  • Better not use CRA, it's terrible for real projects. – AlexG Feb 19 '21 at 12:36
  • 2
    It looks like it still works, but complains that `compilerOptions.paths must not be set (aliased imports are not supported)` anyway. – Coruscate5 Mar 26 '21 at 13:18
  • 1
    For those still looking for a solution, the above works just fine if you replace react-scripts with craco: https://tailwindcss.com/docs/guides/create-react-app (Ignore all the tailwind stuff; the craco setup is the simplest bare-bones example that'll get the above working). – sunny-mittal Jul 18 '21 at 18:55
  • I'm on the one of the latest versions of react-scripts (4.03) and this does not work – Clifford Fajardo Oct 23 '21 at 01:32
25

Create React App does not currently support baseUrl. However there is a workaround...to setup baseUrl for both webpack and the IDE you have to do the following:

  1. Create a .env file with the following code:
NODE_PATH=./
  1. Create a tsconfig.paths.json file with the following code inside:
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "src/*": ["*"]
    }
  }
}
  1. Add the following line to tsconfig.json
{
  "extends": "./tsconfig.paths.json",
  ...
}
Microcipcip
  • 655
  • 9
  • 21
7

You can't and I am unsure when you will be able to. I have been trying to use baseUrl and paths so I can avoid relative imports but as you can see they are intentionally removing certain values. The "(yet)" is encouraging but (sigh) who knows when they will officially be supporting it. I recommend subscribing to this github issue to be alerted if/when this changes.

The following changes are being made to your tsconfig.json file:
      - compilerOptions.baseUrl must not be set (absolute imports are not supported (yet))
      - compilerOptions.paths must not be set (aliased imports are not supported)
GentryRiggen
  • 788
  • 10
  • 10
3

If you are using react-scripts 4.0.0 like me then all you need to do is remove the line (around line 160 on my end):

paths: { value: undefined, reason: 'aliased imports are not supported' }

from the file node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js

I was able to straight up add my baseUrl and paths config to my tsconfig.json file like so:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@domain/*": ["../src/domain/*"],
    },
  }
}

and finally compile and move on with my life.

Per usual, YMMV. Please test your stuff. This is obviously a hack but it worked for me so I'm posting here in case it helps someone.

Here's a patch if you feel like sharing with your team:

diff --git a/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
index 00139ee..5ccf099 100644
--- a/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
+++ b/node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js
@@ -156,7 +156,8 @@ function verifyTypeScriptSetup() {
           : 'react',
       reason: 'to support the new JSX transform in React 17',
     },
-    paths: { value: undefined, reason: 'aliased imports are not supported' },
+    // Removed this line so I can add paths to my tsconfig file
+    // paths: { value: undefined, reason: 'aliased imports are not supported' },
   };

Edit

Per @Bartekus thoughtful suggestion in the comments thread I'm adding information on the package I use when I need to add (possibly) temporary changes like these to an npm package: patch-package

The package essentially provides a way to make changes to a package in a cleaner way. Especially when you consider collaboration it becomes very cumbersome to directly change an npm file and move on. The next time you update that package or even when you start developing in a new machine and run npm install your changes will be lost. Also, if you have teammates working on the same project they would never inherit the changes.

In essence you go through the following steps to patch a package:

# fix a bug in one of your dependencies
vim node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js

# run patch-package to create a .patch file
npx patch-package react-scripts

# commit the patch file to share the fix with your team
git add patches/react-scripts+4.0.0.patch
git commit -m "Enable aliased imports in react-scripts"

Next time someone checks out the project and installs it, the patch will be applied automatically due to a post-install script you add during set up:

 "scripts": {
+  "postinstall": "patch-package"
 }

See up to date instructions in the package's documentation

avlnx
  • 676
  • 1
  • 6
  • 19
  • 3
    man that is a nasty temporary hack. almost better to eject? – dcsan Nov 24 '20 at 22:15
  • Why do you think it’s nasty? IMO the Facebook people might have added that line because they don’t want to support this. Doesn’t mean it doesn’t work for most cases. But you’re right, I would probably eject in prod. I used this hack in a prototype I just needed to get done and it’s spinning fine. Even inside docker. – avlnx Nov 25 '20 at 01:22
  • none of node_modules are checked in, so the code will break for anyone else who checks out the repo? better to fork react-scripts and use your version (and you could send a PR at the same time!). but it's great you were able to find out where to fix it. – dcsan Nov 25 '20 at 19:46
  • I'll have to disagree. This line essentially adds the "paths" key to an object of properties that can't be extended in your own tsconfig file. It has nothing to do with node_modules. Like I said, I ran this project on a docker container and was able to install node packages normally running a simple npm i. In fact the project is in a public repo, you can check it out here and try it out for yourself, just run 'docker-compose up -d': https://gitlab.com/avlnx/goosechase-missions – avlnx Nov 25 '20 at 20:47
  • but aren't you proposing to hot patch a file inside `node_modules` ? Or is it just for your specific project, with it's own version baked into the docker container? – dcsan Nov 25 '20 at 21:07
  • 1
    Ah, I understand what you mean now. A valid question. I used a handy npm module for that called patch-package. You change the node_modules file, run the command and it generates the patch. Then you add the same command to a postinstall npm script and it will repatch everytime (when a team member runs npm i for example since this patch file would be in source control). I still agree with you, detaching would be better for prod but then again in some specific situations it might be worth it. – avlnx Nov 25 '20 at 21:17
  • 2
    @avlnx you should add info about `patch-package` to your answer, since thats is pretty crucial part for the solution to be viable. Otherwise people won't grok why anyone would propose to modify anything in node_modules. To anyone else wondering, yes using `patch-package` is legitimate and sane proposition for dealing with temporary (or not) changes to third party dependencies that one has to work with. – Bartekus Feb 11 '21 at 19:35
2

I had a similar issue to this general problem (CRA overwrites "noEmit": false in my tsconfig.json of a React library I'm working on where I have two separate builds, one for local development, and another to build the production library with typings). Simple solution: use sed in a postbuild script in the package.json. For example: In-place edits with sed on OS X .

{
    ...
    "scripts": {
        ...
        "postbuild": "sed -i '' 's/{THING CRA IS REPLACING}/{WHAT YOU ACTUALLY WANT}/g' tsconfig.json # CRA is too opinionated on this one.",
        ...
    }
    ...
}

This approach, however, is not cross-platform (unlike how rimraf is the cross-platform alternative to rm -rf).

user3773048
  • 5,839
  • 4
  • 18
  • 22
2

For me, the problem was with VSCode using an older version of typescript (4.0.3), while the typescript version shipped with the project is (4.1.2).

The following did the trick for me:

  1. Go to the command palette CTRL+Shift+P.
  2. Choose "TypeScript: Select a TypeScript Version...".
  3. Choose "Use workspace Version".
Vishal Maral
  • 1,279
  • 1
  • 10
  • 30
1

On Botpress (with react-scripts 4.0.3), we use a combination of 2 tricks to use paths without ejecting or patching the code. As Glenn and Microcipcip said, the first step is to extend the tsconfig.json file

tsconfig.path.json

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "~/*": ["src/*"],
      "common/*": ["../bp/src/common/*"]
    }
  }
}

tsconfig.json

{ 
  ...
  "extends": "./tsconfig.paths.json"
}

Then to make it work in the background, use the package react-app-rewired. It allows to make slight adjustments to the webpack configuration without actually ejecting CRA.

config-overrides.js

module.exports = {
  webpack: (config, env) => {
    config.resolve.alias['common'] = path.join(__dirname, '../bp/dist/common')
    config.resolve.alias['~'] = path.join(__dirname, './src')
  }
}

To see the full code, you can check the github repository https://github.com/botpress/botpress/tree/master/packages/ui-admin

Yann
  • 31
  • 3
-1

For macOS this workaround should work.

package.json

"scripts": {
  "start": "osascript -e 'tell app \"Terminal\" to do script \"cd $PATH_TO_REACT_APP && node ./setNoEmitFalse\"' && react-scripts start",
  ...
},
...

setNoEmitFalse.js

const fs = require('fs');
const { sleep } = require('sleep')
const path = './tsconfig.json'
const run = async () => {
  sleep(2)
  const tsconfig = fs.readFileSync(path, 'utf-8');
  const fixed = tsconfig.replace('"noEmit": true', '"noEmit": false');
  fs.writeFileSync(path, fixed)
}
run()

The execution of the javascript file in a separate terminal (osascript) provides the normal output for react-scripts in the original terminal.

mattorp
  • 31
  • 6
-4

Go to node_modules/react-scripts/scripts/utils/verifyTypeScriptSetup.js and replace

const compilerOptions = {
  ...
};

by

const compilerOptions = { };
V D
  • 1
  • 6
    I'm not positive that changing a file inside node_modules should be the way forward considering node_modules is not maintained in source control and other developers would have to remember to do the same on their machines. – Bruno Farias Sep 16 '21 at 16:16
  • Sure-sure, never touch node_modules and don't stress other developers. Then please just enjoy the garbage getting in there via `npm install`, np – V D Dec 22 '21 at 17:28