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

TypeScript {paths} are not taken into consideration #5585

Closed
rolandjitsu opened this issue Oct 26, 2018 · 28 comments
Closed

TypeScript {paths} are not taken into consideration #5585

rolandjitsu opened this issue Oct 26, 2018 · 28 comments

Comments

@rolandjitsu
Copy link

rolandjitsu commented Oct 26, 2018

Edit from maintainers: we want to support this — see #5585 (comment) for details!


Is this a bug report?

Yes.

Did you try recovering your dependencies?

NPM 5.6.0
Yarn 1.7.0

Which terms did you search for in User Guide?

paths, paths map, path mappings, typescript path, typescript paths

Environment

  System:
    OS: macOS High Sierra 10.13.6
    CPU: x64 Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz
  Binaries:
    Node: 8.11.2 - ~/.nvm/versions/node/v8.11.2/bin/node
    Yarn: 1.7.0 - ~/.yarn/bin/yarn
    npm: 5.6.0 - ~/.nvm/versions/node/v8.11.2/bin/npm
  Browsers:
    Chrome: 69.0.3497.100
    Firefox: 61.0.1
    Safari: 12.0
  npmPackages:
    @types/react: ^16.4.18 => 16.4.18 
    react: ^16.6.0 => 16.6.0 
    react-dom: ^16.6.0 => 16.6.0 
    react-scripts: 2.0.6-next.c662dfb0

Steps to Reproduce

TypeScript {paths} in {compilerOptions} are not working.

  1. Clone cra-workspaces#cra-2
  2. yarn install at the root
  3. cd apps/cra
  4. yarn start

Expected Behavior

CRA should resolve the modules listed in {paths}.

Actual Behavior

CRA cannot resolve the modules listed in {paths}.

Reproducible Demo

cra-workspaces#cra-2, instructions listed above.

@miraage
Copy link

miraage commented Oct 26, 2018

AFAIK @babel/plugin-typescript only used for type-checking and validation, whilst actual emit is made by Babel (so no tsc is involved).

Adding tsconfig-paths-webpack-plugin should solve this issue.

@rolandjitsu
Copy link
Author

@miraage but this would have to be done by CRA, because I'd like to avoid ejecting the config.

@miraage
Copy link

miraage commented Oct 26, 2018

@rolandjitsu Agree. It should have been done by CRA, if I had been right in my assumptions regarding babel/tsc.

@rolandjitsu
Copy link
Author

@miraage actually, @babel/plugin-typescript loads @babel/plugin-transform-typescript which does the opposite of what you describe, it does not type check, it just transforms the ts to js.

So it's possible that path support needs to be added in both webpack and babel. Furthermore, jest also needs support for this (in react-scripts-ts this is done via jest moduleNameMapper option).

@miraage
Copy link

miraage commented Oct 26, 2018

@rolandjitsu

https://babeljs.io/blog/2018/08/27/7.0.0#typescript-support-babel-preset-typescript

We worked with the TypeScript team on getting Babel to parse/transform type syntax with @babel/preset-typescript, similar to how we handle Flow with @babel/preset-flow.

@Timer
Copy link
Contributor

Timer commented Oct 26, 2018

Currently this is done on purpose. We have no immediate plans to respect alternate module resolve modes/paths.

@lee-reinhardt
Copy link

lee-reinhardt commented Oct 26, 2018

EDIT: This workaround no longer works with the latest CRA versions where the TS config is routinely reset.

This can be achieved without ejecting if you're willing to use react-app-rewired in combination with customize-cra.

There's a big warning on the react-app-rewired readme about it not supporting CRA 2.x, but this is referring to their helpers like injectBabelPlugin and such. The base machinery for allowing you to hook into and override Webpack/Babel configs is still useful. The actual Webpack/Babel config manipulations provided by customize-cra are made for CRA 2.x.

An example, setting up two aliases:

  • @ui points to <root>/src/ui
  • @src points to <root>/src
  1. Update tsconfig.json with your custom paths:
  "compilerOptions": {
    ...
    "baseUrl": "./src",
    "paths": {
      "@ui/*": ["ui/*"],
      "@src/*": ["./*"]
    },
    ...
  }
  1. $ yarn add react-app-rewired customize-cra
  2. Change all package.json scripts commands to use react-app-rewired instead of react-scripts.
  3. Create a config-overrides.js file at the project root
  4. Set up your paths overrides using the customize-cra helper addWebpackAlias
const path = require('path')
const { addWebpackAlias } = require('customize-cra')

module.exports = function override(config, env) {
  config = addWebpackAlias({
    ['@ui']: path.resolve(__dirname, 'src', 'ui'),
    ['@src']: path.resolve(__dirname, 'src')
  })(config)

  return config
}
  1. At this point, your path aliases should be working.
  2. To get the aliases working in Jest, add this to your package.json:
  "jest": {
    "moduleNameMapper": {
      "^@ui(.*)$": "<rootDir>/src/ui$1",
      "^@src(.*)$": "<rootDir>/src$1"
    }
  },

