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

fix: enable failing dependencies to be optimised by pre-processing them with esbuild #4275

Merged
merged 6 commits into from Aug 23, 2021

Conversation

fwouts
Copy link
Contributor

@fwouts fwouts commented Jul 16, 2021

Description

Some packages such as Gatsby ship with JSX which is expected to be compiled by the library users' bundler.

While there are workarounds to force Vite to interpret .js files as JSX (see discussion), these are not sufficient when the JSX is inside node_modules/. In particular, es-module-lexer doesn't support JSX (this was considered infeasible as per guybedford/es-module-lexer#47). This means that the parse() call at:

const exportsData = parse(entryContent) as ExportsData
fails when it encounters JSX.

While the best approach is certainly to ensure that packages don't ship as JSX, it's possible to improve the situation by adding a fallback mechanism which transforms the code with esbuild prior to re-trying.

This fix enables Gatsby to work when passing Vite the following options:

        esbuild: {
          loader: "jsx",
        },
        optimizeDeps: {
          esbuildOptions: {
            loader: {
              ".js": "jsx",
            },
          },
        },

Since it's only a fallback mechanism, it shouldn't affect performance adversely.

Additional context

This was originally surfaced as a bug report for the Viteshot project, see fwouts/viteshot#53.

Example project: https://github.com/fwouts/vite-gatsby-sample-app


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines and follow the Commit Convention.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.

packages/vite/src/node/optimizer/index.ts Outdated Show resolved Hide resolved
config.logger.warn(
`Unable to parse dependency: ${id}. Trying again with an esbuild transform.`
)
const transformed = await transform(entryContent, config.esbuild || {})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use { loader: { '.js': 'jsx' } } automatically, removing the need for user to configure it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question. Even if we hardcode this here, you still do need the following to make it work, because it would otherwise fail at a later stage when optimising deps:

        optimizeDeps: {
          esbuildOptions: {
            loader: {
              ".js": "jsx",
            },
          },
        },

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could move this statement up:

const { plugins = [], ...esbuildOptions } =
config.optimizeDeps?.esbuildOptions ?? {}

..then mutate the esbuildOptions from here:

esbuildOptions.loader ??= {}
esbuildOptions.loader['.js'] ??= 'jsx'
const transformed = await transform(entryContent, esbuildOptions)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea. I did that, although couldn't directly use esbuildOptions for the transform call (since the loader field type isn't compatible). Let me know what you think!

@aleclarson aleclarson added the p3-downstream-blocker Blocking the downstream ecosystem to work properly (priority) label Jul 16, 2021
@aleclarson
Copy link
Member

A git repo that reproduces the issue would be super handy. :)

@fwouts
Copy link
Contributor Author

fwouts commented Jul 18, 2021

A git repo that reproduces the issue would be super handy. :)

You're right, I should have thought about that! Here you go: https://github.com/fwouts/vite-gatsby-sample-app

@TomokiMiyauci
Copy link

I faced the same problem.

When I use storybook as a vite bandler,
I couldn't handle the jsx files with Gatsby js extension correctly.

@fwouts fwouts requested a review from aleclarson July 20, 2021 03:55
aleclarson
aleclarson previously approved these changes Jul 23, 2021
@patak-dev
Copy link
Member

I think we should discuss this PR with Evan before merging it, as it introduced special handling for JSX. It would be useful for that discussion to know what is preventing this fallback to be added as a userland plugin (or as a more generic feature that could enable the userland plugin)

@fwouts
Copy link
Contributor Author

fwouts commented Jul 24, 2021

I think we should discuss this PR with Evan before merging it, as it introduced special handling for JSX. It would be useful for that discussion to know what is preventing this fallback to be added as a userland plugin (or as a more generic feature that could enable the userland plugin)

That's a great point. If special handling of JSX isn't desired, perhaps a good alternative would be to enable plugins to somehow be able to override the handling in this part of the code.

@antfu
Copy link
Member

antfu commented Aug 2, 2021

Using try-catch to fallback to jsx parsing for every js file in order to fix this niche case is not ideal to me. I think at least on their side they'd better to ship with .jsx instead of .js in their dist.

I will add this to this week's meeting with Evan.

@antfu antfu added the on hold label Aug 2, 2021
@fwouts
Copy link
Contributor Author

fwouts commented Aug 12, 2021

Hey @antfu, I was just wondering what was the outcome of the meeting? :)

@Shinigami92
Copy link
Member

Hey @antfu, I was just wondering what was the outcome of the meeting? :)

The meeting was rescheduled to today

Shinigami92
Shinigami92 previously approved these changes Aug 13, 2021
Copy link
Member

@Shinigami92 Shinigami92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this we are good to go and got an approval from Evan at todays meeting

packages/vite/src/node/optimizer/index.ts Outdated Show resolved Hide resolved
@Shinigami92 Shinigami92 self-requested a review August 13, 2021 16:42
@Shinigami92 Shinigami92 dismissed their stale review August 13, 2021 16:42

Accidentally pressed the wrong button :D

@antfu antfu removed the on hold label Aug 14, 2021
Shinigami92
Shinigami92 previously approved these changes Aug 21, 2021
@aleclarson aleclarson merged commit ea98a1a into vitejs:main Aug 23, 2021
ygj6 pushed a commit to ygj6/vite that referenced this pull request Aug 24, 2021
ygj6 pushed a commit to ygj6/vite that referenced this pull request Aug 24, 2021
ygj6 pushed a commit to ygj6/vite that referenced this pull request Aug 24, 2021
aleclarson pushed a commit to aleclarson/vite that referenced this pull request Nov 8, 2021
@fwouts fwouts deleted the retry-parse branch April 15, 2022 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p3-downstream-blocker Blocking the downstream ecosystem to work properly (priority)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants