create-react-app icon indicating copy to clipboard operation
create-react-app copied to clipboard

Let jsxImportSource be configurable through tsconfig.json

Open Andarist opened this issue 5 years ago • 33 comments
trafficstars

Is your proposal related to a problem?

Right now it's only suggested for tsconfig.json to set "jsx": "react" but it's not enforced.

TS 4.1 will bring new JSX-related option (jsxImportSource) and new possible values for the jsx option (react-jsx & react-jsxdev) - both of those changes are related to the new JSX runtimes.

TS also has an ability to change what exact JSX namespace is used for type-checking based on the used jsx factory as per the documentation. This probably means that there is a problem for some possible configuration today: TS can do its typechecking thinking that another factory is used (when one would configure jsxFactory) but in fact the emitted code uses the default factory of React.createElement because the transpilation is done by Babel that is not aware of TS configuration.

I'm not really interested in fixing this problem - I haven't found any issue about this so the audience for this is probably very little and it's just a possible problem that I have thought of and not something that affects me.

However, I would really love to be able to configure jsxImportSource globally and while you don't allow for Babel customization (which is understandable tradeoff here) you allow for some tsconfig.json configuration. It (tsconfig.json) seems to be a good match for inferring this particular configuration for a vast number of consumers (as TS is used by a lot of people).

Motivation

I'm a maintainer of Emotion which is a popular CSS-in-JS solution for React (3.4M downloads/week) which comes with the CSS prop API that is based on @jsx pragma (although not all of our consumers use the CSS prop API as we expose the popular styled API as well).

Right now the @jsx pragma in CRA has to be used all over the place. We personally don't find it to be that problematic but we get complaints about this regularly from the community. Having a way to configure this (new transforms, not the old pragma) globally in CRA would probably result in a huge DX improvement for us.

Describe the solution you'd like

Provide custom importSource to @babel/preset-react, based on the jsxImportSource from tsconfig.json

Describe alternatives you've considered

If this is something that you don't want to support then I strongly believe that you should disallow configuring jsxImportSource in the tsconfig.json altogether because it causes a configuration mismatch between TS and Babel and this might be a footgun for people.


  • [x] Implementation intent

Andarist avatar Oct 21 '20 05:10 Andarist

I created a new project using CRA4 with typescript template today. I have a difficult time trying to use emotion. as I know with the release version 10.1.0 of emotion, I should use /** @jsxImportSource @emotion/core /` instead of /* @jsx jsx */, so I try to use like this

/** @jsxImportSource @emotion/core */
import { jsx } from '@emotion/core';

or just

/** @jsxImportSource @emotion/core */

but I got error anyway saying "'React' refers to a UMD global, but the current file is a module. Consider adding an import instead.". I guess maybe it's about CRA typescript template.

I'm not familiar with neither CRA nor new JSX runtime.

seanbruce avatar Nov 01 '20 13:11 seanbruce

Could u share a repository with this issue reproduced? I could take a look at this.

Andarist avatar Nov 01 '20 13:11 Andarist

@Andarist Thanks! here is the repository https://github.com/seanbruce/butler-of-ellen.git

seanbruce avatar Nov 01 '20 13:11 seanbruce

The current TS version is not aware of the new @jsxImportSource and thus it doesn't know that there are already implicit imports (inserted automatically) based on that @jsxImportSource pragma. This requires TS 4.1 which is currently at the beta stage and I believe that it is supposed to be shipped as stable this month.

I've managed to trick the compiler to accept this by changing this: https://github.com/seanbruce/butler-of-ellen/blob/28754637234e145547f16232fe5eef111457a651/tsconfig.json#L18 to "preserve"

And by adding import '@emotion/core' to this file: https://github.com/seanbruce/butler-of-ellen/blob/28754637234e145547f16232fe5eef111457a651/src/react-app-env.d.ts

Andarist avatar Nov 01 '20 14:11 Andarist

following this trick. I change compilerOptions.jsx to "preserve" and add change react-app-env.d.ts like this

import '@emotion/core';
/// <reference types="react-scripts" />

then I run yarn start I got this error says TypeError: Cannot assign to read only property 'jsx' of object '#<Object>'

seanbruce avatar Nov 02 '20 04:11 seanbruce

Oh, right 😢 I've focused on fixing TS problems without running yarn start and CRA enforces certain values to be what they want them to be. Those are enforced values: https://github.com/facebook/create-react-app/blob/aec42e2cc05fe0799a3b73830b874757e9e3f561/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js#L148-L158

I'll give this more thought but I don't have an idea how this can be approached right now without waiting for TS 4.1

Andarist avatar Nov 02 '20 08:11 Andarist

@Andarist I think I just wait for TS4.1 released to solve this issue once and for all. for now, I use this not perfect solution until TS4.1. Thank you so much for your time.😄

seanbruce avatar Nov 02 '20 08:11 seanbruce

With version Typescript 4.1 I tried

"jsxImportSource": "@emotion/react",
"jsx": "react-jsx"

But the css props from emotion is not working, I have to put "/** @jsxImportSource @emotion/react */" on top on the file.

Is the property jsxImportSource ignored ?

FinPlorer avatar Dec 03 '20 10:12 FinPlorer

And this issue is exactly about this problem. I'm proposing that the CRA's Babel preset could be "configured" with the importSource based on the jsxImportSource of the tsconfig.json. I believe that wouldn't compromise the 0config approach taken by the CRA.

Andarist avatar Dec 03 '20 10:12 Andarist

@iansu fyi this feature (being able to pass importSource to babel) would be a big usability win for CRA's CSS-in-JS users (i.e. emotion/et al) by being able to remove the /** jsxImportSource ... */ lines that currently have to be copy/pasted into every file in a project.

It looks like this PR added an importSource with a process.env.JSX_IMPORT_SOURCE flag:

https://github.com/facebook/create-react-app/pull/10138/files#diff-7cd8a2246cedc973ca54463e12073aaff89e13fda0f3d8b61742ec8e2b64b708R100

But @Andarist is suggesting adding a smarter if-isTypeScriptEnabled-then-parse-tsconfig-for-its-jsxImportSource setting, right around this section of code from your "New JSX Transform Opt Out" PR:

https://github.com/facebook/create-react-app/blame/master/packages/babel-preset-react-app/create.js#L99

If I wrote a PR that changed that ~section of code to conditionally parse tsconfig.json and pass along importSource to babel, would that likely get accepted? Do you have any preferences/suggestions for a better approach?

Thanks!

(...I'm a little worried about "just fs.load tsconfig.json; while really simple, it wouldn't support tsconfigs that extend other tsconfigs ... would have to research the idiomatic way of loading tsconfigs...although maybe that could be a V2.)

stephenh avatar Jan 14 '21 17:01 stephenh

TS exposes the API to read the config file so that part shouldn't be particularly a problem: https://github.com/facebook/create-react-app/blob/aec42e2cc05fe0799a3b73830b874757e9e3f561/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js#L173-L176

Andarist avatar Jan 14 '21 23:01 Andarist

@stephenh Curious if you had the chance to start the PR you mentioned? I just created a new CRA4 app + Emotion 11 and ran into this - completely agree it will be awesome for CRA users if they don't have to manually prepend /** @jsxImportSource @emotion/react */ on a per-file basis.

onpaws avatar Feb 01 '21 00:02 onpaws

Is the property jsxImportSource ignored ?

@MatthieuCoelho Yes, it seems that way. On CRAv4.0.1 + Emotion v11.1.4 I was able to repro what you're describing - this property seems to not get picked up by react-scripts which makes sense since it only arrived with TS v4.1+.

Is anyone aware of existing PRs that start to make CRA aware of TypeScript 4.1?

onpaws avatar Feb 01 '21 00:02 onpaws

@onpaws no, didn't bother starting a PR w/o an ack from the maintainers. Plus our existing codebase already has the per-file snippet so this is a nice to have, but not blocking us.

stephenh avatar Feb 01 '21 00:02 stephenh

Got it, thanks for the prompt reply.

Plus our existing codebase already has the per-file snippet so this is a nice to have, but not blocking us.

Lucky you, wish I could say the same! 🙈

If I get some time in the coming weeks I'll try to take a look at 1, 2 for other potential ways to workaround it.

onpaws avatar Feb 01 '21 00:02 onpaws

If you're happy using craco/rewired so you can edit the babel config then you should be able to get around the per-file pragma definition with the trick I've used for twin.

ben-rogerson avatar Feb 01 '21 02:02 ben-rogerson

I opened a PR that uses the jsxImportSource compiler option from tsconfig.json or removes it (and explains why) when Babel and TypeScript configuration would be inconsistent: https://github.com/facebook/create-react-app/pull/10583

hermansje avatar Feb 20 '21 16:02 hermansje

Any progress on this one?

pedrosimao avatar Jul 04 '21 23:07 pedrosimao

This issue is confusing and some documents say this typescript config works but actually it is not. Do you have any updates on this issue?

donaldkg avatar Dec 10 '21 04:12 donaldkg

I'm currently running a vite application and the emotion docs (https://emotion.sh/docs/typescript) suggest updating the tsconfig compiler options with:

{
    "jsx": "react-jsx",
    "jsxImportSource": "@emotion/react",
}

but this does not work- I still need to add /** @jsxImportSource @emotion/react */ above each file. What am I missing?

55Cancri avatar May 17 '22 18:05 55Cancri

Any news on this ?

gimurpe avatar Nov 17 '22 15:11 gimurpe

need to add /** @jsxImportSource @emotion/react */ above each file is very hard for devlopers

guopingxiao avatar Dec 01 '22 03:12 guopingxiao

👍

ALFmachine avatar Dec 28 '22 18:12 ALFmachine

Oh man, this problem is really annoying for the developer experience. In our project, the css prop worked for a long time, until some update. Unfortunately, the bug is noticed only in the application and not in the development process.

I don't want to complain, because I am very thankful for all the time invested in open source tools here. However, this problem is so prominent in Google searches that it really should be addressed.

baba43 avatar Feb 20 '23 13:02 baba43

In case this helps anyone: if your configuration is ejected and you have access to the Webpack config file, you can use the ModifySourcePlugin to prepend the jsxImportSource comment to every file:

new ModifySourcePlugin({
  rules: [
    {
      test: /\.tsx$/i,
      operations: [
        new ConcatOperation(
          'start',
          '/** @jsxImportSource @emotion/react */\n\n'
        )
      ]
    }
  ]
}),

I added it at the start of the plugins list, which seemed to do the trick. It's not ideal, but I couldn't bear the thought of adding this at the top of every file. 😅

claudiamatosa avatar Mar 01 '23 10:03 claudiamatosa

Is there any update on this issue? It's been a problem for a while, and I can not figure out how to use the CSS prop without manually adding the JSX Pragma in every file. It is extremely annoying to add it to every file and if anyone has a solution that does not involve prepending the pragma using a Webpack plugin it would be much appreciated! I am also using CRACO, but no luck getting it to work.

Gittified avatar Apr 15 '23 23:04 Gittified

Would be awesome to have an inline CSS solution out of the box. Svelte/SvelteKit does this the best way to my knowledge: no extra steps needed, you can just write standard CSS within your component and they are scoped to it by default, even the classes.

finnhvman avatar Apr 16 '23 09:04 finnhvman

I do not want to add /** @jsxImportSource @emotion/react */ at the top of every file in my CRA project. Not only because its extra work, and we as developers should find solutions for repetitive tasks, but also because it looks hideous and hacky.

Does anyone have a step by step work-around this issue?

TamirCode avatar May 31 '23 18:05 TamirCode

I do not want to add /** @jsxImportSource @emotion/react */ at the top of every file in my CRA project. Not only because its extra work, and we as developers should find solutions for repetitive tasks, but also because it looks hideous and hacky.

Does anyone have a step by step work-around this issue?

Yes, the solution is simple: switch to vite yesterday and start using stitches instead of emotion. All your problems will be solved overnight.

55Cancri avatar May 31 '23 19:05 55Cancri

I do not want to add /** @jsxImportSource @emotion/react */ at the top of every file in my CRA project. Not only because its extra work, and we as developers should find solutions for repetitive tasks, but also because it looks hideous and hacky. Does anyone have a step by step work-around this issue?

Yes, the solution is simple: switch to vite yesterday and start using stitches instead of emotion. All your problems will be solved overnight.

I like to use inline-styles like this, unfortunately stitches doesnt work like this.

			<div
				css={{
					backgroundColor: 'pink',
					height: "500px",
					'&:hover': {
						backgroundColor: 'green'
					}
				}}
			>
			</div>

TamirCode avatar May 31 '23 23:05 TamirCode