kentcdodds / mdx-bundler

🦤 Give me MDX/TSX strings and I'll give you back a component you can render. Supports imports!
MIT License
1.78k stars 75 forks source link

How can I get fast reloading working? #49

Open leon opened 3 years ago

leon commented 3 years ago

Hi, I’ve got a question.

I got it working and the bundler works great in my next.js app. But since the content isn’t bundled by webpack anymore, it means I have to refresh the browser while I’m writing to see the changes.

Is there a way to get real-time updates while writing the mdx? Do you live with cmd + R, or is there a better way?

kentcdodds commented 3 years ago

I live with manual refresh personally.

Arcath commented 3 years ago

Like Kent I tend to just refresh the page when I want to preview the changes on the site.

I did find this in my research https://github.com/hashicorp/next-remote-watch that looks like it can do what you are after.

souporserious commented 3 years ago

+1 would love be able to utilize Fast Refresh with this library. Since it's platform agnostic, I'm assuming it would require specific integrations with bundlers like Webpack?

kentcdodds commented 3 years ago

Anyone can feel free to work on this. It's definitely not something I'll be working on personally and I also don't want to explode the scope of this package with a lot of complexity.

gchallen commented 3 years ago

I'm also interested in hot reload. Here's what I think should work without requiring changes to mdx-bundler or resorting to next-remote-watch, which looks somewhat sketchy and I think only does page refresh (slower), not hot component reload.

Essentially you want to trigger next's built-in hot reload capabilities by changing a file that exports a component somewhere that it's already watching. Starting with MDX, you can write a simple build script to output a component into the pages directory. next will take it from there. (Actually you could output your component anywhere, as long as it's imported somewhere in the pages directory...)

Unfortunately mdx-bundler doesn't output a component that you can directly dump into the pages directory, since it expects you to use getMDXComponent on the client. (Perhaps this is something that could be enable via an option? Or maybe it's already possible and I haven't figured it out yet.) So instead my prototype is currently templating the code into the sample code shown in the README, using base64 to safely pass the code through the template:

Promise.resolve().then(async () => {
  const result = await bundleMDX(mdxSource);
  const { code } = result;
  const output = `
import * as React from 'react'
import {getMDXComponent} from 'mdx-bundler/client'

const code = Buffer.from("${Buffer.from(code).toString('base64')}", 'base64').toString()

export default function Post() {
  const Component = React.useMemo(() => getMDXComponent(code), [code])
  return (
    <Component />
  )
}`;
  console.log(output);
});

At this point I have a working build script. Next step is to have it watch files using chokidar, and maybe allow MDX files to choose a template using frontmatter. So a small little bespoke build system. Not the nicest solution, but it should work. (In my case I have some additional processing I need to do on the MDX tree and frontmatter, so this makes at least a bit of sense.)

(Note that the console.log above combined with output piping causes flicker, since the file gets removed briefly before being replaced with the updated content. The solution is to use fs.writeFileSync and a command-line output with the path to output to.)

with-heart commented 3 years ago

@gchallen Excellent exploration and write-up! Thanks so much for sharing. Looking forward to playing around with your posted solution and future discoveries ❤️

gchallen commented 3 years ago

Actually you might consider just using xdm directly at this point, since next will take care of the bundling for you. xdm produces a component that you can just drop into the file without any further munging. I'm not sure how to handle frontmatter yet, but it seems doable.

souporserious commented 3 years ago

Just wanted to ping this thread for Next users. I wrote a small plugin that allows remote data (like mdx-bundler) and Fast Refresh to work together. There's an example in the repo, it should be drop-in and no changes necessary to your getStaticProps code.