mapbox / batfish

A static-site generator for React and Markdown
ISC License
126 stars 17 forks source link

Planning: Markdown support #1

Closed davidtheclark closed 7 years ago

davidtheclark commented 7 years ago

There are two kinds of Markdown support to consider: Markdown embedded in JS, and Markdown files used as pages.

Markdown embedded in JS

Looking something like this:

import md from 'some-module-name';

const text = md(`Some **markdown**`).

This would provide the flexibility we'd want to be able to use Markdown anywhere that we have extended prose.

However, we don't want to bundle a Markdown parser and send it to the browser. I think the way to do this is to build a Babel plugin that uses remark-react at compile time to transform all uses of md().

Here's an existing Babel plugin to learn from: https://github.com/threepointone/markdown-in-js

Markdown files used as pages

This is the class Jekyll format. Both Phenomic and Gatsby support it, so it should be easy to learn from their open-source code. We'd use front matter to pass props to a specified layout component.

There's a big limitation with this format: Although (I think) you could embed HTML directly into the Markdown in a document like this, you could not embed JSX and use React components. If you want to embed JSX, it makes more sense to avoid this additional level of abstraction and write the page as a (relatively simple) JS file. I think that's ok. If people need to do a minimal amount of custom styling interspersed in their prose, they can do that with HTML. If they need more, they can create a page component.

cammace commented 7 years ago

To my knowledge, Docbox implements it's own markdown parser which works fairly well (although not the easiest to read) https://github.com/tmcw/docbox/blob/master/src/components/content.js#L14.

Although (I think) you could embed HTML directly into the Markdown in a document like this

I've been including HTML inside the markdown files inside /android-docs with no issues, see the Getting Started doc for example. MarkdownIt ignores any HTML syntax when parsing the markdown files. While this works, it would be great to reduce repetition and instead, create a React component and be able to include it inside the markdown directly. Creating a page component isn't ideal in my opinion since it isn't as readable and generally consumes more time maintaining.

Another requirement for parsing the Markdown would be to allow for variables inside the docs, similar to Liquid or Handlebars. This would allow for single line changes to SDK versions. I hacked my way through this by just replacing strings if they match the keyword. This might also be a solution for including react components directly inside the markdown?

danswick commented 7 years ago

Per @cammace's comment, should templating be its own planning issue?

davidtheclark commented 7 years ago

@danswick: Can you say more about what you mean by "templating"?

cammace commented 7 years ago

I think @danswick's referring to the Liquid syntax Jekyll offers, https://jekyllrb.com/docs/templates/

danswick commented 7 years ago

@davidtheclark: I was thinking something similar to Jekyll's approach to working with template layouts and includes, as @cammace said above. I suspect much of this will be taken care of with components, but I'm not totally clear on how components will work as a replacement. Is the goal of Batfish to replicate the functionality of tools like Jekyll to let authors define page templates ahead of time, then specify which of those templates should be applied to the content they write?

davidtheclark commented 7 years ago

Yesterday I spent a bunch of time investigating Markdown possibilities. I'll write down some thoughts before they vanish into the ether.

I'm seeing 3 different ways we could support Markdown. Maybe we should try all 3.

Markdown documents without JSX or expressions, with front-matter

This is easy to do. This is what Gatsby provides (and Phonemic). It involves a very short and simple Webpack loader — we could even use Gatsby's.

Advantages

Disadvantages

Because this would be so easy to implement, we might consider implementing it in addition to other techniques that allow for more complications in the Markdown.

Compile-time Markdown component

A JSX Markdown component that takes effect at compile time, as a Babel plugin, instead of runtime. Use it to wrap markdown, either as blocks or inline. babel-plugin-jsx-markdown, we could call it.

Examples:

<Markdown>
  ## Heading 2

  Lorem ipsum **dolor** sit amet, consectetur [adipisicing](#thing) elit.

  Another paragraph.
</Markdown>
<p>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
  <Markdown inline={true}>labore _et_ dolore</Markdown> magna aliqua.
</p>

Advantages:

Disadvantages:

Prior art:

Challenges:

Enhanced Markdown documents with JS expressions and JSX

Much like Jekyll's Markdown documents, except instead of Liquid you could us JS, and instead of HTML you could insert JSX.

Here's an ideal example:

---
title: My page
description: 'I made it'
version: 4
import:
  WonderfulComponent: "../../wc"
---

## Introduction

This is **my page.** It uses Markdown.

You are looking at version {{ version }}.

<div className="mt24">
  Here's some JSX.
</div>

<WonderfulComponent works={true} />

Advantages:

Disadvantages:

Prior art:

KyleAMathews commented 7 years ago

On compile-time Markdown, there is https://github.com/threepointone/markdown-in-js

davidtheclark commented 7 years ago

I spent some time experimenting with a compile-time Markdown component. markdown-in-js is so complicated and overreaching that I'm not sure it'll be an option for us. I came out with this experiment: https://github.com/davidtheclark/babel-plugin-transform-markdown-in-jsx. The big caveat, maybe crippling for it, is that code in the Markdown (inline or block) is very dangerous, because curly braces will mess up the JSX and most code uses curly braces. The way out of that might be to suggest using a React component that accepts strings to display code.

However, the more I've thought about it, the less important I think a compile-time Markdown is. If you're writing small chunks of Markdown embedded in JSX, you could just as well write straight JSX most of the time. The real value of Markdown parsing is in Markdown documents for highly templated pages. markdown-component-loader looks good for this, and the author is active and responsive, so I think I'm going to dig deeper into that.

davidtheclark commented 7 years ago

Not happy with the way babel-plugin-transform-markdown-in-jsx is going ... too many kind of confusing caveats. I'm leaning towards https://github.com/davidtheclark/md-jsx-transform as the solution.

davidtheclark commented 7 years ago

Somewhat related to this, in the sense of creating tools that help writers of pages without adding to the page bundle ... I learned more about Babel plugins last night by working on https://github.com/davidtheclark/babel-plugin-transform-syntax-highlight. I think this is working well, and code be a good way to get syntax highlighting when you're not using a Markdown document.

davidtheclark commented 7 years ago

I made https://github.com/mapbox/md-react-transformer and a Webpack loader for it, https://github.com/mapbox/md-react-transformer-loader.

Next week I'll try to incorporate the loader into Batfish.

davidtheclark commented 7 years ago

Markdown support is in, with https://github.com/mapbox/jsxtreme-markdown.