1
1
mirror of https://github.com/mdx-js/mdx.git synced 2024-08-16 18:30:27 +03:00

New and improved docs, with a website (#198)

* Begin adding more involved docs

* Begin docs site

* Bump deps

* Continue with possible docs structure

* Improve docs

* Add md and jsx syntax links

* Add live editor for MDX in docs

* Ensure classname is set

* Add more docs and a deploy script

* Tweak docs index page wording

* Add an advanced section

* Change order of pages

* Improve component docs

* Add logo

* Begin adding now config for docs deploy

* Fix now config

* Remove travis based now build

* Add dockerfile for site building

* Don't run prepare scripts

* mdx docs and pointer to gatsby-mdx (#200)

* Reorganize docs

* Fix typo

* Clean up app file

* More docs organization

* Add WIP labels to WIP sections

* Add sync api docs

* Add MDX deck link

* Implement option to opt out of export wrapper (#209)

In certain cases, like mdx-js/runtime or mdx-deck
we want to avoid the wrapping export default so that
it doesn't need to be manually stripped off.

* v0.15.0-2

* Update readme to reflect new docs

* Add license link

* Add link to vid in docs
This commit is contained in:
John Otander 2018-08-11 07:05:40 -06:00 committed by GitHub
parent e61b567ac0
commit d4154b8c4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1035 additions and 341 deletions

1
.npmrc Normal file
View File

@ -0,0 +1 @@
package-lock=false

9
Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM mhart/alpine-node
WORKDIR /usr/src
COPY package.json .
RUN npm i --ignore-scripts
COPY . .
RUN npm run docs:build && mv dist /public

82
docs/_app.js Normal file
View File

@ -0,0 +1,82 @@
import React from 'react'
import RebassMDX from '@rebass/mdx'
import createScope from '@rebass/markdown'
import * as Rebass from 'rebass'
import sortBy from 'lodash.sortby'
import { SidebarLayout, ScopeProvider } from '@compositor/x0/components'
import { LiveEditor, Logo } from './_ui'
const scope = { ...createScope(), ...Rebass, code: LiveEditor, pre: ({ children }) => children }
const navOrder = [
'index',
'syntax',
'getting-started',
'webpack',
'parcel',
'next',
'create-react-app',
'gatsby',
'x0',
'typescript',
'plugins',
'advanced',
'ast',
'components',
'writing-a-plugin',
'custom-loader',
'specification',
'sync-api',
'runtime',
'contributing',
'projects',
'about'
]
const pageNames = {
index: 'Introduction',
next: 'Next.js',
ast: 'AST',
projects: 'Projects Using MDX',
'getting-started': 'Getting Started',
'create-react-app': 'Create React App',
'writing-a-plugin': 'Writing a Plugin',
'sync-api': 'Sync API'
}
const sortRoutes = routes => [
...sortBy([...routes], a => {
const i = navOrder.indexOf(a.name)
return i < 0 ? Infinity : i
})
].map(route => {
if (!pageNames[route.name]) return route
return {
...route,
name: pageNames[route.name]
}
})
export default class App extends React.Component {
static defaultProps = {
title: 'MDX'
}
render () {
const { routes } = this.props
const nav = sortRoutes(routes)
return (
<RebassMDX>
<ScopeProvider scope={scope}>
<SidebarLayout
{...this.props}
logo={<Logo />}
routes={nav}
/>
</ScopeProvider>
</RebassMDX>
)
}
}

38
docs/_ui.js Normal file
View File

@ -0,0 +1,38 @@
import React from 'react'
import { Pre, Box, Border } from 'rebass'
import { LiveEditor as Editor, LivePreview } from '@compositor/x0/components'
export const Logo = () => <img src="https://mdx-logo.now.sh" width="70" />
export const LiveEditor = props => {
const lang = (props.className || '').replace(/^language\-/, '')
const type = lang.charAt(0)
const code = React.Children.toArray(props.children).join('\n')
switch (type) {
case '.':
return (
<Editor
mdx={lang === '.mdx'}
code={code}
/>
)
case '!':
return (
<LivePreview
mdx={lang === '!mdx'}
code={code}
/>
)
default:
return (
<Pre
p={3}
mt={4}
mb={4}
bg='gray'
children={props.children}
/>
)
}
}

54
docs/about.md Normal file
View File

@ -0,0 +1,54 @@
import { Avatar } from 'rebass'
# About
MDX is based on the [original `.mdx` proposal](https://spectrum.chat/thread/1021be59-2738-4511-aceb-c66921050b9a) by Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)).
## Design
[Logo designs](https://github.com/mdx-js/design) were created by [Evil Rabbit](https://twitter.com/evilrabbit_) of [ZEIT](https://zeit.co).
[See logo resources](https://github.com/mdx-js/design)
## Authors
- [John Otander](https://johno.com) ([@4lpine](https://twitter.com/4lpine)) [Compositor](https://compositor.io) + [Clearbit](https://clearbit.com)
- Tim Neutkens ([@timneutkens](https://github.com/timneutkens)) [ZEIT](https://zeit.co)
- [Guillermo Rauch](https://rauchg.com) ([@rauchg](https://twitter.com/rauchg)) [ZEIT](https://zeit.co)
- [Brent Jackson](https://jxnblk.com) ([@jxnblk](https://twitter.com/jxnblk)) [Compositor](https://compositor.io)
## Related
The following projects, languages, and articles helped to shape MDX either in implementation or inspiration.
### Syntax
These projects define the syntax which MDX blends together (MD and JSX).
- [Markdown](https://daringfireball.net/projects/markdown/syntax)
- [JSX](https://reactjs.org/docs/introducing-jsx.html)
- [React](https://reactjs.org/)
### Parsing and implementation
- [Remark](http://remark.js.org)
- [Unified](https://github.com/unifiedjs/unified)
- [Webpack](https://webpack.js.org)
- [Parcel](https://parceljs.com)
### Libraries
- [MDXC](https://github.com/jamesknelson/mdxc)
- [Markdown Component Loader](https://github.com/ticky/markdown-component-loader)
- [markdown-in-js](https://github.com/threepointone/markdown-in-js)
- [remark-jsx](https://github.com/fazouane-marouane/remark-jsx)
- [remark-react](https://github.com/mapbox/remark-react)
### Other
- [IA Markdown Content Blocks](https://github.com/iainc/Markdown-Content-Blocks)
- [Idyll: Markup language for interactive documents](https://idyll-lang.org)
### Is your work missing?
If you have related work or prior art we've failed to reference, please open a PR!

118
docs/advanced/ast.md Normal file
View File

@ -0,0 +1,118 @@
# AST
The majority of the MDXAST specification is defined by [MDAST][].
MDXAST is a superset of MDAST, with three additional node types:
- `jsx` (in place of `html`)
- `import`
- `export`
It's also important to note that an MDX document that contains no JSX or imports is a valid MDAST.
### Differences to MDAST
The `import` type is used to provide the necessary block elements to the Remark HTML block parser and for the execution context/implementation.
For example, a webpack [loader][] might want to transform an MDX import by appending those imports.
An `export` is used to emit data from MDX, similarly to traditional markdown frontmatter.
The `jsx` node would most likely be passed to Babel to create functions.
This will also differ a bit in parsing because the remark parser is built to handle particular HTML element types, whereas JSX support will require the ability to parse any tag, and those that self close.
The `jsx`, `import`, and `export` node types are defined below.
#### JSX
The `JSX` ([`ElementNode`](#elementnode)) which contains embedded JSX as a string and `children` ([`ElementNode`](#elementnode)).
```idl
interface JSX <: Element {
type: "jsx";
value: "string";
children: [ElementNode]
}
```
For example, the following MDX:
```jsx
<Heading hi='there'>
Hello, world!
</Heading>
```
Yields:
```json
{
"type": "jsx",
"value": "<Heading hi='there'>\n Hello, world!\n</Heading>"
}
```
#### Import
The `import` ([`Textnode`](#textnode)) contains the raw import as a string.
```idl
interface JSX <: Text {
type: "import";
}
```
For example, the following MDX:
```md
import Video from '../components/Video'
```
Yields:
```json
{
"type": "import",
"value": "import Video from '../components/Video'"
}
```
#### Export
The `export` ([`Textnode`](#textnode)) contains the raw export as a string.
```idl
interface JSX <: Text {
type: "export";
}
```
For example, the following MDX:
```md
export { foo: 'bar' }
```
Yields:
```json
{
"type": "export",
"value": "export { foo: 'bar' }"
}
```
## MDXHAST
The majority of the MDXHAST specification is defined by [HAST][].
MDXHAST is a superset of HAST, with four additional node types:
- `jsx`
- `import`
- `export`
- `inlineCode`
It's also important to note that an MDX document that contains no JSX or imports results in a valid HAST.
[MDAST]: https://github.com/syntax-tree/mdast
[HAST]: https://github.com/syntax-tree/hast
[loader]: https://github.com/mdx-js/mdx/tree/master/packages/loader

View File

@ -0,0 +1,41 @@
# Components
The MDX core library accepts a string and exports a JSX string.
## MDXTag
MDXTag is an internal component that MDX uses to map components to an HTML element based on the Markdown syntax.
Consider the following MDX:
```
import MyComponent from './my-component'
# Title
<MyComponent />
Lorem ipsum dolor sit amet.
```
MDX core turns that text into the following JSX to be consumed by your app:
```jsx
import React from 'react'
import { MDXTag } from '@mdx-js/tag'
import MyComponent from './my-component'
export default ({ components }) => (
<MDXTag name="wrapper" components={components}>
<MDXTag name="h1" components={components}>
Title
</MDXTag>
<MyComponent />
<MDXTag name="p" components={components}>
Lorem ipsum dolor sit amet.
</MDXTag>
</MDXTag>
)
```
If the component mapping contains a `p` key, that will be used for "Lorem ipsum dolor sit amet.", otherwise a standard `p` tag is rendered (`<p>Lorem ipsum dolor sit amet.</p>`).
This is what allows you to pull in existing components to style your MDX documents.

View File

@ -0,0 +1,20 @@
# Contributing
:pray: Thanks in advance for your contribution!
To get started, after cloning the repo:
```
npm i
npm t
```
## Project structure
MDX is a monorepo that uses [lerna][].
- All packages are found in `./packages`
- All documentation is found in `./docs` and can be viewed with `npm run docs -- -o`
- There's an `./examples` directory where examples for different tools and frameworks
[lerna]: https://lernajs.io

View File

@ -0,0 +1,7 @@
import { Message } from 'rebass'
# Custom loader
<Message>
This docs page is a WIP
</Message>

7
docs/advanced/index.md Normal file
View File

@ -0,0 +1,7 @@
import { Message } from 'rebass'
# Advanced
<Message>
This docs page is a WIP
</Message>

3
docs/advanced/runtime.md Normal file
View File

@ -0,0 +1,3 @@
import Doc from '../../packages/runtime/readme.md'
<Doc />

View File

@ -0,0 +1,11 @@
# MDX Specification
MDX includes a [specification][spec] to define the syntax and transpilation.
This can be leveraged by code formatters, linters, and implementations in other languages created by the community.
It's based on the [remark][remark]/[unist][unist] ecosystem to ensure robust parsing and the ability to leverage plugins from within your MDX.
[See the specification][spec]
[spec]: https://github.com/mdx-js/specification
[remark]: https://github.com/remarkjs
[unified]: https://github.com/unifiedjs

23
docs/advanced/sync-api.md Normal file
View File

@ -0,0 +1,23 @@
import { Message } from 'rebass'
# Sync API
MDX processes everything asynchronously by default.
In certain cases this behavior might not be desirable.
If you're using the MDX library directly, you might want to process an MDX string synchronously.
It's important to note that if you have any async plugins, they will be ignored.
```js
const fs = require('fs')
const mdx = require('@mdx-js/mdx')
const mdxText = fs.readFileSynx('hello.mdx', 'utf8')
const jsx = mdx.sync(mdxText)
```
MDX's [runtime][] package has [example][] usage.
[runtime]: https://github.com/mdx-js/mdx/tree/master/packages/runtime
[example]: https://github.com/mdx-js/mdx/blob/d5a5189e715dc28370de13f6cc0fd18a06f0f122/packages/runtime/src/index.js#L16-L18

View File

@ -0,0 +1,7 @@
import { Message } from 'rebass'
# Writing a plugin
<Message>
This docs page is a WIP
</Message>

View File

@ -0,0 +1,41 @@
import { Message } from 'rebass'
# Create React App
<Message>
This docs page is a WIP
</Message>
With Create React App you will need to use [`create-react-app-rewired`][cra-rewired] and add a `config-overrides.js`.
```js
const { getBabelLoader } = require('react-app-rewired')
module.exports = (config, env) => {
const babelLoader = getBabelLoader(config.module.rules)
config.module.rules.map(rule => {
if (typeof rule.test !== 'undefined' || typeof rule.oneOf === 'undefined') {
return rule
}
rule.oneOf.unshift({
test: /\.mdx$/,
use: [
{
loader: babelLoader.loader,
options: babelLoader.options
},
'@mdx-js/loader'
]
})
return rule
})
return config
}
```
[See the full example][cra-example]
[cra]: https://github.com/facebook/create-react-app
[cra-rewired]: https://github.com/timarney/react-app-rewired
[cra-example]: https://github.com/mdx-js/mdx/tree/master/examples/create-react-app

View File

@ -0,0 +1,35 @@
# Gatsby
In order to use MDX with [Gatsby][gatsby] you can use the [gatsby-mdx][] package.
First scaffold a new Gatsby 2.0 or greater site and install the `gatsby-mdx` plugin.
```shell
gatsby new gatsby-site https://github.com/gatsbyjs/gatsby-starter-default#v2
cd gatsby-site
yarn add gatsby-mdx @mdx-js/mdx
```
Then add `gatsby-mdx` to your `gatsby-config.js` in the `plugins` section.
```javascript
module.exports = {
siteMetadata: {
title: `My Ambitious Project`
},
plugins: [`gatsby-mdx`]
};
```
Finally, add an `.mdx` file in the `src/pages` directory. It "Just Works".
```
# My first MDX Page
some awesome content
```
For more documentation on programmatically creating pages with Gatsby, see the [gatsby-mdx docs][gatsby-mdx]
[gatsby]: https://gatsbyjs.org
[gatsby-mdx]: https://github.com/ChristopherBiscardi/gatsby-mdx

View File

@ -0,0 +1,84 @@
import { Text } from 'rebass'
# Getting Started
To get started quickly with an example project you can use `npm init`.
It will scaffold out a [Next.js][next] app with MDX configured.
```
npm init mdx
```
<Text color="darkgray" mt={-3} mb={4}>
Note: MDX requires a version of node that is >= v8.5 and React 16.0+
</Text>
## Components
You can pass in components for any HTML element that Markdown compiles to.
This allows you to use your existing components and even CSS-in-JS like `styled-components`.
```jsx
import React from 'react'
import Hello from '../hello.md'
import {
Text,
Heading,
Code,
InlineCode
} from '../ui'
export default () =>
<Hello
components={{
h1: Heading,
p: Text,
code: Code,
inlineCode: InlineCode
}}
/>
```
With the above, the Heading component will be rendered for any h1, Text for p tags, and so on.
In addition to HTML elements, there's an `inlineCode`.
This is what remark uses for code elements within paragraphs, tables, etc.
## MDXProvider
If you're using an app layout that wraps your JSX, you can use the `MDXProvider` to only pass your components in one place:
```jsx
import React from 'react'
import { MDXProvider } from '@mdx-js/tag'
import * as components from './markdown-components'
export default props =>
<MDXProvider components={components}>
<main {...props} />
</MDXProvider>
```
This allows you to remove duplicated component imports and passing.
It will typically go in layout files.
#### How does it work?
MDXProvider uses React [context][] to provide the component mapping to MDXTag.
MDXTag knows to use these components when determining which to render.
## Projects, libraries and frameworks
If you're already working with a particular tool, you can try out MDX with the following commands:
- `npm init mdx` [`webpack`](./webpack)
- `npm init mdx` [`parcel`](./parcel)
- `npm init mdx` [`next`](./next)
- `npm init mdx` [`create-react-app`](./create-react-app)
- `npm init mdx` [`gatsby`](./gatsby)
- `npm init mdx` [`x0`](./x0)
[next]: https://github.com/zeit/next.js
[context]: https://reactjs.org/docs/context.html

View File

@ -0,0 +1,31 @@
# Next.js
Next.js provides an [official plugin][next-plugin] to simplify MDX importing into your project.
```
npm install --save-dev @zeit/next-mdx
```
To configure MDX, add the following to your `next.config.js`:
```js
const withMDX = require('@zeit/next-mdx')()
module.exports = withMDX()
```
### Use MDX for `.md` files
The Next.js MDX plugin allows for you to also use MDX parsing for `.md` files:
```js
const withMDX = require('@zeit/next-mdx')({
extension: /\.mdx?$/
})
module.exports = withMDX({
pageExtensions: ['js', 'jsx', 'md', 'mdx']
})
```
[next-plugin]: https://github.com/zeit/next-plugins/tree/master/packages/next-mdx

View File

@ -0,0 +1,26 @@
import { Message } from 'rebass'
# Parcel
<Message>
This docs page is a WIP
</Message>
You'll need to install the `@mdx-js/parcel-plugin-mdx` plugin to transpile MDX.
```js
{
"scripts": {
"start": "parcel index.html --no-cache"
},
"dependencies": {
"react": "16.4.1",
"react-dom": "16.4.1",
"@mdx-js/tag": "@mdx-js/tag"
},
"devDependencies": {
"@mdx-js/parcel-plugin-mdx": "@mdx-js/parcel-plugin-mdx",
"parcel-bundler": "1.9.0"
}
}
```

View File

@ -0,0 +1,11 @@
# TypeScript
If you're getting errors from TypeScript related to imports with an `*.mdx` extension, create an `mdx.d.ts` file in your types directory and include inside your `tsconfig.json`
```
// types/mdx.d.ts
declare module '*.mdx' {
let MDXComponent: (props) => JSX.Element;
export default MDXComponent;
}
```

View File

@ -0,0 +1,26 @@
import { Message } from 'rebass'
# Webpack
<Message>
This docs page is a WIP
</Message>
## Basic Setup
MDX provides a loader that needs to be used in tandem with the [babel-loader][babel-loader].
For webpack projects you can define the following `webpack.config.js`:
```js
module.exports = {
module: {
rules: [
{
test: /\.mdx?$/,
use: ['babel-loader', '@mdx-js/loader']
}
]
}
}
```

View File

@ -0,0 +1,27 @@
import { Message } from 'rebass'
# x0
<Message>
This docs page is a WIP
</Message>
[x0][] supports MDX files with either `.md` or `.mdx` file extensions out of the box, but you will need to use the component provider in `_app.js`. Here's an example using [Rebass][rebass] components:
```jsx
import React from 'react'
import * as Rebass from 'rebass'
import createScope from '@rebass/markdown'
import { ScopeProvider } from '@compositor/x0/components'
export default ({ route, routes, ...props }) => (
<ScopeProvider scope={{ ...Rebass, ...createScope() }}>
<Rebass.Provider>
<Rebass.Box p={[2, 4, 4]} {...props} />
</Rebass.Provider>
</ScopeProvider>
)
```
[x0]: https://compositor.io/x0
[rebass]: https://jxnblk.com/rebass

56
docs/index.md Normal file
View File

@ -0,0 +1,56 @@
import { Border, Blockquote, BlockLink } from 'rebass'
# MDX
MDX enables you to seamlessly use JSX in your Markdown documents.
This makes writing long-form content with components a blast.
__:heart: Powerful__: MDX makes it effortless to import and render components in your React/JSX-based projects.
__:computer: Component-based__: Use existing JSX components inside your MDX, and import MDX files as plain components.
__:fire: Blazingly blazing fast__: MDX has no runtime, all compilation occurs during the build stage.
> “It's extremely useful for using design system components to render markdown
and weaving interactive components in with existing markdown.”
>
> — [@chrisbiscardi](https://twitter.com/chrisbiscardi/status/1022304288326864896)
## Why?
Before MDX, some of the benefits of writing Markdown were lost when integrating with JSX.
Implementations were often template string-based which required lots of escaping and cumbersome syntax.
MDX seeks to make writing with Markdown _and_ JSX simpler while being more expressive.
The possibilities are endless when you combine components (that can even be dynamic or load data) with the simplicity of Markdown for long-form content.
## Features
- Fast
- No runtime compilation
- [Pluggable][remark-plugins]
- Element to React component mapping
- React component `import`/`export`
- Customizable layouts
- Webpack loader
- Parcel plugin
- Next.js plugin
- Gatsby plugin
> [Watch some of these features in action](https://www.youtube.com/watch?v=d2sQiI5NFAM&list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u)
## Try it
```.mdx
# Hello, world!
Here's an example of the [Rebass][] Donut rendered inside an MDX document.
<Donut value={2/3} />
[Rebass]: https://jxnblk.com/rebass
```
[md]: http://commonmark.org/
[jsx]: https://facebook.github.io/jsx/
[remark-plugins]: https://github.com/remarkjs/remark/blob/master/doc/plugins.md

82
docs/plugins.md Normal file
View File

@ -0,0 +1,82 @@
# Plugins
Since MDX uses the [remark][]/[rehype][] ecosystems, you can use plugins to modify the AST at different stages of the transpilation process.
## Transpilation
The MDX transpilation flow consists of six steps, ultimately resulting in JSX that can be used in React/Preact/etc.
1. __Parse__: Text => MDAST
1. __Transpile__: MDAST => MDXAST
1. __Transform__: MDX/Remark plugins applied to AST
1. __Transpile__: MDXAST => MDXHAST
1. __Transform__: Hyperscript plugins applied to AST
1. __Transpile__: MDXHAST => JSX
### Options
Name | Type | Required | Description
---- | ---- | -------- | -----------
`mdPlugins` | Array[] | `false` | Array of remark plugins to manipulate the MDAST
`hastPlugins` | Array[] | `false` | Array of rehype plugins to manipulate the MDXHAST
#### Specifying plugins
Plugins need to be passed to MDX core library, this is often as options to your loader:
```js
const images = require('remark-images')
const emoji = require('remark-emoji')
module.exports = {
module: {
rules: [
{
test: /\.mdx?$/,
use: [
{
loader: 'babel-loader'
},
{
loader: '@mdx-js/loader',
options: {
mdPlugins: [images, emoji]
}
}
]
}
]
}
}
```
Though if you're using MDX directly, they can be passed like so:
```js
const fs = require('fs')
const mdx = require('@mdx-js/mdx')
const images = require('remark-images')
const emoji = require('remark-emoji')
const mdxText = fs.readFileSync('hello.mdx', 'utf8')
const jsx = mdx.sync(mdxText, {
mdPlugins: [images, emoji]
})
```
#### Plugin options
If a plugin needs specific options, use the `[plugin, pluginOptions]` syntax.
```js
mdx.sync(mdxText, {
mdPlugins: [
images,
[emoji, { padSpaceAfter: true }]
})
```
The following example ensures that `padSpaceAfter` is only passed as options to the `emoji` plugin.
[remark]: https://github.com/remarkjs/remark
[rehype]: https://github.com/rehypejs/rehype

16
docs/projects.md Normal file
View File

@ -0,0 +1,16 @@
# Projects using MDX
- [ok-mdx][]: Browser-based MDX editor
- [docz][]: Documentation framework
- [mdx-deck][]: MDX-based presentation decks
## Sites using MDX
- [ZEIT Docs][zeit-docs]
- [Compositor][compositor]
[ok-mdx]: https://github.com/jxnblk/ok-mdx
[mdx-deck]: https://github.com/jxnblk/mdx-deck
[docz]: https://www.docz.site/
[zeit-docs]: https://github.com/zeit/docs
[compositor]: https://compositor.io

125
docs/syntax.md Normal file
View File

@ -0,0 +1,125 @@
# Syntax
MDX syntax can be boiled down to being JSX in Markdown.
It's a superset of Markdown syntax that also support importing, exporting, and JSX blocks.
### Markdown
Standard [Markdown syntax][md] is supported.
### JSX
[JSX syntax][jsx] is fully supported, JSX blocks are opened by starting a line with the `<` character.
```jsx
<Box>
<Heading>Here's a JSX block</Heading>
<Text>It's pretty neat</Text>
</Box>
```
### Imports
Imports can be used to [import][] components into the scope and later rendered:
```jsx
import Graph from './components/graph'
## Here's a graph
<Graph />
```
You can also import data that you want to display in a JSX block:
```jsx
import { colors } from './theme'
import Palette from './components/palette'
# Colors
<Palette colors={colors} />
```
#### Markdown file transclusion
You can [transclude][] Markdown files by importing one `.md` or `.mdx` file into another:
```jsx
import License from './license.md'
import Contributing from './docs/contributing.md'
# Hello, world!
<License />
---
<Contributing />
```
### Exports
You can use exports to export metadata like layout or authors.
It's a mechanism for an imported MDX file to communicate with its parent.
It works similarly to frontmatter, but uses ES2015 syntax.
```js
// posts/post.mdx
import { fred, sue } from '../data/authors'
import Layout from '../components/blog-layout'
export const meta = {
authors: [fred, sue],
layout: Layout
}
# Post about MDX
MDX is a JSX in Markdown loader, parser, and renderer for ambitious projects.
```
```jsx
// index.js
import React from 'react'
import Mdx, { meta } from 'posts/post.mdx'
const { authors, layout } = meta
export default () => (
<layout>
<Mdx />
By: {authors.map(author => author.name)}
</layout>
)
```
#### `export default`
The ES default [export][] is used to provide a layout component which will wrap the transpiled JSX.
You can export it as a function:
```jsx
import Layout from './Layout'
export default ({ children }) => <Layout some='metadata' >{children}</Layout>
# Hello, world!
```
Or directly as a component:
```jsx
import Layout from './Layout'
export default Layout
# Hello, world!
```
[md]: https://daringfireball.net/projects/markdown/syntax
[jsx]: https://reactjs.org/docs/introducing-jsx.html
[import]: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import
[export]: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
[transclude]: https://en.wikipedia.org/wiki/Transclusion

6
now.json Normal file
View File

@ -0,0 +1,6 @@
{
"name": "mdx",
"alias": "mdxjs.com",
"public": true,
"type": "static"
}

View File

@ -2,6 +2,9 @@
"private": true,
"scripts": {
"bootstrap": "lerna bootstrap",
"docs": "x0 docs",
"docs:build": "x0 build docs",
"docs:deploy": "npm run docs:build && now dist",
"test": "lerna run test",
"format": "prettier --no-semi --single-quote --write '{examples,packages}/**/*.js'",
"prepare": "lerna bootstrap && lerna link --force-local"
@ -9,7 +12,15 @@
"repository": "mdx-js/mdx",
"license": "MIT",
"devDependencies": {
"lerna": "^2.5.1",
"prettier": "^1.11.1"
"@compositor/x0": "^6.0.3",
"lerna": "^2.11.0",
"prettier": "^1.13.7"
},
"dependencies": {
"@rebass/mdx": "^1.0.0-1",
"styled-components": "^3.3.3"
},
"x0": {
"title": "MDX"
}
}

374
readme.md
View File

@ -3,360 +3,52 @@
[![Build Status](https://travis-ci.org/mdx-js/mdx.svg?branch=master)](https://travis-ci.org/mdx-js/mdx)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/mdx)
MDX is a JSX in Markdown loader, parser, and renderer for ambitious projects.
It combines the readability of Markdown with the expressivity of JSX.
The best of both worlds. :globe_with_meridians:
MDX enables you to seamlessly use JSX in your Markdown documents.
This makes writing long-form content with components a blast.
[See the MDX specification](https://github.com/mdx-js/specification)
__:heart: Powerful__: MDX makes it effortless to import and render components in your React/JSX-based projects.
## Features
__:computer: Component-based__: Use existing JSX components inside your MDX, and import MDX files as plain components.
- Fast
- No runtime compilation
- [Pluggable](https://github.com/remarkjs/remark/blob/master/doc/plugins.md)
- Element to React component mapping
- React component `import`/`export`
- Simpler image syntax
- Webpack loader
__:fire: Blazingly blazing fast__: MDX has no runtime, all compilation occurs during the build stage.
> [Watch some of these features in action](https://www.youtube.com/watch?v=d2sQiI5NFAM&list=PLV5CVI1eNcJgCrPH_e6d57KRUTiDZgs0u)
## Installation
> “It's extremely useful for using design system components to render markdown
and weaving interactive components in with existing markdown.”
>
> — [@chrisbiscardi](https://twitter.com/chrisbiscardi/status/1022304288326864896)
```sh
npm install --save-dev @mdx-js/loader @mdx-js/mdx
```
## Why?
> Note: mdx requires a version of node that is >= `v8.5`
Before MDX, some of the benefits of writing Markdown were lost when integrating with JSX.
Implementations were often template string-based which required lots of escaping and cumbersome syntax.
### Configuring with Webpack
MDX seeks to make writing with Markdown _and_ JSX simpler while being more expressive.
The possibilities are endless when you combine components (that can even be dynamic or load data) with the simplicity of Markdown for long-form content.
You'll need to specify the `@mdx-js/loader` webpack loader and follow it with the `babel-loader`:
- Fast
- No runtime compilation
- [Pluggable][remark-plugins]
- Element to React component mapping
- React component `import`/`export`
- Customizable layouts
- Webpack loader
- Parcel plugin
- Next.js plugin
- Gatsby plugin
```js
module.exports = {
module: {
rules: [
{
test: /\.md$/,
use: ['babel-loader', '@mdx-js/loader']
}
]
}
}
```
<p>
<details>
<summary><b>Examples</b></summary>
<ul>
<li>
<a href="./examples/next"><code>next.js</code></a>
</li>
<li>
<a href="./examples/x0"><code>x0</code></a>
</li>
</ul>
</details>
</p>
### Configuring with Parcel
You'll need to install the `@mdx-js/parcel-plugin-mdx` plugin to transpile MDX.
```js
{
"scripts": {
"start": "parcel index.html --no-cache"
},
"dependencies": {
"react": "16.4.1",
"react-dom": "16.4.1",
"@mdx-js/tag": "latest"
},
"devDependencies": {
"@mdx-js/parcel-plugin-mdx": "latest",
"parcel-bundler": "1.9.0"
}
}
```
<p>
<details>
<summary><b>Examples</b></summary>
<ul>
<li>
<a href="./examples/parcel"><code>Parcel</code></a>
</li>
</ul>
</details>
</p>
### Configuring TypeScript
If you're getting errors from TypeScript related to imports with an `*.mdx` extension, create an `mdx.d.ts` file in your types directory and include inside your `tsconfig.json`
## Getting started
```
// types/mdx.d.ts
declare module '*.mdx' {
let MDXComponent: (props) => JSX.Element;
export default MDXComponent;
}
npx init mdx
```
## Usage
Create an md file, `hello.md`:
```jsx
# Hello, world!
```
And import it from a component, `pages/index.js`:
```jsx
import React from 'react'
import Hello from '../hello.md'
export default () => <Hello />
```
## MDX syntax
### Imports
Similarly to JSX, components can be rendered after an `import`:
```jsx
import Graph from './components/graph'
## Here's a graph
<Graph />
```
#### Markdown file transclusion
You can transclude Markdown files by importing one `.md` file into another:
```jsx
import License from './license.md'
import Contributing from './docs/contributing.md'
# Hello, world!
<License />
---
<Contributing />
```
### Exports
You can use exports to export metadata like layout or authors.
It's a mechanism for an imported MDX file to communicate with its parent.
It works similarly to frontmatter, but uses ES2015 syntax.
```js
// posts/post.mdx
import { fred, sue } from '../data/authors'
import Layout from '../components/blog-layout'
export const meta = {
authors: [fred, sue],
layout: Layout
}
# Post about MDX
MDX is a JSX in Markdown loader, parser, and renderer for ambitious projects.
```
```jsx
// index.js
import React from 'react'
import Mdx, { meta } from 'posts/post.mdx'
const { authors, layout } = meta
export default () => (
<layout>
<Mdx />
By: {authors.map(author => author.name)}
</layout>
)
```
#### `export default`
The ES default export is used to provide a layout component which will wrap the transpiled JSX.
You can export it as a function:
```jsx
import Layout from './Layout'
export default ({children}) => <Layout some='metadata' >{children}</Layout>
# Hello, world!
```
Or directly as a component:
```jsx
import Layout from './Layout'
export default Layout
# Hello, world!
```
Any additional props passed to the imported MDX component will be passed to its default export:
```jsx
// index.js
import Mdx from './posts/post.mdx'
export default () => (
<Mdx someProp="value" />
)
```
```js
// posts/post.mdx
import Layout from '../components/blog-layout'
# Hello, world!
export default ({ children, someProp }) => <Layout someProp={someProp}>{children}</Layout>
```
### Component customization
You can pass in components for any `html` element that Markdown compiles to.
This allows you to use your existing components and use CSS-in-JS like `styled-components`.
```jsx
import React from 'react'
import Hello from '../hello.md'
import {
Text,
Heading,
Code,
InlineCode
} from '../ui'
export default () =>
<Hello
components={{
h1: Heading,
p: Text,
code: Code,
inlineCode: InlineCode
}}
/>
```
### MDXProvider
If you're using an app layout that wraps your JSX, you can use the `MDXProvider` to only pass your components in one place:
```jsx
import React from 'react'
import { MDXProvider } from '@mdx-js/tag'
import * as components from './markdown-components'
export default props =>
<MDXProvider components={components}>
<main {...props} />
</MDXProvider>
```
## Plugins
Since MDX uses the [remark](https://github.com/remarkjs/remark)/[rehype](https://github.com/rehypejs/rehype) ecosystems, you can use plugins to modify the AST at different stages of the transpilation process.
If you look at the [next example](https://github.com/mdx-js/mdx/blob/master/examples/next/next.config.js#L3), it shows you to pass plugins as options to the [MDX loader](https://github.com/mdx-js/mdx/tree/master/packages/loader).
### Options
Name | Type | Required | Description
---- | ---- | -------- | -----------
`mdPlugins` | Array[] | `false` | Array of remark plugins to manipulate the MDXAST
`hastPlugins` | Array[] | `false` | Array of rehype plugins to manipulate the MDXHAST
`skipExport` | Boolean | `false` | Skip `export default` wrapper on transpiled JSX
#### Specifying plugins
Plugins need to be passed to the MDX loader via webpack options.
If a plugin needs specific options, use the `[plugin, pluginOptions]` syntax.
```js
const images = require('remark-images')
const emoji = require('remark-emoji')
const toc = require('remark-toc')
module.exports = {
module: {
rules: [
{
test: /\.mdx?$/,
use: [
{
loader: 'babel-loader'
},
{
loader: '@mdx-js/loader',
options: {
mdPlugins: [images, emoji, [toc, {heading: 'intro'}]]
}
}
]
}
]
}
}
```
##### Next.js
If you're using Next.js, you can specify options in your `next.config.js`.
```js
const images = require('remark-images')
const emoji = require('remark-emoji')
module.exports = {
pageExtensions: ['js', 'jsx', 'md', 'mdx'],
webpack: (config, { defaultLoaders }) => {
config.module.rules.push({
test: /\.md$/,
use: [
defaultLoaders.babel,
{
loader: '@mdx-js/loader',
options: {
mdPlugins: [images, emoji]
}
}
]
})
return config
}
}
```
## Sync API
If you're using the MDX library directly, you might want to process an MDX string synchronously.
```js
const jsx = mdx.sync('# Hello, world!')
```
- [Documentation](https://mdxjs.com)
- [Syntax](https://mdxjs.com/syntax)
- [Getting Started](https://mdxjs.com/getting-started)
- [Plugins](https://mdxjs.com/plugins)
- [Contributing](https://mdxjs.com/advanced/contributing)
## Related
@ -368,3 +60,7 @@ const jsx = mdx.sync('# Hello, world!')
- Tim Neutkens ([@timneutkens](https://github.com/timneutkens)) [ZEIT](https://zeit.co)
- Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) [ZEIT](https://zeit.co)
- Brent Jackson ([@jxnblk](https://twitter.com/jxnblk)) [Compositor](https://compositor.io)
---
> [MIT](./license) license