3b1b / 3Blue1Brown.com

https://www.3blue1brown.com
Other
360 stars 138 forks source link

Comparing MDX Options #91

Open PullJosh opened 3 years ago

PullJosh commented 3 years ago

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 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:

3b1b commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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