wooorm / xdm

Just a *really* good MDX compiler. No runtime. With esbuild, Rollup, and webpack plugins
http://wooorm.com/xdm/
MIT License
595 stars 18 forks source link

Performance issues in a live editor using evaluate #93

Closed shimamooo closed 3 years ago

shimamooo commented 3 years ago

Background

I am building a live editor using xdm evaluate. Functions the exact same as the MDX playground. From what I understand, a new React node is generated by evaluate for every keyboard event. This causes considerable keyboard input lag especially when you start embedding some and JSX components. I have tried to make iframe components load on click and initially render without src attribute but this didn't have an impact on input lag. I've also tried memoizing my evaluate call.

Reproduce input lag

Copy and paste this into the MDX Playground:

# Hello, world!

<button>Here is a button</button>

Try back space on this sentence to delete (will see lag). Iframes and React components reload on every single keystroke.

<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />
<iframe src="https://codesandbox.io/embed/nice-cloud-3chkc?fontsize=14&hidenavigation=1&theme=dark" />

Question

How can I make this editor more performant? Can it be done better using compile every few seconds?

Demoboard

Demoboard has an excellent live editor with no input lag, however compromises by not having a live output. Can I do same thing it does by using compile? And would I be able to avoid input lag but still have a live output?

Thank you!

wooorm commented 3 years ago

a) see https://github.com/mdx-js/mdx/blob/main/docs/_component/editor.client.js for inspiration, this uses the next mdx, which is not released, nu when it is, will be the same as xdm. The key here is to use a good editor (codemirror or so that handles the complex stuff, de ounces, and that you memo things) b) yes, debounce and memo c) is possible, call the resulting component from evaluate yourself: MDXContent(props) instead <MDXContent>. See: https://github.com/mdx-js/mdx/issues/1655

shimamooo commented 3 years ago

Absolute beauty of an answer, going to debounce & memo w/ compile & codemirror. Thanks once again!

wooorm commented 3 years ago

Perfect! Btw I don’t necessarily recommend doing compile instead of evaluate. evaluate shouldn’t be a performance bottle neck — doing compile and then some manual code to eval it would most likely be exactly as slow/fast!

shimamooo commented 3 years ago

Continuing the discussion because of the last part of your comment that I didn't completely understand initially.

c) is possible, call the resulting component from evaluate yourself: MDXContent(props) instead . See: mdx-js/mdx#1655

I had a performance problem with <iframe /> elements reloading on every change when I called <MDXContent>. I notice that when I call MDXContent(), the iframes no longer reload. So React diffing magic is actually working here. Good news 😄

How can I pass components into the output? Previously you could do <MDXContent components={MDXComponents} />. Would I need to use a provider from @mdx-js/mdx?

I read through the issue and tried MDXContent({ components }) along with MDXContent(props) but couldn't get either to work.

shimamooo commented 3 years ago

Nevermind, found it. MDXContent({ components: MDXComponents })