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

Improve auto-import for JSX (the jsxInject option) #2369

Closed
vimcaw opened this issue Mar 4, 2021 · 10 comments
Closed

Improve auto-import for JSX (the jsxInject option) #2369

vimcaw opened this issue Mar 4, 2021 · 10 comments
Labels
enhancement New feature or request

Comments

@vimcaw
Copy link

vimcaw commented Mar 4, 2021

Is your feature request related to a problem? Please describe.

According to the document of Vite, we can do an auto-import for JSX by:

// vite.config.js
export default {
  esbuild: {
    jsxInject: `import React from 'react'`
  }
}

But it just places this snippet to the header of codes by simply concatenating string:

result.code = options.jsxInject + ';' + result.code

If some codes have already import React for something like:

import React from 'react';

export default function Button(props: React.ButtonHTMLAttributes<HTMLElement>) {
    return <div {...props} />
}

that will cause conflict and throw an error: Uncaught SyntaxError: Identifier 'React' has already been declared.

I know some codemod can migrate the React imports, but I don't want to change that codes for some reason.

Describe the solution you'd like

According to the document of ESBuild:

First, create a file called react-shim.js that re-exports everything from the react package in an export called React:

// react-shim.js
export * as React from 'react'

Then use esbuild's inject feature to inject this into each file:

esbuild app.jsx --bundle --inject:./react-shim.js --outfile=out.js

In my test, I create a file with:

import React from 'react';

export default function Test() {
    return <div>Test</div>
}

Then use esbuild's inject feature by --inject:./react-shim.js, esbuild will output:

import * as React from "react";
import React2 from "react";
export default function Test() {
  return /* @__PURE__ */ React2.createElement("div", null, "Test");
}

Although there are duplicate variables React, but at least this is compatible with the old code.

So I hope vite can provide inject config of esbuild.

Describe alternatives you've considered

Or handle duplicated import by vite itself.

Additional context

Some codemod can migrate the React importing:
https://github.com/reactjs/react-codemod#update-react-imports

@patak-dev patak-dev added the enhancement New feature or request label Mar 4, 2021
vimcaw added a commit to vimcaw/vite that referenced this issue Mar 18, 2021
@vimcaw vimcaw changed the title Improve auto-import for JSX Improve auto-import for JSX (the jsxInject option) Mar 18, 2021
@vimcaw
Copy link
Author

vimcaw commented Mar 22, 2021

The dev-server of Vite uses transform API of esbuild so it can't use the inject option (that is build API only option), so it should be handled by Vite, I made a PR to solve this: #2586

@VottusCode
Copy link

VottusCode commented May 22, 2021

Considering the following snippet:

result.code = options.jsxInject + ';' + result.code

Why not just make jsxInject a function that you pass result.code into? What I'm proposing is something like:

{
  esbuild: {
    jsxInject: (str: string) => !str.includes('import React') ? "import React from 'react'" : ""
  }
}

The refactoring changes would be minimal, the old way of directly passing a string can still be supported and it adds more flexibility to the configuration IMO.

@aleclarson
Copy link
Member

Now that vite-react-jsx exists, the esbuild.jsxInject option will probably be deprecated.

@vimcaw
Copy link
Author

vimcaw commented May 24, 2021

@aleclarson I notice it use babel to transform jsx, how about performance?

@aleclarson
Copy link
Member

@aleclarson I notice it use babel to transform jsx, how about performance?

I guess I should make the readme clearer. It only uses Babel when vite build is used. In serve mode, it just injects a React import into JSX/TSX modules that are missing one.

@vimcaw
Copy link
Author

vimcaw commented May 24, 2021

@aleclarson That's Cool! I will try it.

abhijit-hota added a commit to abhijit-hota/vite that referenced this issue Jul 18, 2021
**Motivation:** The comment [here](vitejs#2369 (comment)) 
The mentioned plugin is really helpful (and is maintained by a member of the Vite team) and could help users finding a (better ?) solution instead of the proposed way of just injecting the `import` statement in `jsxInject` which seems hacky.
@codepunkt
Copy link
Contributor

Whatever the way to go forward is, please don't forget preact and other jsx pragmas.

@JanTvrdik
Copy link

The following workaround seems to work for me.

// vite.config.js
export default {
  esbuild: {
    jsxFactory: '_jsx',
    jsxFragment: '_jsxFragment',
    jsxInject: `import { createElement as _jsx, Fragment as _jsxFragment } from 'react'`,
  }
}

@VottusCode
Copy link

The following workaround seems to work for me.

// vite.config.js
export default {
  esbuild: {
    jsxFactory: '_jsx',
    jsxFragment: '_jsxFragment',
    jsxInject: `import { createElement as _jsx, Fragment as _jsxFragment } from 'react'`,
  }
}

Nice seeing you here, thought you're stuck with Nette :D

Anyways, yeah, this works for me too.

dhess added a commit to hackworthltd/primer-app that referenced this issue Sep 23, 2021
See:

https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

For the moment, the best way to support this in Vite (`esbuild`,
really) is via this configuration:

vitejs/vite#2369 (comment)

so that's what we use.

There's a Vite plugin that addresses this here:
https://github.com/alloc/vite-react-jsx. However, that plugin has a
performance impact on production builds because has to use Babel,

The simpler `jsxInject` workaround described here:

vitejs/vite#2369

is not quite as foolproof as the workaround we're using.
@Niputi
Copy link
Contributor

Niputi commented Oct 31, 2021

closing at the new react plugin improved auto import.

@Niputi Niputi closed this as completed Oct 31, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Nov 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
7 participants