The react-app-rewired + customize-cra combo should allow you to change nearly anything you want in CRA without ejecting. I use it for path aliasing and Babel plugins where a macro is unavailable.

@jamsch
Copy link

jamsch commented Oct 27, 2018

Yeah, I currently have the following config which works fine on react-scripts-ts@3.1.0 however not here.

 "paths": {
      "~/*": [
        "src/*"
      ]
    },

@rolandjitsu
Copy link
Author

rolandjitsu commented Oct 27, 2018

@Timer while I understand the decision, I do hope that this is somewhere on the roadmap. Clearly, some of us (e.g. @lee-reinhardt) go to great lengths to figure out how to make this work.

I personally believe that it would be a valuable feature to have built in support for paths in CRA 2, and the effort to achieve this should be small, assuming it's just a matter of adding the webpack tsconfig-paths-webpack-plugin plugin.

@jamsch yes, react-scripts-ts does have support for paths. And they're also working on wmonk/create-react-app-typescript#409 to upgrade to CRA 2. But they're debating whether it's worth continuing given that CRA 2 also has support for TS.

The only difference, at the moment, between react-scripts and react-scripts-ts in terms of TS is path support and tslint (more or less). So adding path support here would eliminate the need of using react-scripts-ts which means that you do not need to wait for the maintainers of react-scripts-ts to upgrade CRA (they're usually doing a great job at being in sync with CRA) to get the newest features and that there are less chances for bugs to occur when the sync occurs.

Nonetheless, I'd be more than happy to give this a shot if pointed in the right direction.

EDIT: If babel is in charge of transforming ts to js, perhaps module-resolver could be an option?

@ahadcove
Copy link

I agree with @rolandjitsu, this is a pretty big concern. Every Typescript app I have made exploited Paths as much as possible. One of the beauties of using TS. I currently have a few projects in react-scripts-ts that I was converting over this weekend until I kept running into issues with paths. That's what led me here.

I really hope this is built into CRA sooner rather than later.

@rassie
Copy link

rassie commented Oct 28, 2018

FWIW, I've managed to add paths support via craco like this:

First, a craco plugin is needed:

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');

module.exports = {
    overrideWebpackConfig: ({ webpackConfig, cracoConfig, pluginOptions, context: { env, paths } }) => {
        webpackConfig.resolve.plugins.push(new TsconfigPathsPlugin({}))
        return webpackConfig;
    }
};

Then, it needs to be added to craco configuration:

const logWebpackConfigPlugin = require("./craco-plugin");

module.exports = {
    plugins: [
        { plugin: logWebpackConfigPlugin }
    ]
}

Hope this will help someone on this thread. However, now I have to wonder whether it's all broken now due to #5609.

@rassie
Copy link

rassie commented Oct 28, 2018

@Timer please consider changing value to suggested in #5609 to allow temporary hacks and workaround like the one I cited to continue to work. Thank you for understanding.

@jamsch
Copy link

jamsch commented Oct 28, 2018

Honestly I see paths as quite a necessity for any medium-large project because what inevitably happens is importing from the project root for components that are multiple levels deep which ends up like:

// src/components/ui/Button/Square.tsx
import colors from '../../../../res/colors.ts'; // instead of '~/res/colors.ts'

// src/pages/auth/signin/SignIn.tsx
import * as Button from '../../../../components/ui/Button';  // instead of '~/components/ui/Button'

Any further refactoring (such as moving components around) often end up messing the import path nesting unless IDE refactoring features save you.

This is a must-have for my use case so I'll probably end up ejecting if this isn't on the cards for the CRA team.

@Timer
Copy link
Contributor

Timer commented Oct 28, 2018

Closing as a duplicate of #5118.

TypeScript support will ship without support for baseUrl and paths.
Sorry for any inconvenience! I know it'll be a bit painful to switch back to relative paths.

Edit: we do want to support this in the future, it just didn't make it into the initial release. See this comment: #5585 (comment).

@Timer Timer closed this as completed Oct 28, 2018
@rolandjitsu
Copy link
Author

@Timer I'm a bit disappointed to see such resistance to add TS paths support. Paths were quite a big feature in TS and a lot of ppl were very happy to have it.

@danielkcz
Copy link

@Timer Would you care to elaborate on why this decision has been made? Your comments have been rather short and non-informative. Is it really such a technical difficulty or it was left out just annoy developers and never use Typescript with CRA? Once you start using this TypeScript feature you really don't want to go back to these long '../../../..' paths.

@Timer
Copy link
Contributor

Timer commented Oct 29, 2018

We've held this position for a long time. Allowing users to adjust the module resolution order is rather confusing and can lead to subtle bugs (i.e. aliasing something that conflicts with a npm package name).

It's hard to get all tooling to agree on how the resolution is performed, as we need to consider: webpack, Jest, Flow, TypeScript itself, and other tooling end-users install.

This isn't a hard no, but it's likely we'll only add support for absolute imports and not arbitrary aliasing (i.e. baseUrl but not paths).

Due to this complexity, we'll ship support without paths & baseUrl and evaluate it at a later date.

Edit: we do want to support this in the future, it just didn't make it into the initial release. See this comment: #5585 (comment).

@izayl
Copy link

izayl commented Nov 7, 2018

This can be achieved without ejecting if you're willing to use react-app-rewired in combination with customize-cra.

There's a big warning on the react-app-rewired readme about it not supporting CRA 2.x, but this is referring to their helpers like injectBabelPlugin and such. The base machinery for allowing you to hook into and override Webpack/Babel configs is still useful. The actual Webpack/Babel config manipulations provided by customize-cra are made for CRA 2.x.

An example, setting up two aliases:

  • @ui points to <root>/src/ui
  • @src points to <root>/src
  1. Update tsconfig.json with your custom paths:
  "compilerOptions": {
    ...
    "baseUrl": "./src",
    "paths": {
      "@ui/*": ["ui/*"],
      "@src/*": ["./*"]
    },
    ...
  }
  1. $ yarn add react-app-rewired customize-cra
  2. Change all package.json scripts commands to use react-app-rewired instead of react-scripts.
  3. Create a config-overrides.js file at the project root
  4. Set up your paths overrides using the customize-cra helper addWebpackAlias
const path = require('path')
const { addWebpackAlias } = require('customize-cra')

module.exports = function override(config, env) {
  config = addWebpackAlias({
    ['@ui']: path.resolve(__dirname, 'src', 'ui'),
    ['@src']: path.resolve(__dirname, 'src')
  })(config)

  return config
}
  1. At this point, your path aliases should be working.
  2. To get the aliases working in Jest, add this to your package.json:
  "jest": {
    "moduleNameMapper": {
      "^@ui(.*)$": "<rootDir>/src/ui$1",
      "^@src(.*)$": "<rootDir>/src$1"
    }
  },

The react-app-rewired + customize-cra combo should allow you to change nearly anything you want in CRA without ejecting. I use it for path aliasing and Babel plugins where a macro is unavailable.

CRA@2.0.4 not work, It will remove baseUrl and paths in tsconfig.json

@jamsch
Copy link

jamsch commented Nov 7, 2018

@izayl

CRA@2.0.4 not work, It will remove baseUrl and paths in tsconfig.json

You're right. I'm currently stuck on react-scripts@2.0.6-next.c662dfb0 with the customize-cra/react-app-rewired config for the time being. Considering forking this repo and at least taking out the part that removes path/baseurl config from the user's tsconfig if there's no plans for implementation.

@gopeter
Copy link

gopeter commented Nov 7, 2018

You can use 2.1.0 (or rather 2.1.1) and use the extends function (#5645 (comment)). Works like a charm for my mid-sized Typescript CRA app.

@danielkcz
Copy link

@jamsch Why to fork when there is react-scripts-ts@next? So far it works just fine.

@chulanovskyi
Copy link

You can use 2.1.0 (or rather 2.1.1) and use the extends function (#5645 (comment)). Works like a charm for my mid-sized Typescript CRA app.

Confirm, it works. But another problem is with "isolatedModules" is being set to "true", and the extending file does not overwrite this parameter.

@gopeter
Copy link

gopeter commented Nov 8, 2018

That's right. I assume that you need this to fix .json imports? I didn't find a solution for this, but since I just have to import a few JSON files, I've converted them to plain JS objects for now.

@diegolaciar
Copy link

diegolaciar commented Dec 7, 2018

+1 to add this feature to TS project.

People working with TS need Absolute Path or Alias config feature.

Thanks

@ChristianIvicevic
Copy link

You can use 2.1.0 (or rather 2.1.1) and use the extends function (#5645 (comment)). Works like a charm for my mid-sized Typescript CRA app.

This doesn't work for me - the moment I run the server the tsconfig gets reset and apparently the baseUrl doesn't get propagated to webpack. It is a shame that this does not work as expected.

@gaearon
Copy link
Contributor

gaearon commented Jan 3, 2019

Just to be clear — we do want to support absolute paths.

#5585 (comment) referred to what we ship in the first version with TypeScript to intentionally limit the scope. It doesn't mean we don't want this! :-)

In particular, we want to:

I'm sorry for the frustration this is causing. We're not asking you to convert your code to use relative paths — but please wait for either of these two issues to resolve.

I'll close this one but you can track either #5692 or #5118, and we'll let you know when we have something!

@diegolaciar
Copy link

@gaearon thanks for your response

@gaearon
Copy link
Contributor

gaearon commented Jan 3, 2019

There is also another plausible alternative — we could embrace tsconfig.json / jsconfig.json, and make paths specified there work across the setup (Webpack/Jest). See #5645 for that.

@lock lock bot locked and limited conversation to collaborators Jan 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests