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

Comparing MDX Options #91

Open
PullJosh opened this issue Jun 17, 2021 · 5 comments
Open

Comparing MDX Options #91

PullJosh opened this issue Jun 17, 2021 · 5 comments

Comments

@PullJosh
Copy link
Collaborator

PullJosh commented Jun 17, 2021

There are a lot of different ways to use MDX files within Next.js. All of them have pros and cons. (We are currently pursuing next-mdx-remote with the final option listed under the header below. After typing up this list of pros and cons, mdx-bundler also looks attractive.)

  • @next/mdx is built by the Next.js team, but it seems abandoned/poorly documented. It works by configuring webpack.
  • next-mdx-enhanced This library seems to do a lot of what we want, but it has a big giant warning in the readme which says to use next-mdx-remote instead, which scared us away from using it.
  • next-mdx-remote seems to be the most popular method. It works by parsing mdx files as strings.
  • mdx-bundler works by parsing mdx files and their Javascript dependencies (such as one-off interactive components) as strings.
@next/mdx next-mdx-remote mdx-bundler
Allows providing a default set of components automatically?
Allows importing one-off components within .mdx file? ❌ * see below
Allows markdown to live alongside assets (images/videos)?
Allows easy parsing of frontmatter?
Supports hot-reloading on save? Maybe? Maybe?
Does not require explicitly setting page layout for every lesson?

* Handling one-off components (like interactives)

Many components are shared between almost all lessons, and it is totally reasonable to always load their source code when viewing a lesson.

But other components, such as the special interactive elements, are only used occasionally, perhaps in one or two lessons. We need a way to include those one-off components on the pages where they're used, but not include them when they aren't.

Some tools allow importing those components directly from the .mdx file (see row 2 of the table), but even when that isn't an option, there are alternatives available:

  • Provide all components to all lessons, but lazy-load the components that are used infrequently. This requires maintaining a list of components that might be used in a separate place from where they are actually being defined and used. So maintenance is a bit of a pain, but initial setup is very straightforward.
  • Whatever this thing Vince and I came up with is:
    <ImportComponent src="./NeuralNetworkSimulator">
      {(NeuralNetworkSimulator) => (
         <NeuralNetworkSimulator showAnimation={true} {/* ...etc */} />
      )}
    </ImportComponent>
    We are yet to try it, but if it works it would be a nice editing experience.
@3b1b
Copy link
Owner

3b1b commented Jun 18, 2021

Provide all components to all lessons, but lazy-load the components that are used infrequently. This requires maintaining a list of components that might be used in a separate place from where they are actually being defined and used. So maintenance is a bit of a pain, but initial setup is very straightforward.

To my taste, this option actually seems pretty good. I think the maintenance cost is actually pretty minimal since it's just a list where you put something once while making the component. It also means that the markdown for the article can be totally agnostic to whether the components it uses are special or not. This feels like a nice conceptual separation between content and code, whereas having import statements feels like a little leakage between the two (admittedly a small amount).

@vincerubinetti
Copy link
Collaborator

I would recommend against a separate list. As the website grows bigger and more complex, it will be harder remember than you have to also update some random file somewhere else in order for your interactive to work. It also may be a pain to lazy load these components.

My upcoming PR has the above ImportComponent solution, which hopefully works when the site is actually built and not running in dev mode. I also think this component somewhat makes sense because we'll probably want a consistent wrapper for all of the interactives.

All of that said, I think mdx-bundler should be very strongly investigated in the near future to see if it simplifies things in pages.js and elsewhere. I also think importing right in the MDX, assuming that they're truly one-off components, makes the most sense. Co-located, simple, and no need for dynamic importing; everything handled at compile time.

@PullJosh
Copy link
Collaborator Author

All of that said, I think mdx-bundler should be very strongly investigated in the near future

I agree. There's a good chance that mdx-bundler turns out to be the right tool for the job, that makes all the discussion about handling one-off components totally unnecessary. I will probably look into it more soon.

@PullJosh PullJosh self-assigned this Jun 22, 2021
@PullJosh
Copy link
Collaborator Author

Trying out mdx-bundler. The first roadblock is this error, where backslashes in math expressions cause issues:

 > __mdx_bundler_fake_dir__/_mdx_bundler_entry_point.mdx:94:40: error: [plugin: esbuild-xdm] Could not parse expression with acorn: Expecting Unicode escape sequence \uXXXX
    94 │ An example of inline math $f(x) = e^{i \pi} + sin(x)$ in the middle of a sentence.
       ╵                                         ^

The error appears whether or not I have the math plugins enabled. I don't have any solution yet; just documenting what I see.

@wooorm
Copy link

wooorm commented Jun 27, 2021

That looks like the math plugin isn’t properly enabled btw, it should work

@PullJosh PullJosh removed their assignment Jul 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants