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(renderer): omitting internal symbol from mdx props #10813

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Xetera
Copy link
Contributor

@Xetera Xetera commented Apr 18, 2024

I've noticed that when using the following code in an mdx file with a content collection, everything works fine if I have a properly compiling page

<MyComponent {...props} />

But if there's an error anywhere in the codebase after a react dependency is being used, let's say

import { useState } from 'react';
export default function MyComponent() {
  useState(0);
  someKindOfRenderBreakingErrorHere;

  return <p>something</p>;
}

we're greeted with an error that makes no sense

Cannot read properties of null (reading 'useState')

But if the error happens earlier in the code like

import { useState } from 'react';
export default function MyComponent() {
  someKindOfRenderBreakingErrorHere;
  useState(0);

  return <p>something</p>;
}

then we get the expected error

someKindOfRenderBreakingErrorHere is not defined

Here's a minimal reproducible example: https://codesandbox.io/p/devbox/magical-hoover-phk2cv?file=%2Fastro.config.mjs%3A9%2C2

After some digging, I found that the problem happens because the symbol

const hasTriedRenderComponentSymbol = Symbol('hasTriedRenderComponent');

gets passed down to the user's component.

The weird error messages even go away if we manage to get rid of that symbol in the mdx outside the compiler before the react component is rendered, like:

{(function (props) {
  const [symbol] = Object.getOwnPropertySymbols(props)
  delete props[symbol]
}(props))}

While trying to unknowningly recreate the above example using an old astro version before v4.5.9, I realized that all react mdx components used to have this issue even without {...props} being spread.

<MyComponent />

After updating astro to latest, I traced this problem getting partially fixed with this commit 627e47d.

I'm guessing it has something to do with Skip.symbol always being passed in, but the new symbol is also always being passed in. I guess I'm not familiar enough with the astro compiler internals to know why that was always erroring and the above commit made it only break when props is spread. Oh well.

Here's the same problem happening with v4.5.8 without any props getting passed to the component in the mdx file in case you're curious https://codesandbox.io/p/devbox/compassionate-hypatia-glvdg5?file=%2Fastro.config.mjs

Changes

I'm not 100% sure what part of the process vnode.type() exactly represents. Omitting the symbol here seems to magically solve the problem, but I can't really explain why a symbol being passed to a component would cause React to be null. Since this is a build error, I can't compare bundle outputs either to see what exactly is being changed either.

Since this function continues to recurse with the value of vnode.props, I had to spread the symbol out of it instead of mutating.

Testing

I added a regression test for the user-facing part of the problem which is that error messages get messed up during build errors. I don't think it would be valuable to check for any specific symbol in the mdx here

Docs

Shouldn't need a documentation change for a bug fix

Copy link

changeset-bot bot commented Apr 18, 2024

🦋 Changeset detected

Latest commit: 6d0645d

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added pkg: integration Related to any renderer integration (scope) pkg: astro Related to the core `astro` package (scope) labels Apr 18, 2024
@Xetera Xetera changed the title fix(renderer): omitting internal symbol from user component props fix(renderer): omitting internal symbol from mdx props Apr 18, 2024
@matthewp
Copy link
Contributor

!bench render

This comment was marked as outdated.

@Xetera Xetera force-pushed the fix-renderer-internal-symbol branch 2 times, most recently from 3b7c092 to b57b8cf Compare April 19, 2024 12:47
@Xetera Xetera force-pushed the fix-renderer-internal-symbol branch from b57b8cf to 6d0645d Compare April 19, 2024 13:43
@ematipico
Copy link
Member

!bench render

Copy link
Contributor

PR Benchmark

Render

Page Avg (ms) Stdev (ms) Max (ms)
/astro 110.98 32.46 219.26
/md 3.44 2.95 29.15
/mdx 103.77 21.19 194.76

Main Benchmark

Render

Page Avg (ms) Stdev (ms) Max (ms)
/astro 114.70 31.17 212.31
/md 3.45 2.90 28.97
/mdx 104.36 20.80 197.03

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: astro Related to the core `astro` package (scope) pkg: integration Related to any renderer integration (scope)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants