Join the conversation

Sign in to join this conversation, and others like it, in the communities you care about.

Frontend Cafe

A community for discussing frontend engineering news, best practices, and new technologies.

Frontend Cafe / General

.mdx proposal

.mdx proposal

Frontend Cafe / General · February 9, 2018 at 5:43pm
For a while now at ZEIT we've been using markdown-in-js as a pre-processor with Babel, so that we can write static documents more practically.
In practice, our pages end up looking something like this:
import * as components from './components/text' import Video from ./components/video' export markdown(components)` # hello there \`\`\` My code snippet ${<Image />} \`\`\` `
In addition to letting us quickly write markdown, it has some really powerful benefits:
  • It's still JS, which means we can do imports, define helpers, assert that it's valid via a linter, etc.
  • We can embed JSX components inside Markdown. This is a must for us, because we like writing blog posts (https://zeit.co/blog) that have diverse content inside.
However, in my opinion, a lot of the benefits of "writing markdown" are lost. For example, as you see above, escaping code blocks becomes cumbersome.
As a result, I've been playing with an idea in my mind for a potential custom webpack loader and a new format called mdx, which brings the "best of both worlds" of JSX and Markdown.
Imagine my-blog-post.mdx:
import Video from '../components/video' # My blog post ``` my code! ``` And here's a video: <Video width={300} src="video.mp4" />
This looks great IMO, however, some important problems remain:
  • How do we lint? It should be impossible to include <Vid> because it's not imported, but <Video> should work. Can we extend eslint to understand .mdx ?
  • How do we defined the default set of components? One option would be to pass them to the webpack loader configuration
  • How do we override one component? Let's say we want to use a custom paragraph renderer. An idea here would be to standarize on a series of names, so that you can just do import P from '../components/paragraph'
  • How do we prettify it? Another issue we have with our markdown pages is that the markdown inside ends up looking really ugly, unless you painstakingly format it by hand. Can we extend prettier to understand .mdx?
If someone in the community wants to start playing around with a prototype, please share!

February 9, 2018 at 5:51pm

I need this so badly, pleeease

like-fill
1
  • reply
  • like

I've wanted this kind of thing a million times!

like-fill
8
  • reply
  • like
👏🏼👏🏼👏🏼
  • reply
  • like

This is a really neat idea, I'd love to see an implementation.

  • reply
  • like

This lines up really nicely with recent work on Gatsby: https://github.com/gatsbyjs/gatsby/issues/312

like-fill
2
  • reply
  • like

We've definitely been experimenting with some similar things. For the imports, I like the idea of allowing imports/props/etc to be set with front matter in the markdown

like-fill
1
  • reply
  • like

I've gone ahead and open sourced our current experiment with a markdown implementation along the same lines of this proposal: https://github.com/c8r/markdown It's a bit different because we've been experimenting more with `.jsx` code blocks and front matter to handle the JSX/React specific functionality. Though it allows for passing in components that are rendered in place of html elements during the transpilation process. Using mdast/remark and based of remark-react.

like-fill
2
  • reply
  • like

What's nice about targeting `.jsx` code blocks is that editors/GitHub will syntax highlight, and a linter could quickly discern what is markdown and what is JSX. Though it's also not quite as expressive as inlined JSX in the document.

  • reply
  • like

I would love to see this somewhat standardized in the community as .mdx. I've had to do it multiple times for different design systems' documentation, etc.

like-fill
3
  • reply
  • like

Yeah, this is definitely a problem that most teams run into. Having a standardized specification with surrounding community built tooling will help us arrive at the best solution.

  • reply
  • like

Of course @jxnblk and @johno have already built something, why am I not surprised? 😉 Going to dig into that for the styled-components website, /cc @philpl

like-fill
1
  • reply
  • like

I think the proper extension of markdown to allow custom React components to be embedded warrants the special syntax. Reasons for this are:

* We need both *block* level and *inline* level markup constructs for custom components. This is mainly due to how markdown markup is structured — I think you'd need this distinction to allow markdown and React components to be interleaved (e.g. pass some markdown to a React component as `children`).

* JSX (XML-like syntax) is too heavyweight to be embedded into markdown. I figured out you'd want to use such custom components often (there are a lot of use cases for them and not just for some ad-hoc uses).

I'v created a PoC quiet a while ago — https://andreypopp.github.io/reactdown (**warning:** it's not maintained) which exercises the points above by introducing a special syntax for block level and inline level constructs.

Block level constructs called **directives** look like this — https://raw.githubusercontent.com/andreypopp/reactdown/master/src/parse/__tests__/directive-fixture/with-data-children.md

Inline level constructs called **roles** — https://raw.githubusercontent.com/andreypopp/reactdown/master/src/parse/__tests__/role-fixture/multi.md

Reactdown isn't ready and is super alpha and outdated software, be warned. But I believe the idea is sound. :-)

like-fill
1
  • reply
  • like

I've built something similar in the past and also overrode code blocks to allow them to execute. I liked the proposed style but the code blocks got highlighting for free. And allowed for running arbitrary js.

  • reply
  • like

@rauchg goes without saying that we’d need to make it agnostic of render target, but imagine how great this would be for writing transactional emails

like-fill
7
  • reply
  • like

I'm not sure you guys aware of this: https://github.com/jamesknelson/mdxc

like-fill
1
  • reply
  • like

It's awesome. I'm refactoring my blog to use it

  • reply
  • like

mdxc is used in https://reactarmory.com/ for making interactive articles

  • reply
  • like

@mxstbr It's definitely still an experiment, but we are consuming it as a library for some of our other experiments : )

  • reply
  • like

It's really cool to see all these awesome projects in this area. Definitely shows that there's a need and @rauchg is onto something with a formalized proposal. I'd personally love to see (and happy to help work on) some type of specification with standardized tools to blend markdown and JSX into a .mdx format.

  • reply
  • like

This is a great idea! People have been wanting to do this for a while for Gatsby and just last week a contributor merged a PR adding support for this using rehype:

https://using-remark.gatsbyjs.org/custom-components/

like-fill
1
  • reply
  • like

Could you adjust the syntax like this to make it compatible with other frameworks/languages in the future?

  • reply
  • like
  • reply
  • like

February 9, 2018 at 10:53pm

I prefer the original proposal. It's tempting to want to use fenced code blocks, but they add viewing and editing overhead beyond what markdown already has, with its inline HTML support. I think the popularity of next and styled-components despite needing editor plugins (also jsx in the early days) shows that iterating on the language is feasible. My only suggestion is adding a jsx tag for import so it's `<import Video="../components/video" />` or something.

like-fill
1
  • reply
  • like

Wow, https://github.com/jamesknelson/mdxc is quite similar to this proposal! Even the import syntax is the same.

like-fill
2
  • reply
  • like
like-fill
1
  • reply
  • like
Your message here...

*bold*_italic_`code````codeblock```