├── .npmrc ├── .travis.yml ├── docs ├── src │ ├── 404.md │ ├── card.png │ ├── logo.png │ ├── css-in-js.md │ ├── ComponentProvider.md │ ├── card.js │ ├── Head.md │ ├── examples.md │ ├── Link.md │ ├── logo.js │ ├── using-mdx.md │ ├── StyleProvider.md │ ├── exporting.md │ ├── typography.md │ ├── routing.md │ ├── getting-started.md │ ├── index.js │ ├── configuration.md │ └── components.js └── package.json ├── examples ├── basic │ ├── docs │ │ └── index.mdx │ ├── package.json │ └── README.md ├── dev │ ├── hello.mdx │ ├── components │ │ └── button.mdx │ ├── index.mdx │ └── typography.mdx ├── routing │ ├── docs │ │ ├── about.mdx │ │ └── index.mdx │ ├── README.md │ └── package.json ├── emotion │ ├── docs │ │ ├── index.mdx │ │ └── Box.js │ ├── README.md │ └── package.json ├── styled-components │ ├── docs │ │ ├── index.mdx │ │ └── Box.js │ ├── README.md │ └── package.json ├── head-content │ ├── README.md │ ├── package.json │ └── docs │ │ └── index.mdx ├── react-live │ ├── README.md │ ├── docs │ │ ├── index.mdx │ │ └── components.js │ ├── package.json │ └── package-lock.json ├── live-code │ ├── README.md │ ├── docs │ │ └── index.mdx │ ├── package.json │ └── package-lock.json ├── dev-environment │ ├── README.md │ ├── docs │ │ ├── index.mdx │ │ ├── Button.md │ │ └── Heading.md │ ├── package.json │ ├── src │ │ ├── Heading.js │ │ └── Button.js │ └── package-lock.json └── mdx-themes │ ├── README.md │ ├── docs │ └── index.mdx │ └── package.json ├── .gitignore ├── test ├── snapshots │ ├── build.js.snap │ └── build.js.md ├── fixtures │ └── index.mdx ├── build.js └── dev.js ├── lib ├── client │ ├── withComponents.js │ ├── keyboard-shortcuts.md │ ├── components.js │ ├── Link.js │ ├── index.js │ ├── StyleProvider.js │ ├── ComponentProvider.js │ ├── scope.js │ ├── lazyComponent.js │ ├── App.js │ ├── Keyboard.js │ ├── Head.js │ └── routes.js ├── build.js ├── dev.js ├── config.js ├── html-plugin.js └── render-html.js ├── now.json ├── .npmignore ├── Dockerfile ├── babel.config.js ├── LICENSE.md ├── package.json ├── cli.js └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=true 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10 4 | -------------------------------------------------------------------------------- /docs/src/404.md: -------------------------------------------------------------------------------- 1 | 2 | # 404 3 | 4 | Page not found 5 | -------------------------------------------------------------------------------- /examples/basic/docs/index.mdx: -------------------------------------------------------------------------------- 1 | 2 | # mdx-go basic example 3 | 4 | -------------------------------------------------------------------------------- /examples/dev/hello.mdx: -------------------------------------------------------------------------------- 1 | 2 | # Hello 3 | 4 | This is another route 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .nyc_output 3 | coverage 4 | temp 5 | node_modules/ 6 | -------------------------------------------------------------------------------- /docs/src/card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jxnblk/mdx-go/HEAD/docs/src/card.png -------------------------------------------------------------------------------- /docs/src/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jxnblk/mdx-go/HEAD/docs/src/logo.png -------------------------------------------------------------------------------- /examples/dev/components/button.mdx: -------------------------------------------------------------------------------- 1 | 2 | # Button 3 | 4 | This is a subroute 5 | -------------------------------------------------------------------------------- /examples/routing/docs/about.mdx: -------------------------------------------------------------------------------- 1 | 2 | # About 3 | 4 | - [Home](/) 5 | - [About](/about) 6 | -------------------------------------------------------------------------------- /examples/routing/docs/index.mdx: -------------------------------------------------------------------------------- 1 | 2 | # routing example 3 | 4 | - [Home](/) 5 | - [About](/about) 6 | 7 | -------------------------------------------------------------------------------- /test/snapshots/build.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jxnblk/mdx-go/HEAD/test/snapshots/build.js.snap -------------------------------------------------------------------------------- /lib/client/withComponents.js: -------------------------------------------------------------------------------- 1 | export { withMDXComponents as withComponents } from '@mdx-js/tag/dist/mdx-provider' 2 | -------------------------------------------------------------------------------- /examples/emotion/docs/index.mdx: -------------------------------------------------------------------------------- 1 | import Box from './Box' 2 | 3 | # emotion example 4 | 5 | 6 | Box 7 | 8 | -------------------------------------------------------------------------------- /examples/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "basic", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/styled-components/docs/index.mdx: -------------------------------------------------------------------------------- 1 | import Box from './Box' 2 | 3 | # styled-components example 4 | 5 | 6 | Box 7 | 8 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mdx-go", 3 | "alias": [ 4 | "mdx-go.now.sh" 5 | ], 6 | "public": true, 7 | "type": "static" 8 | } 9 | -------------------------------------------------------------------------------- /examples/basic/README.md: -------------------------------------------------------------------------------- 1 | 2 | # mdx-go basic example 3 | 4 | ```sh 5 | npm i -g mdx-go 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/head-content/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Head example 3 | 4 | ```sh 5 | npm i -g mdx-go 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/routing/README.md: -------------------------------------------------------------------------------- 1 | 2 | # routing example 3 | 4 | ```sh 5 | npm i -g mdx-go 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/emotion/README.md: -------------------------------------------------------------------------------- 1 | 2 | # emotion example 3 | 4 | ```sh 5 | npm i -g mdx-go && npm i 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/react-live/README.md: -------------------------------------------------------------------------------- 1 | 2 | # mdx-go basic example 3 | 4 | ```sh 5 | npm i -g mdx-go 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/head-content/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "head-content", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/live-code/README.md: -------------------------------------------------------------------------------- 1 | 2 | # mdx-go live-code example 3 | 4 | ```sh 5 | npm i -g mdx-go 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/routing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "routing-example", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/dev-environment/README.md: -------------------------------------------------------------------------------- 1 | 2 | # dev environment example 3 | 4 | ```sh 5 | npm i -g mdx-go 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/mdx-themes/README.md: -------------------------------------------------------------------------------- 1 | 2 | # mdx-themes example 3 | 4 | ```sh 5 | npm i -g mdx-go && npm i 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/styled-components/README.md: -------------------------------------------------------------------------------- 1 | 2 | # styled-components example 3 | 4 | ```sh 5 | npm i -g mdx-go && npm i 6 | ``` 7 | 8 | ```sh 9 | npm start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/react-live/docs/index.mdx: -------------------------------------------------------------------------------- 1 | 2 | export { Root } from './components' 3 | 4 | # mdx-go react-live example 5 | 6 | ```.jsx 7 |

Edit me

8 | ``` 9 | 10 | -------------------------------------------------------------------------------- /examples/dev-environment/docs/index.mdx: -------------------------------------------------------------------------------- 1 | 2 | export { DevLayout as Root } from 'mdx-go' 3 | 4 | # dev environment example 5 | 6 | - [Button](/Button) 7 | - [Heading](/Heading) 8 | -------------------------------------------------------------------------------- /examples/mdx-themes/docs/index.mdx: -------------------------------------------------------------------------------- 1 | export { BaseTheme as Root } from 'mdx-themes' 2 | 3 | # BaseTheme example 4 | 5 | This example uses the `BaseTheme` component from mdx-themes 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/index.mdx: -------------------------------------------------------------------------------- 1 | 2 | # Hello mdx-go 3 | 4 | This is a test fixture for snapshot testing 5 | 6 | ```jsx 7 | 8 | ``` 9 | 10 | ```.jsx 11 |

Hello

12 | ``` 13 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | docs 2 | .nyc_output 3 | coverage 4 | test 5 | temp 6 | src 7 | examples 8 | .travis.yml 9 | .babelrc 10 | Dockerfile 11 | now.json 12 | babel.config.js 13 | 14 | packages 15 | -------------------------------------------------------------------------------- /examples/dev-environment/docs/Button.md: -------------------------------------------------------------------------------- 1 | import Button from '../src/Button' 2 | 3 | # Button 4 | 5 | 8 | 11 | -------------------------------------------------------------------------------- /examples/react-live/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "basic", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | }, 7 | "dependencies": { 8 | "react-live": "^1.11.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/mdx-themes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "mdx-themes-example", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | }, 7 | "dependencies": { 8 | "mdx-themes": "^1.0.0-0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/head-content/docs/index.mdx: -------------------------------------------------------------------------------- 1 | import { Head } from 'mdx-go' 2 | 3 | 4 | Head example 5 | 6 | 7 | # Head example 8 | 9 | This example has a custom `` set with the `Head` component 10 | 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:10-alpine 2 | 3 | WORKDIR /usr/src 4 | 5 | COPY package.json . 6 | COPY package-lock.json . 7 | 8 | RUN npm i 9 | 10 | COPY . . 11 | 12 | RUN cd docs && npm i && npm run build 13 | 14 | RUN mv docs/dist /public 15 | -------------------------------------------------------------------------------- /examples/emotion/docs/Box.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | const Box = styled('div')` 4 | padding: 32px; 5 | font-size: 32px; 6 | font-weight: bold; 7 | background-color: tomato; 8 | ` 9 | 10 | export default Box 11 | -------------------------------------------------------------------------------- /examples/live-code/docs/index.mdx: -------------------------------------------------------------------------------- 1 | 2 | export { ComponentProvider as Root } from 'mdx-go' 3 | 4 | # LiveCode example 5 | 6 | ```.jsx 7 | <div 8 | style={{ 9 | color: 'tomato' 10 | }}> 11 | <h2>Edit me</h2> 12 | </div> 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /examples/styled-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "styled-components-example", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | }, 7 | "dependencies": { 8 | "styled-components": "^3.4.5" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/client/keyboard-shortcuts.md: -------------------------------------------------------------------------------- 1 | 2 | ### Keyboard Shortcuts 3 | 4 | - `/`: Show directory listing 5 | - `→` `j`: Go to next route 6 | - `←` `k`: Go to previous route 7 | 8 | <a href='https://github.com/jxnblk/mdx-go' target='_blank'>About MDX Go</a> 9 | -------------------------------------------------------------------------------- /examples/dev-environment/docs/Heading.md: -------------------------------------------------------------------------------- 1 | import Heading from '../src/Heading' 2 | 3 | # Heading 4 | 5 | <Heading>Hello</Heading> 6 | <Heading fontSize={4}>Hello</Heading> 7 | <Heading fontSize={3}>Hello</Heading> 8 | <Heading fontSize={2}>Hello</Heading> 9 | -------------------------------------------------------------------------------- /examples/styled-components/docs/Box.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Box = styled.div` 4 | padding: 32px; 5 | font-size: 32px; 6 | font-weight: bold; 7 | background-color: tomato; 8 | ` 9 | 10 | export default Box 11 | -------------------------------------------------------------------------------- /examples/emotion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "emotion-example", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | }, 7 | "dependencies": { 8 | "emotion": "^9.2.6", 9 | "emotion-server": "^9.2.6", 10 | "react-emotion": "^9.2.6" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/live-code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "live-code", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | }, 7 | "devDependencies": { 8 | "emotion": "^9.2.8", 9 | "emotion-theming": "^9.2.6", 10 | "react-emotion": "^9.2.8" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/dev-environment/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "dev-environment", 4 | "scripts": { 5 | "start": "mdx-go docs" 6 | }, 7 | "dependencies": { 8 | "emotion": "^9.2.8", 9 | "react-emotion": "^9.2.8", 10 | "styled-system": "^3.0.2" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/client/components.js: -------------------------------------------------------------------------------- 1 | export { Head, HeadProvider } from './Head' 2 | export { Link } from './Link' 3 | export { ComponentProvider } from './ComponentProvider' 4 | export { withComponents } from './withComponents' 5 | export { StyleProvider } from './StyleProvider' 6 | export { lazyComponent } from './lazyComponent' 7 | -------------------------------------------------------------------------------- /lib/client/Link.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link as ReachLink } from '@reach/router' 3 | import isAbsoluteURL from 'is-absolute-url' 4 | 5 | export const Link = ({ 6 | href, 7 | ...props 8 | }) => isAbsoluteURL(href) 9 | ? <a href={href} {...props} /> 10 | : <ReachLink to={href} {...props} /> 11 | 12 | export default Link 13 | -------------------------------------------------------------------------------- /examples/dev-environment/src/Heading.js: -------------------------------------------------------------------------------- 1 | import styled from 'react-emotion' 2 | import { space, fontSize, color } from 'styled-system' 3 | 4 | const Heading = styled('h2')({ 5 | fontSize: '14px', 6 | fontWeight: 600, 7 | }, space, fontSize, color) 8 | 9 | Heading.defaultProps = { 10 | fontSize: 5, 11 | m: 0 12 | } 13 | 14 | export default Heading 15 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [['@babel/env', { modules: false }], '@babel/react'], 3 | plugins: [ 4 | '@babel/proposal-class-properties', 5 | '@babel/proposal-export-default-from', 6 | '@babel/proposal-export-namespace-from', 7 | '@babel/proposal-nullish-coalescing-operator', 8 | '@babel/syntax-dynamic-import' 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /lib/client/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import React from 'react' 3 | import { render, hydrate } from 'react-dom' 4 | import App from './App' 5 | 6 | const div = document.getElementById('root') 7 | const mount = div.innerHTML ? hydrate : render 8 | 9 | const basename = __BASENAME__ 10 | const props = __OPTIONS__ 11 | props.basepath = basename 12 | 13 | mount(<App {...props} />, div) 14 | 15 | if (module.hot) module.hot.accept() 16 | -------------------------------------------------------------------------------- /lib/client/StyleProvider.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import MDXStyle from 'mdx-style' 3 | import { base as theme } from 'mdx-style/themes' 4 | import scope from './scope' 5 | 6 | export const StyleProvider = ({ 7 | components = {}, 8 | ...props 9 | }) => 10 | <MDXStyle 11 | components={{ 12 | ...scope, 13 | ...components 14 | }} 15 | css={theme} 16 | {...props} 17 | /> 18 | 19 | export default StyleProvider 20 | -------------------------------------------------------------------------------- /docs/src/css-in-js.md: -------------------------------------------------------------------------------- 1 | 2 | # CSS-in-JS 3 | 4 | Any CSS-in-JS library will work with MDX Go. 5 | When [exporting as static HTML](/exporting), MDX Go includes server-side rendering support for [emotion][] and [styled-components][]. 6 | 7 | To make use of the built-in layout components, you'll need to install [emotion][] or [styled-components][]. 8 | 9 | [emotion]: https://github.com/emotion-js/emotion 10 | [styled-components]: https://github.com/styled-components/styled-components 11 | -------------------------------------------------------------------------------- /lib/client/ComponentProvider.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { MDXProvider } from '@mdx-js/tag' 3 | import defaultScope from './scope' 4 | 5 | export const ComponentProvider = ({ 6 | components, 7 | ...props 8 | }) => 9 | <MDXProvider 10 | components={{ 11 | ...defaultScope, 12 | ...components 13 | }}> 14 | <React.Fragment> 15 | {props.children} 16 | </React.Fragment> 17 | </MDXProvider> 18 | 19 | export default ComponentProvider 20 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "mdx-go src", 5 | "build": "mdx-go build src", 6 | "logo": "npx repng src/logo.js -w 256 -h 256 -d src -f logo.png", 7 | "card": "npx repng src/card.js -w 1024 -h 512 -d src -f card.png" 8 | }, 9 | "dependencies": { 10 | "react": "^16.5.2", 11 | "rebass": "^3.0.0-9", 12 | "sidepane": "^1.0.0-4", 13 | "styled-components": "^4.0.0-beta.10", 14 | "mdx-go": "^2.0.0-25" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/src/ComponentProvider.md: -------------------------------------------------------------------------------- 1 | 2 | # ComponentProvider 3 | 4 | Wrap your application with the ComponentProvider to use custom MDX components. 5 | 6 | ```jsx 7 | // example Root component 8 | import React from 'react' 9 | import { ComponentProvider } from 'mdx-go' 10 | 11 | export const Root = props => 12 | <ComponentProvider> 13 | {props.children} 14 | </ComponentProvider> 15 | ``` 16 | 17 | For a version with built-in styles, see the [`StyleProvider`](/StyleProvider) component. 18 | 19 | -------------------------------------------------------------------------------- /examples/dev-environment/src/Button.js: -------------------------------------------------------------------------------- 1 | import styled from 'react-emotion' 2 | import { space, color } from 'styled-system' 3 | 4 | const Button = styled('button')({ 5 | appearance: 'none', 6 | border: 0, 7 | borderRadius: '4px', 8 | display: 'inline-block', 9 | fontSize: '14px', 10 | fontFamily: 'inherit', 11 | fontWeight: 600, 12 | }, space, color) 13 | 14 | Button.defaultProps = { 15 | px: 3, 16 | py: 2, 17 | color: 'white', 18 | bg: '#c0c' 19 | } 20 | 21 | export default Button 22 | -------------------------------------------------------------------------------- /docs/src/card.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Logo from './logo' 3 | 4 | export default ({ 5 | width = 1024, 6 | color = '#0d0', 7 | bg = '#000' 8 | }) => 9 | <svg 10 | viewBox='0 0 256 128' 11 | width={width} 12 | height={width / 2} 13 | > 14 | <rect 15 | fill={bg} 16 | width='256' 17 | height='128' 18 | /> 19 | <g transform='translate(80 16)'> 20 | <Logo 21 | bg={color} 22 | size={96} 23 | /> 24 | </g> 25 | </svg> 26 | -------------------------------------------------------------------------------- /docs/src/Head.md: -------------------------------------------------------------------------------- 1 | 2 | # Head 3 | 4 | Use the Head component to set contents in the document `<head>`. 5 | This component can be used in a Root component or in individual pages. 6 | 7 | ```mdx 8 | import { Head } from 'mdx-go' 9 | 10 | <Head> 11 | <title>My Page Title 12 | 13 | ``` 14 | 15 | ## Webfonts 16 | 17 | The Head component can be used to load webfonts with a `` tag. 18 | 19 | ```mdx 20 | 21 | 25 | 26 | ``` 27 | -------------------------------------------------------------------------------- /examples/dev/index.mdx: -------------------------------------------------------------------------------- 1 | import { 2 | Head, 3 | } from 'mdx-go' 4 | 5 | 6 | Hello 7 | 8 | 9 | 10 | 11 | # Dev Example 12 | 13 | This example can be run from the root directory as a development environment for the core library. 14 | 15 | - [Menu](/_) 16 | - [Typography](/typography) 17 | - [Hello](/hello) 18 | - [Button](/components/button) 19 | 20 | 21 | ```jsx 22 | import React from 'react' 23 | 24 | export default () => 25 |
26 |

Not Live

27 |
28 | ``` 29 | 30 | ``` 31 | export const files = require.context('..', true, /\.example\.mdx?$/, 'lazy') 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/src/examples.md: -------------------------------------------------------------------------------- 1 | 2 | # Examples 3 | 4 | See examples of how to set up MDX Go on GitHub: 5 | 6 | - [Basic](https://github.com/jxnblk/mdx-go/tree/master/examples/basic) 7 | - [Routing](https://github.com/jxnblk/mdx-go/tree/master/examples/routing) 8 | - [Head Content](https://github.com/jxnblk/mdx-go/tree/master/examples/head-content) 9 | - [Emotion](https://github.com/jxnblk/mdx-go/tree/master/examples/emotion) 10 | - [Styled Components](https://github.com/jxnblk/mdx-go/tree/master/examples/styled-components) 11 | - [Dev Environment](https://github.com/jxnblk/mdx-go/tree/master/examples/dev-environment) 12 | 13 | [examples]: https://github.com/jxnblk/mdx-go/tree/master/examples 14 | -------------------------------------------------------------------------------- /lib/client/scope.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from './Link' 3 | import lazyComponent from './lazyComponent' 4 | 5 | const pre = lazyComponent(() => import('mdx-live')) 6 | 7 | const heading = Tag => ({ id, children, ...props }) => 8 | 9 | 17 | 18 | 19 | export const scope = { 20 | a: Link, 21 | pre, 22 | h1: heading('h1'), 23 | h2: heading('h2'), 24 | h3: heading('h3'), 25 | h4: heading('h4'), 26 | h5: heading('h5'), 27 | h6: heading('h6'), 28 | } 29 | 30 | export default scope 31 | -------------------------------------------------------------------------------- /test/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const test = require('ava') 4 | const rimraf = require('rimraf') 5 | const build = require('../lib/build') 6 | 7 | const output = path.resolve('test/helpers') 8 | const index = path.resolve('test/helpers/index.html') 9 | 10 | const clean = () => { 11 | rimraf.sync(output) 12 | } 13 | 14 | test.before(clean) 15 | test.after(clean) 16 | 17 | test.serial('builds', async t => { 18 | const stats = await build({ 19 | basename: '', 20 | dirname: path.join(__dirname, './fixtures'), 21 | outDir: output 22 | }) 23 | t.is(typeof stats, 'object') 24 | const html = fs.readFileSync(index, 'utf8') 25 | t.is(typeof html, 'string') 26 | t.snapshot(html) 27 | }) 28 | -------------------------------------------------------------------------------- /docs/src/Link.md: -------------------------------------------------------------------------------- 1 | 2 | # Link 3 | 4 | The Link component is provided as an MDX component by default. 5 | It automatically handles absolute URLs and relative links with client-side routing. 6 | 7 | When providing custom MDX components with the [ComponentProvider](/ComponentProvider), it's recommended you use the `Link` component for the `a` element. 8 | 9 | ```jsx 10 | // example Root component 11 | import React from 'react' 12 | import { ComponentProvider, Link } from 'mdx-go' 13 | import styled from 'react-emotion' 14 | 15 | const components = { 16 | a: styled(Link)({ 17 | color: 'tomato' 18 | }) 19 | } 20 | 21 | export const Root = props => 22 | 23 | {props.children} 24 | 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /test/dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const test = require('ava') 3 | const request = require('supertest') 4 | const dev = require('../lib/dev') 5 | 6 | let server 7 | 8 | test.serial('starts', async t => { 9 | server = await dev({ 10 | port: 3000, 11 | dirname: path.join(__dirname, './fixtures') 12 | }) 13 | t.is(typeof server, 'object') 14 | t.is(typeof server.address, 'function') 15 | }) 16 | 17 | test('returns html', async t => { 18 | const res = await request(server).get('/') 19 | .expect(200) 20 | .expect('Content-Type', 'text/html; charset=UTF-8') 21 | t.is(typeof res.text, 'string') 22 | }) 23 | 24 | test('serves bundled.js', async t => { 25 | const res = await request(server).get('/main.js') 26 | .expect(200) 27 | .expect('Content-Type', 'application/javascript; charset=UTF-8') 28 | t.is(typeof res.text, 'string') 29 | }) 30 | -------------------------------------------------------------------------------- /examples/react-live/docs/components.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ComponentProvider, Layout } from 'mdx-go' 3 | import { 4 | LiveProvider, 5 | LivePreview, 6 | LiveEditor, 7 | LiveError 8 | } from 'react-live' 9 | 10 | const code = props => { 11 | const isLive = props.className.includes('language-.jsx') 12 | if (!isLive) return
13 |   const code = React.Children.toArray(props.children).join('')
14 | 
15 |   return (
16 |     
20 |       
21 |       
22 |       
23 |     
24 |   )
25 | }
26 | 
27 | const components = {
28 |   code,
29 | }
30 | 
31 | export const Root = props =>
32 |   
33 |     
34 |       {props.children}
35 |     
36 |   
37 | 
38 | 


--------------------------------------------------------------------------------
/lib/client/lazyComponent.js:
--------------------------------------------------------------------------------
 1 | import React from 'react'
 2 | 
 3 | export const lazyComponent = (loader, loading) => {
 4 |   let Component = null
 5 | 
 6 |   return class Loadable extends React.Component {
 7 |     static preload = () => {
 8 |       Component = loader().default
 9 |     }
10 | 
11 |     constructor () {
12 |       super()
13 |       this.state = {
14 |         Component,
15 |       }
16 |     }
17 | 
18 |     componentDidMount () {
19 |       const load = loader()
20 |       if (typeof load.then !== 'function') {
21 |         this.setState({ Component: load.default })
22 |         return
23 |       }
24 | 
25 |       load.then(({
26 |         default: Component,
27 |       }) => {
28 |         this.setState({ Component })
29 |       })
30 |     }
31 | 
32 |     render () {
33 |       const { Component } = this.state
34 | 
35 |       if (!Component) return false
36 | 
37 |       return (
38 |         
41 |       )
42 |     }
43 |   }
44 | }
45 | 
46 | export default lazyComponent
47 | 


--------------------------------------------------------------------------------
/docs/src/logo.js:
--------------------------------------------------------------------------------
 1 | import React from 'react'
 2 | 
 3 | // forward //
 4 | const forward = [
 5 |   'M 16 0',
 6 |   'L 48 0',
 7 |   'L 32 32',
 8 |   'L 0 32',
 9 |   'z',
10 | ].join(' ')
11 | 
12 | // \\
13 | const backward = [
14 |   'M 0 0',
15 |   'L 32 0',
16 |   'L 48 32',
17 |   'L 16 32',
18 |   'z',
19 | ].join(' ')
20 | 
21 | export default ({
22 |   size = 256,
23 |   color = '#fff',
24 |   bg = '#0d0'
25 | }) =>
26 |   
30 |     
36 |     
37 |       
38 |       
39 |       
40 |       
41 |       
42 |       
43 |     
44 |   
45 | 


--------------------------------------------------------------------------------
/docs/src/using-mdx.md:
--------------------------------------------------------------------------------
 1 | 
 2 | # Using MDX
 3 | 
 4 | MDX combines the simplicity of markdown with the ability to import and use React components inline.
 5 | 
 6 | Write markdown like you normally would.
 7 | 
 8 | ```md
 9 | # Hello
10 | ```
11 | 
12 | Import and use React components inline.
13 | 
14 | ```mdx
15 | import { Box } from 'grid-styled'
16 | 
17 | # Hello
18 | 
19 | 
20 |   This is a React component!
21 | 
22 | ```
23 | 
24 | ## Exports
25 | 
26 | MDX uses the ES export syntax to communicate with its parent.
27 | MDX Go makes use of this to customize layouts, routing, and set other configuration options.
28 | 
29 | For example, a custom [Root component](/configuration#root-component) that wraps the entire app can be added by exporting `Root` from your `index.mdx` file.
30 | 
31 | ```mdx
32 | export const Root = props =>
33 |   
37 | {props.children} 38 |
39 | 40 | # Tomato 41 | ``` 42 | 43 | To learn more about using MDX, see the [MDX docs][MDX]. 44 | 45 | [MDX]: https://github.com/mdx-js/mdx 46 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | # The MIT License (MIT) 3 | Copyright (c) 2018 Brent Jackson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | -------------------------------------------------------------------------------- /lib/client/App.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import React from 'react' 3 | import { 4 | Router, 5 | } from '@reach/router' 6 | import { routes, Root, NotFound } from './routes' 7 | import { 8 | HeadProvider, 9 | ComponentProvider, 10 | } from 'mdx-go' 11 | import Keyboard from './Keyboard' 12 | 13 | const App = ({ 14 | basepath = '', 15 | keyboard, 16 | fullscreen, 17 | headTags = [], 18 | }) => 19 | 20 | 23 | 24 | {routes.map(({ 25 | Component, 26 | ...route 27 | }) => Component && ( 28 | 34 | ))} 35 | 39 | 40 | 41 | {keyboard && } 42 | 43 | 44 | export default App 45 | export { routes, Root, NotFound } 46 | -------------------------------------------------------------------------------- /docs/src/StyleProvider.md: -------------------------------------------------------------------------------- 1 | 2 | # StyleProvider 3 | 4 | The StyleProvider component is an extension of the [ComponentProvider](/ComponentProvider) component that includes default styles for MDX components with support for theming. 5 | The StyleProvider is enabled by default when a custom Root component is not configured. 6 | 7 | ```jsx 8 | // example Root component 9 | import React from 'react' 10 | import { StyleProvider } from 'mdx-go' 11 | 12 | export const Root = props => 13 | 14 | {props.children} 15 | 16 | ``` 17 | 18 | ## Theming 19 | 20 | Custom themes can be passed to the StyleProvider with the `theme` prop. 21 | 22 | ```jsx 23 | 26 | ``` 27 | 28 | ## Props 29 | 30 | Prop | Type | Description 31 | ---|---|--- 32 | `theme` | object | [theme](#theming) 33 | `components` | object | MDX component scope 34 | `fontSize` | number, string, or array | Base font size 35 | `fontFamily` | string | Base font family 36 | `color` | string | Base text color 37 | `bg` | string | Base background color 38 | `css` | object or string | Additional CSS to pass to the root element 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/src/exporting.md: -------------------------------------------------------------------------------- 1 | 2 | # Exporting 3 | 4 | To export as static HTML with a client-side JS bundle, use the `build` command. 5 | 6 | ```sh 7 | mdx-go build docs 8 | ``` 9 | 10 | This will create a `dist/` directory with an HTML file for each route and include a `main.js` bundle. 11 | 12 | ## CSS-in-JS 13 | 14 | To ensure [emotion][] or [styled-components][] styles are rendered during build, 15 | include one of these libraries as a dependency in your `package.json`. 16 | 17 | For [emotion][], be sure to install `emotion-server` for static export. 18 | 19 | ```sh 20 | npm i emotion-server 21 | ``` 22 | 23 | ## HTML Only 24 | 25 | To export a site as static HTML without JS, use the `--static` flag. 26 | 27 | ```sh 28 | mdx-go build docs --static 29 | ``` 30 | 31 | ## Basename 32 | 33 | When exporting for use on a domain with a base path, such as gh-pages, use the `--basename` CLI flag to specify the path. 34 | 35 | ```sh 36 | mdx-go build docs --basename /my-app 37 | ``` 38 | 39 | ## Options 40 | 41 | Use the following CLI options to customize the export. 42 | 43 | ``` 44 | -d --out-dir Output directory for static export 45 | --basename Base path for routing 46 | --static Export HTML without JS bundle 47 | ``` 48 | 49 | [emotion]: https://github.com/emotion-js/emotion 50 | [styled-components]: https://github.com/styled-components/styled-components 51 | -------------------------------------------------------------------------------- /docs/src/typography.md: -------------------------------------------------------------------------------- 1 | 2 | # Typography 3 | 4 | This is a demonstration page for MDX typographic styles provided by the [`StyleProvider`](/StyleProvider) component. 5 | 6 | # Hamburger 1 7 | ## Hamburger 2 8 | ### Hamburger 3 9 | #### Hamburger 4 10 | ##### Hamburger 5 11 | ###### Hamburger 6 12 | 13 | ``` 14 | This is a fenced code block 15 | ``` 16 | 17 | ```.jsx 18 |

This is a live code block

19 | ``` 20 | 21 | ![](card.png) 22 | 23 | This is a paragraph with `inline code` and *italics* and **bold** and a [link](#typography). 24 | 25 | > Hello, this is a blockquote. 26 | 27 | --- 28 | 29 | ## Lists 30 | 31 | - This is a list 32 | - Of things that can be listed 33 | - And this particular item is really really long. Much longer than the other items, so it should wrap, but still look okay. 34 | - And here's the last item 35 | 36 | ## Checklists 37 | 38 | - [x] checklist 39 | - [ ] things you could do 40 | - [ ] check items off the list 41 | - [ ] ignore the checklist 42 | 43 | ## Ordered Lists 44 | 45 | 1. Get Ready 46 | 2. Get Set 47 | 3. Go! 48 | 49 | Prop | Type | Description 50 | ---|---|--- 51 | `color` | string | Text color 52 | `bg` | string | Background color 53 | `mt` | number, string, or array | margin top 54 | `mb` | number, string, or array | margin bottom 55 | 56 | ## This is a really long heading that should wrap but still look okay with regard to line height 57 | 58 | -------------------------------------------------------------------------------- /examples/dev/typography.mdx: -------------------------------------------------------------------------------- 1 | 2 | export const name = 'Typography' 3 | 4 | # Typography 5 | 6 | This is a demonstration page for MDX typographic styles provided by the [`StyleProvider`](/StyleProvider) component. 7 | 8 | # Hamburger 1 9 | ## Hamburger 2 10 | ### Hamburger 3 11 | #### Hamburger 4 12 | ##### Hamburger 5 13 | ###### Hamburger 6 14 | 15 | ``` 16 | This is a fenced code block 17 | ``` 18 | 19 | ```.jsx 20 |

This is a live code block

21 | ``` 22 | 23 | ![](https://jxnblk.com/mdx-go/card.png) 24 | 25 | This is a paragraph with `inline code` and *italics* and **bold** and a [link](#typography). 26 | 27 | > Hello, this is a blockquote. 28 | 29 | --- 30 | 31 | ## Lists 32 | 33 | - This is a list 34 | - Of things that can be listed 35 | - And this particular item is really really long. Much longer than the other items, so it should wrap, but still look okay. 36 | - And here's the last item 37 | 38 | ## Checklists 39 | 40 | - [x] checklist 41 | - [ ] things you could do 42 | - [ ] check items off the list 43 | - [ ] ignore the checklist 44 | 45 | ## Ordered Lists 46 | 47 | 1. Get Ready 48 | 2. Get Set 49 | 3. Go! 50 | 51 | Prop | Type | Description 52 | ---|---|--- 53 | `color` | string | Text color 54 | `bg` | string | Background color 55 | `mt` | number, string, or array | margin top 56 | `mb` | number, string, or array | margin bottom 57 | 58 | ## This is a really long heading that should wrap but still look okay with regard to line height 59 | 60 | -------------------------------------------------------------------------------- /docs/src/routing.md: -------------------------------------------------------------------------------- 1 | 2 | # Routing 3 | 4 | Each MDX file in the target directory will become its own route, 5 | with `index.mdx` serving as the base route, i.e. `/`. 6 | 7 | With the following directory structure: 8 | 9 | ``` 10 | docs/ 11 | index.mdx 12 | getting-started.mdx 13 | api.mdx 14 | ``` 15 | 16 | MDX Go will create routes for `/`, `/getting-started`, and `/api`. 17 | 18 | ## React Components 19 | 20 | MDX Go also supports using React components as routes for files with the `.js` extension. 21 | Be sure that the `.js` file exports a default component to render as a route. 22 | 23 | ```jsx 24 | // example React component route 25 | import React from 'react' 26 | 27 | export default props => 28 |

Hello

29 | ``` 30 | 31 | ## Customizing Routes 32 | 33 | Each page can customize its path and other metadata using exports. 34 | 35 | To set a custom path, without renaming the file, export a `path` string. 36 | 37 | ```mdx 38 | export const path = '/go' 39 | 40 | # Getting Started 41 | ``` 42 | 43 | ## Route Object 44 | 45 | Each file will generate a route object with the following keys. Additionally, the `index.mdx` route will include any additional named exports from the file. 46 | 47 | Key | Description 48 | ---|--- 49 | `key` | Key from wepback's `require.context` 50 | `extname` | The file extension of the route 51 | `name` | The file basename 52 | `dirname` | The directory of the file 53 | `path` | Route pathname used for routing 54 | `Component` | React component 55 | -------------------------------------------------------------------------------- /lib/client/Keyboard.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Location } from '@reach/router' 3 | import routes from './routes' 4 | 5 | export class Keyboard extends React.Component { 6 | handleKeyDown = e => { 7 | const { location } = this.props 8 | const { tagName } = document.activeElement 9 | if (tagName !== 'BODY' && tagName !== 'DIV') return 10 | switch (e.key) { 11 | case '/': 12 | this.navigate('/_') 13 | break 14 | case 'ArrowLeft': 15 | case 'k': 16 | this.goto(-1) 17 | break 18 | case 'ArrowRight': 19 | case 'j': 20 | this.goto(1) 21 | break 22 | } 23 | } 24 | 25 | navigate = pathname => { 26 | const { navigate } = this.props 27 | navigate(pathname) 28 | .then(() => { 29 | window.scrollTo(0, 0) 30 | }) 31 | } 32 | 33 | goto = n => { 34 | const { location } = this.props 35 | const index = routes.findIndex(route => route.path === location.pathname) 36 | const next = routes[index + n] 37 | if (!next) return 38 | this.navigate(next.path) 39 | } 40 | 41 | componentDidMount () { 42 | document.addEventListener('keydown', this.handleKeyDown) 43 | } 44 | 45 | componentWillUnmount () { 46 | document.removeEventListener('keydown', this.handleKeyDown) 47 | } 48 | 49 | render () { 50 | return false 51 | } 52 | } 53 | 54 | export default props => 55 | } 57 | /> 58 | -------------------------------------------------------------------------------- /docs/src/getting-started.md: -------------------------------------------------------------------------------- 1 | 2 | # Getting Started 3 | 4 | MDX Go is best suited as a globally available dev server for React 5 | that can be used in any project. 6 | Install MDX Go globally with the following command: 7 | 8 | ```sh 9 | npm install -g mdx-go 10 | ``` 11 | 12 | Create a `docs` folder and `docs/index.mdx` file. 13 | 14 | ```mdx 15 | import MyComponent from '../src' 16 | 17 | # Component Demo 18 | 19 | 22 | ``` 23 | 24 | Start the dev server on the `docs` folder: 25 | 26 | ```sh 27 | mdx-go docs 28 | ``` 29 | 30 | ### npm run scripts 31 | 32 | Alternatively, mdx-go can be installed as a development dependency and used with run scripts in your `package.json`. 33 | 34 | ```json 35 | "scripts": { 36 | "dev": "mdx-go docs", 37 | "docs": "mdx-go build docs" 38 | } 39 | ``` 40 | 41 | ```sh 42 | npm run dev 43 | ``` 44 | 45 | ## Motivation 46 | 47 | MDX Go is built with the idea of **[Progressive Documentation][]** in mind, 48 | intended to be used anywhere as a dev server, prototyping tool, or simple static site generator. 49 | By embracing the MDX file format, the docs you create with MDX Go can easily be used in other tools. 50 | Start your docs with MDX Go and migrate to tools like [Next.js][] and [Gatsby][] when needed. 51 | You can even keep MDX Go around to use as a dev tool outside of other React applications. 52 | 53 | [Progressive Documentation]: https://jxnblk.com/writing/posts/progressive-documentation/ 54 | [Next.js]: https://github.com/zeit/next.js/ 55 | [Gatsby]: https://github.com/gatsbyjs/gatsby 56 | -------------------------------------------------------------------------------- /lib/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const http = require('http') 3 | const path = require('path') 4 | const webpack = require('webpack') 5 | const rimraf = require('rimraf') 6 | const createConfig = require('./config') 7 | const HTMLPlugin = require('./html-plugin') 8 | const renderHTML = require('./render-html') 9 | 10 | const compile = async compiler => await new Promise((resolve, reject) => { 11 | compiler.run((err, stats) => { 12 | if (err) { 13 | reject(err) 14 | return 15 | } 16 | resolve(stats) 17 | }) 18 | }) 19 | 20 | module.exports = async opts => { 21 | const pages = await renderHTML(opts) 22 | const config = createConfig(opts) 23 | 24 | const defs = new webpack.DefinePlugin({ 25 | __DEV__: JSON.stringify(false), 26 | __OPTIONS__: JSON.stringify(opts), 27 | __DIRNAME__: JSON.stringify(opts.dirname), 28 | __BASENAME__: JSON.stringify(opts.basename), 29 | __STATIC__: JSON.stringify(false) 30 | }) 31 | 32 | config.plugins.push(defs) 33 | config.output.path = opts.outDir 34 | config.output.publicPath = opts.basename + '/' 35 | 36 | if (opts.debug) { 37 | console.log('DEBUG MODE') 38 | config.mode = 'development' 39 | config.stats = 'verbose' 40 | } 41 | 42 | pages.forEach(page => { 43 | config.plugins.push( 44 | new HTMLPlugin({ 45 | filename: page.path + '/index.html', 46 | context: page 47 | }) 48 | ) 49 | }) 50 | 51 | const compiler = webpack(config) 52 | 53 | const stats = await compile(compiler) 54 | 55 | if (opts.static) { 56 | const bundle = path.join(opts.outDir, './main.js') 57 | rimraf(bundle, err => { 58 | if (err) console.error(err) 59 | }) 60 | } 61 | 62 | return stats 63 | } 64 | -------------------------------------------------------------------------------- /lib/dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const http = require('http') 3 | const connect = require('connect') 4 | const webpack = require('webpack') 5 | const history = require('connect-history-api-fallback') 6 | const serveStatic = require('serve-static') 7 | const devMiddleware = require('webpack-dev-middleware') 8 | const hotMiddleware = require('webpack-hot-middleware') 9 | const chalk = require('chalk') 10 | 11 | const HTMLPlugin = require('./html-plugin') 12 | const createConfig = require('./config') 13 | 14 | module.exports = async opts => { 15 | const config = createConfig(opts) 16 | 17 | config.entry.unshift( 18 | 'webpack-hot-middleware/client' 19 | ) 20 | config.plugins.push( 21 | new webpack.HotModuleReplacementPlugin() 22 | ) 23 | config.mode = 'development' 24 | 25 | const defs = new webpack.DefinePlugin({ 26 | __DEV__: JSON.stringify(true), 27 | __OPTIONS__: JSON.stringify(opts), 28 | __DIRNAME__: JSON.stringify(opts.dirname), 29 | __BASENAME__: JSON.stringify(''), 30 | __STATIC__: JSON.stringify(false) 31 | }) 32 | 33 | config.plugins.push(defs) 34 | 35 | config.plugins.push( 36 | new HTMLPlugin() 37 | ) 38 | 39 | const devOptions = { 40 | stats: 'errors-only', 41 | logLevel: 'error', 42 | publicPath: '/', 43 | } 44 | const hotOptions = { 45 | log: false 46 | } 47 | 48 | if (opts.debug) { 49 | console.log('DEBUG MODE') 50 | config.stats = 'verbose' 51 | devOptions.stats = 'verbose' 52 | devOptions.logLevel = 'debug' 53 | hotOptions.log = true 54 | } 55 | 56 | const app = connect() 57 | 58 | const compiler = webpack(config) 59 | 60 | const middleware = devMiddleware(compiler, devOptions) 61 | 62 | app.use(history()) 63 | app.use(serveStatic(opts.dirname)) 64 | app.use(middleware) 65 | app.use(hotMiddleware(compiler, hotOptions)) 66 | 67 | return new Promise((resolve) => { 68 | const server = http.createServer(app) 69 | 70 | compiler.hooks.done.tap('mdx-go', () => { 71 | resolve(server) 72 | }) 73 | 74 | const port = Number(opts.port) 75 | server.listen(port) 76 | }) 77 | } 78 | -------------------------------------------------------------------------------- /lib/client/Head.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { createPortal } from 'react-dom' 3 | 4 | const noop = () => { 5 | console.warn('Missing HeadProvider') 6 | } 7 | 8 | export const Context = React.createContext({ 9 | tags: [], 10 | push: noop 11 | }) 12 | 13 | export class HeadProvider extends React.Component { 14 | static defaultProps = { 15 | tags: [] 16 | } 17 | 18 | push = (elements) => { 19 | this.props.tags.push(...elements) 20 | } 21 | 22 | render () { 23 | const context = { 24 | ...this.props, 25 | push: this.push 26 | } 27 | 28 | return ( 29 | 30 | {this.props.children} 31 | 32 | ) 33 | } 34 | } 35 | 36 | export class Head extends React.Component { 37 | state = { 38 | didMount: false 39 | } 40 | 41 | rehydrate = () => { 42 | const children = React.Children.toArray(this.props.children) 43 | const nodes = [ 44 | ...document.head.querySelectorAll('[data-head]') 45 | ] 46 | 47 | nodes.forEach(node => { 48 | node.remove() 49 | }) 50 | children.forEach(child => { 51 | if (child.type === 'title') { 52 | const title = document.head.querySelector('title') 53 | if (title) title.remove() 54 | } 55 | if (child.type === 'meta') { 56 | const { name } = child.props 57 | let meta 58 | if (name) meta = document.head.querySelector(`meta[name="${name}"]`) 59 | if (meta) meta.remove() 60 | } 61 | }) 62 | 63 | this.setState({ 64 | didMount: true 65 | }) 66 | } 67 | 68 | componentDidMount () { 69 | this.rehydrate() 70 | } 71 | 72 | render () { 73 | const children = React.Children.toArray(this.props.children) 74 | .map(child => React.cloneElement(child, { 75 | 'data-head': true 76 | })) 77 | 78 | const { didMount } = this.state 79 | 80 | if (!didMount) { 81 | return ( 82 | { 84 | push(children) 85 | return false 86 | }} 87 | /> 88 | ) 89 | } 90 | 91 | return createPortal( 92 | children, 93 | document.head 94 | ) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mdx-go", 3 | "version": "2.0.0-31", 4 | "description": "Lightning-fast MDX-based dev server", 5 | "bin": { 6 | "mdx-go": "./cli.js" 7 | }, 8 | "main": "lib/client/components.js", 9 | "module": "lib/client/components.js", 10 | "sideEffects": false, 11 | "scripts": { 12 | "start": "./cli.js examples/dev", 13 | "build": "./cli.js build examples/dev -d temp", 14 | "help": "./cli.js", 15 | "test": "nyc ava" 16 | }, 17 | "keywords": [ 18 | "mdx", 19 | "react", 20 | "dev-server", 21 | "development", 22 | "docs", 23 | "documentation", 24 | "static-site" 25 | ], 26 | "author": "Brent Jackson", 27 | "license": "MIT", 28 | "dependencies": { 29 | "@babel/core": "^7.8.3", 30 | "@babel/plugin-proposal-class-properties": "^7.8.3", 31 | "@babel/plugin-proposal-export-default-from": "^7.8.3", 32 | "@babel/plugin-proposal-export-namespace-from": "^7.8.3", 33 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", 34 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 35 | "@babel/plugin-transform-runtime": "^7.8.3", 36 | "@babel/preset-env": "^7.8.3", 37 | "@babel/preset-react": "^7.8.3", 38 | "@babel/runtime": "^7.8.3", 39 | "@mdx-js/loader": "^1.5.4", 40 | "@mdx-js/mdx": "^1.5.4", 41 | "@mdx-js/tag": "^0.20.3", 42 | "@reach/router": "^1.2.1", 43 | "babel-loader": "^8.0.6", 44 | "chalk": "^3.0.0", 45 | "connect": "^3.7.0", 46 | "connect-history-api-fallback": "^1.6.0", 47 | "find-up": "^4.1.0", 48 | "friendly-errors-webpack-plugin": "^1.7.0", 49 | "is-absolute-url": "^3.0.3", 50 | "lodash.get": "^4.4.2", 51 | "lodash.sortby": "^4.7.0", 52 | "mdx-live": "^2.0.0-alpha.2", 53 | "mdx-style": "^2.0.0-alpha.2", 54 | "meow": "^6.0.0", 55 | "pkg-conf": "^3.1.0", 56 | "prop-types": "^15.7.2", 57 | "react": "^16.12.0", 58 | "react-dev-utils": "^10.0.0", 59 | "react-dom": "^16.12.0", 60 | "read-pkg-up": "^7.0.1", 61 | "remark-autolink-headings": "^5.2.1", 62 | "remark-emoji": "^2.0.2", 63 | "remark-images": "^1.0.0", 64 | "remark-slug": "^5.1.2", 65 | "remark-unwrap-images": "1.0.0", 66 | "resolve-cwd": "^3.0.0", 67 | "rimraf": "^3.0.0", 68 | "serve-static": "^1.14.1", 69 | "update-notifier": "^4.0.0", 70 | "webpack": "^4.41.5", 71 | "webpack-dev-middleware": "^3.7.2", 72 | "webpack-hot-middleware": "^2.25.0", 73 | "webpack-merge": "^4.2.2", 74 | "webpack-node-externals": "^1.7.2", 75 | "webpack-sources": "^1.4.3", 76 | "webpackbar": "^4.0.0" 77 | }, 78 | "devDependencies": { 79 | "@babel/polyfill": "^7.8.3", 80 | "@babel/register": "^7.8.3", 81 | "ava": "^2.4.0", 82 | "nyc": "^15.0.0", 83 | "supertest": "^4.0.2" 84 | }, 85 | "ava": { 86 | "require": [ 87 | "@babel/register", 88 | "@babel/polyfill" 89 | ] 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const WebpackBar = require('webpackbar') 3 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 4 | const merge = require('webpack-merge') 5 | const remarkPlugins = [ 6 | require('remark-emoji'), 7 | require('remark-images'), 8 | require('remark-autolink-headings'), 9 | require('remark-slug'), 10 | require('remark-unwrap-images'), 11 | ] 12 | 13 | const babel = { 14 | babelrc: false, 15 | presets: [ 16 | [ require.resolve('@babel/preset-env'), { modules: false } ], 17 | require.resolve('@babel/preset-react'), 18 | ], 19 | plugins: [ 20 | '@babel/plugin-proposal-class-properties', 21 | '@babel/plugin-proposal-export-default-from', 22 | '@babel/plugin-proposal-export-namespace-from', 23 | '@babel/plugin-transform-runtime', 24 | '@babel/plugin-syntax-dynamic-import', 25 | ].map(require.resolve) 26 | } 27 | 28 | const rules = [ 29 | { 30 | test: /\.js$/, 31 | exclude: /node_modules/, 32 | use: { 33 | loader: require.resolve('babel-loader'), 34 | options: babel 35 | } 36 | }, 37 | { 38 | test: /\.js$/, 39 | exclude: path.join(__dirname, '../node_modules'), 40 | include: [ 41 | path.join(__dirname, './lib'), 42 | __dirname, 43 | path.join(__dirname, '..') 44 | ], 45 | use: { 46 | loader: require.resolve('babel-loader'), 47 | options: babel 48 | } 49 | }, 50 | { 51 | test: /\.mdx?$/, 52 | exclude: /node_modules\/(?!(mdx-go)\/).*/, 53 | use: [ 54 | { 55 | loader: require.resolve('babel-loader'), 56 | options: babel 57 | }, 58 | { 59 | loader: require.resolve('@mdx-js/loader'), 60 | options: { 61 | remarkPlugins 62 | } 63 | } 64 | ] 65 | }, 66 | ] 67 | 68 | const createConfig = (opts = {}) => merge.smart(({ 69 | name: 'mdx-go', 70 | context: __dirname, 71 | mode: 'production', 72 | stats: 'errors-only', 73 | entry: [ 74 | path.join(__dirname, './client/index.js') 75 | ], 76 | output: { 77 | path: path.resolve('dist'), 78 | filename: 'main.js', 79 | publicPath: '/' 80 | }, 81 | module: { 82 | rules 83 | }, 84 | resolve: { 85 | alias: { 86 | 'mdx-go': path.resolve(__dirname, './client/components'), 87 | 'webpack-hot-middleware/client': path.resolve(require.resolve('webpack-hot-middleware/client')) 88 | }, 89 | modules: [ 90 | __dirname, 91 | path.join(__dirname, '../node_modules'), 92 | path.relative(process.cwd(), path.join(__dirname, '../node_modules')), 93 | 'node_modules' 94 | ] 95 | }, 96 | plugins: [ 97 | new WebpackBar({ 98 | name: '[mdx-go]' 99 | }), 100 | new FriendlyErrorsPlugin(), 101 | ] 102 | }), opts.webpack) 103 | 104 | module.exports = createConfig 105 | -------------------------------------------------------------------------------- /test/snapshots/build.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/build.js` 2 | 3 | The actual snapshot is saved in `build.js.snap`. 4 | 5 | Generated by [AVA](https://ava.li). 6 | 7 | ## builds 8 | 9 | > Snapshot 1 10 | 11 | `␊ 12 | ␊ 13 | ␊ 14 | ␊ 15 | ␊ 16 | ␊ 17 | ␊ 18 | ␊ 19 | ␊ 20 |

Hello mdx-go

This is a test fixture for snapshot testing

<Box />␊
21 |     
<h1>Hello</h1>␊
22 |     
␊ 23 | ␊ 24 | ␊ 25 | ` 26 | -------------------------------------------------------------------------------- /lib/html-plugin.js: -------------------------------------------------------------------------------- 1 | // based on mini-html-webpack-plugin 2 | const path = require('path') 3 | const { RawSource } = require('webpack-sources') 4 | 5 | class HTMLPlugin { 6 | constructor (options = {}) { 7 | this.options = options 8 | this.plugin = this.plugin.bind(this) 9 | } 10 | 11 | plugin (compilation, callback) { 12 | const { publicPath } = compilation.options.output 13 | const { 14 | filename = 'index.html', 15 | template = defaultTemplate, 16 | context 17 | } = this.options 18 | 19 | const files = getFiles(compilation.entrypoints) 20 | const chunks = getChunks(compilation.chunks) 21 | const links = generateCSSReferences(files.css, publicPath) 22 | const scripts = generateJSReferences(files.js, publicPath) 23 | const prefetch = generatePrefetchLinks(chunks.js, publicPath) 24 | const ctx = Object.assign({}, files, { 25 | publicPath, 26 | links, 27 | prefetch, 28 | scripts 29 | }, context) 30 | 31 | compilation.assets[filename] = new RawSource( 32 | template(ctx) 33 | ) 34 | 35 | callback() 36 | } 37 | 38 | apply (compiler) { 39 | compiler.hooks.emit.tapAsync('MDXGoHtmlPlugin', this.plugin) 40 | } 41 | } 42 | 43 | const getFiles = (entrypoints) => { 44 | const files = {} 45 | 46 | entrypoints.forEach(entry => { 47 | entry.getFiles().forEach(file => { 48 | const extension = path.extname(file).replace(/\./, '') 49 | 50 | if (!files[extension]) { 51 | files[extension] = [] 52 | } 53 | 54 | files[extension].push(file) 55 | }) 56 | }) 57 | 58 | return files 59 | } 60 | 61 | const getChunks = (chunks) => { 62 | const obj = {} 63 | 64 | chunks.forEach(chunk => { 65 | chunk.files.forEach(file => { 66 | const extension = path.extname(file).replace(/\./, '') 67 | if (!obj[extension]) { 68 | obj[extension] = [] 69 | } 70 | obj[extension].push(file) 71 | }) 72 | }) 73 | 74 | return obj 75 | } 76 | 77 | const defaultTemplate = ({ 78 | links, 79 | prefetch, 80 | scripts, 81 | title = '', 82 | body = '', 83 | head = '', 84 | css = '', 85 | static: noScript, 86 | publicPath 87 | }) => ` 88 | 89 | 90 | 91 | 92 | 93 | ${head}${css}${links}${prefetch} 94 | 95 | 96 |
${body}
97 | ${noScript ? '' : scripts} 98 | 99 | ` 100 | 101 | const generateCSSReferences = (files = [], publicPath = '') => files 102 | .map(file => ``) 103 | .join('') 104 | 105 | const generateJSReferences = (files = [], publicPath = '') => files 106 | .map(file => ``) 107 | .join('') 108 | 109 | const generatePrefetchLinks = (files = [], publicPath = '') => files 110 | .map(file => ``) 111 | .join('') 112 | 113 | module.exports = HTMLPlugin 114 | module.exports.template = defaultTemplate 115 | -------------------------------------------------------------------------------- /lib/client/routes.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import React from 'react' 3 | import { Location } from '@reach/router' 4 | import lazyComponent from './lazyComponent' 5 | import { Link } from './Link' 6 | import StyleProvider from './StyleProvider' 7 | import KeyboardShortcuts from './keyboard-shortcuts.md' 8 | 9 | const name = 'mdx-go' 10 | const context = __STATIC__ 11 | ? require.context(__DIRNAME__, true, /\.(js|md|mdx)$/, 'sync') 12 | : require.context(__DIRNAME__, true, /\.(js|md|mdx)$/, 'lazy') 13 | 14 | const getSync = require.context(__DIRNAME__, false, /index\.(js|md|mdx)$/, 'sync') 15 | 16 | export let Root = props => props.fullscreen ? props.children : 17 | 26 | 27 | export let NotFound = (props) => 28 |

Page not found

29 | 30 | export const Directory = props => 31 | 32 |

{name}

33 | {props.routes 34 | .filter(route => route.path !== '/_') 35 | .map(route => ( 36 |
37 | 42 | {route.key} 43 | 44 |
45 | ))} 46 | 47 |
48 | 49 | export const parseRoute = (key, context) => { 50 | const extname = path.extname(key) 51 | const name = path.basename(key, extname) 52 | if (/^_/.test(name)) return null 53 | const dirname = path.dirname(key).replace(/^\./, '') 54 | const index = name === 'index' 55 | const pathname = dirname + '/' + (index ? '' : name) 56 | 57 | let Component = lazyComponent(() => context(key)) 58 | let exports = {} 59 | 60 | if (index) { 61 | exports = context(key) 62 | Component = lazyComponent(() => exports) 63 | } 64 | 65 | if (name === '404') { 66 | NotFound = Component 67 | return 68 | } 69 | 70 | return { 71 | key, 72 | extname, 73 | name, 74 | dirname, 75 | path: pathname, 76 | Component, 77 | ...exports 78 | } 79 | } 80 | 81 | export const [ index ] = getSync.keys() 82 | .map(key => parseRoute(key, getSync)) 83 | .filter(Boolean) 84 | 85 | const withRouter = Component => React.forwardRef((props, ref) => 86 | ( 88 | 93 | )} 94 | /> 95 | ) 96 | 97 | if (typeof index.Root === 'function') { 98 | Root = withRouter(index.Root) 99 | } 100 | 101 | export const mainRoutes = context.keys() 102 | .filter(key => key !== index.key) 103 | .map(key => parseRoute(key, context)) 104 | .filter(Boolean) 105 | 106 | export const subRoutes = (typeof index.files === 'function' && index.files.keys) 107 | ? index.files.keys().map(key => parseRoute(key, index.files)) 108 | : [] 109 | 110 | const directory = { 111 | key: '_', 112 | path: '/_', 113 | Component: lazyComponent(() => ({ default: Directory })), 114 | } 115 | 116 | export const routes = [ 117 | index, 118 | ...mainRoutes, 119 | ...subRoutes, 120 | directory 121 | ] 122 | 123 | export default routes 124 | -------------------------------------------------------------------------------- /lib/render-html.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const React = require('react') 4 | const { 5 | renderToString, 6 | renderToStaticMarkup 7 | } = require('react-dom/server') 8 | const { ServerLocation } = require('@reach/router') 9 | const webpack = require('webpack') 10 | const nodeExternals = require('webpack-node-externals') 11 | const rimraf = require('rimraf') 12 | const mkdirp = require('mkdirp') 13 | const resolveCWD = require('resolve-cwd') 14 | const createConfig = require('./config') 15 | 16 | const getApp = async opts => { 17 | opts.tempdir = path.join(opts.outDir, 'TEMP') 18 | 19 | if (!fs.existsSync(opts.outDir)) mkdirp.sync(opts.outDir) 20 | if (!fs.existsSync(opts.tempdir)) mkdirp.sync(opts.tempdir) 21 | 22 | const config = createConfig(opts) 23 | 24 | config.output = { 25 | path: opts.tempdir, 26 | filename: '[name].js', 27 | libraryTarget: 'umd' 28 | } 29 | config.entry = { 30 | App: path.join(__dirname, './client/App.js') 31 | } 32 | config.target = 'node' 33 | config.externals = [ 34 | nodeExternals({ 35 | whitelist: [ 36 | 'mdx-go' 37 | ] 38 | }) 39 | ] 40 | config.plugins.push( 41 | new webpack.DefinePlugin({ 42 | __OPTIONS__: JSON.stringify(opts), 43 | __DIRNAME__: JSON.stringify(opts.dirname), 44 | __STATIC__: JSON.stringify(true) 45 | }) 46 | ) 47 | 48 | if (opts.debug) { 49 | config.mode = 'development' 50 | config.stats = 'verbose' 51 | } 52 | 53 | const compiler = webpack(config) 54 | 55 | return new Promise((resolve, reject) => { 56 | compiler.run((err, stats) => { 57 | if (err) { 58 | reject(err) 59 | return 60 | } 61 | const app = require( 62 | path.resolve(opts.tempdir, './App.js') 63 | ) 64 | 65 | if (!opts.debug) { 66 | rimraf(opts.tempdir, err => { 67 | if (err) console.error(err) 68 | }) 69 | } 70 | resolve(app) 71 | }) 72 | }) 73 | } 74 | 75 | const renderPage = (App, path, opts) => { 76 | let body, css, head 77 | const headTags = [] 78 | const el = React.createElement(ServerLocation, { 79 | basename: opts.basename, 80 | url: path 81 | }, 82 | React.createElement(App, { headTags }) 83 | ) 84 | switch (opts.cssLibrary) { 85 | case 'styled-components': 86 | const { ServerStyleSheet } = require(resolveCWD('styled-components')) 87 | const sheet = new ServerStyleSheet() 88 | body = renderToString( 89 | sheet.collectStyles(el) 90 | ) 91 | css = sheet.getStyleTags() 92 | break 93 | case 'emotion': 94 | const { renderStylesToString } = require(resolveCWD('emotion-server')) 95 | body = renderStylesToString(renderToString(el)) 96 | break 97 | default: 98 | body = renderToString(el) 99 | break 100 | } 101 | head = renderToStaticMarkup(headTags) 102 | return { body, css, head } 103 | } 104 | 105 | const renderHTML = async opts => { 106 | const { default: App, routes } = await getApp(opts) 107 | const headTags = [] 108 | const pages = routes.map(route => { 109 | route.Component.preload() 110 | const { body, css, head } = renderPage(App, route.path, opts) 111 | return Object.assign({ body, head, css }, opts, route) 112 | }) 113 | return pages 114 | } 115 | 116 | module.exports = renderHTML 117 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const path = require('path') 3 | const meow = require('meow') 4 | const chalk = require('chalk') 5 | const open = require('react-dev-utils/openBrowser') 6 | const findUp = require('find-up') 7 | 8 | const name = 'mdx-go' 9 | const config = require('pkg-conf').sync(name) 10 | const { pkg } = require('read-pkg-up').sync() 11 | 12 | const log = (...msg) => { 13 | console.log( 14 | chalk.green(`[${name}]`), 15 | ...msg 16 | ) 17 | } 18 | 19 | log.error = (...msg) => { 20 | console.log( 21 | chalk.red('[err]'), 22 | ...msg 23 | ) 24 | } 25 | 26 | const cli = meow(` 27 | ${chalk.gray('Usage')} 28 | 29 | ${chalk.gray('$')} ${chalk.green(name + ' docs')} 30 | 31 | ${chalk.gray('$')} ${chalk.green(name + ' build docs')} 32 | 33 | ${chalk.gray('Options')} 34 | 35 | -p --port Port for dev server 36 | --no-open Disable opening in default browser 37 | --fullscreen Disable default centered layout 38 | --no-keyboard Disable keyboard shortcuts 39 | 40 | -d --out-dir Output directory for static export 41 | --basename Base path for routing 42 | --static Export HTML without JS bundle 43 | --webpack Path to custom webpack config 44 | 45 | `, { 46 | description: chalk.green(name) + ' Lightning fast MDX-based dev server', 47 | flags: { 48 | help: { 49 | type: 'boolean', 50 | alias: 'h' 51 | }, 52 | version: { 53 | type: 'boolean', 54 | alias: 'v' 55 | }, 56 | port: { 57 | type: 'string', 58 | alias: 'p', 59 | default: '8080' 60 | }, 61 | open: { 62 | type: 'boolean', 63 | alias: 'o', 64 | default: true 65 | }, 66 | fullscreen: { 67 | type: 'boolean' 68 | }, 69 | keyboard: { 70 | type: 'boolean', 71 | default: true 72 | }, 73 | outDir: { 74 | type: 'string', 75 | alias: 'd', 76 | default: 'dist' 77 | }, 78 | basename: { 79 | type: 'string' 80 | }, 81 | static: { 82 | type: 'boolean' 83 | }, 84 | webpack: { 85 | type: 'string' 86 | }, 87 | debug: { 88 | type: 'boolean' 89 | } 90 | } 91 | }) 92 | 93 | require('update-notifier')({ pkg: cli.pkg }).notify() 94 | 95 | const [ cmd, input ] = cli.input 96 | 97 | if (!cmd && !input) { 98 | cli.showHelp(0) 99 | } 100 | 101 | const opts = Object.assign({ 102 | pkg, 103 | name, 104 | dirname: path.resolve(input || cmd), 105 | basename: '', 106 | webpack: findUp.sync('webpack.config.js'), 107 | }, config, cli.flags) 108 | 109 | opts.outDir = path.resolve(opts.outDir) 110 | 111 | if (!opts.cssLibrary && pkg && pkg.dependencies) { 112 | const deps = Object.assign({}, pkg.devDependencies, pkg.dependencies) 113 | if (deps['styled-components']) { 114 | opts.cssLibrary = 'styled-components' 115 | } else if (deps['emotion']) { 116 | opts.cssLibrary = 'emotion' 117 | } 118 | } 119 | 120 | if (opts.webpack) { 121 | opts.webpack = require(path.resolve(opts.webpack)) 122 | } 123 | 124 | switch (cmd) { 125 | case 'build': 126 | log('building...') 127 | const build = require('./lib/build') 128 | build(opts) 129 | .catch(err => { 130 | log.error(err) 131 | process.exit(1) 132 | }) 133 | .then(stats => { 134 | log('built', chalk.gray(opts.outDir)) 135 | }) 136 | break 137 | case 'dev': 138 | default: 139 | log('starting dev server...') 140 | const dev = require('./lib/dev') 141 | dev(opts) 142 | .then(server => { 143 | const { port } = server.address() 144 | const url = `http://localhost:${port}` 145 | log('listening on', chalk.green(url)) 146 | if (opts.open) open(url) 147 | }) 148 | .catch(err => { 149 | log.error(err) 150 | process.exit(1) 151 | }) 152 | } 153 | 154 | -------------------------------------------------------------------------------- /docs/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Flex, Box } from 'rebass' 3 | import { 4 | Banner, 5 | Title, 6 | Text, 7 | Button, 8 | ButtonOutline, 9 | Container, 10 | Col, 11 | Link, 12 | Pre, 13 | Divider, 14 | } from './components' 15 | import Logo from './logo' 16 | export { Root } from './components' 17 | 18 | export const name = 'Home' 19 | 20 | const github = 'https://github.com/jxnblk/mdx-go' 21 | const blog = 'https://jxnblk.com/writing/posts/progressive-documentation' 22 | 23 | const intro = 24 | MDX Go is built with the idea of Progressive Documentation in mind, intended to be used anywhere as a dev server, prototyping tool, or simple static site generator. By embracing the MDX file format, the docs you create with MDX Go can easily be used in other tools. Start your docs with MDX Go, and migrated to tools like Next.js and Gatsby when needed. You can even keep MDX Go around to use as a dev tool outside of other React applications. 25 | 26 | 27 | export default props => 28 | 29 | 30 | 31 | 32 | 38 | Docs 39 | 40 | 46 | GitHub 47 | 48 | 49 | 59 | 62 | 63 | MDX Go 64 | 65 | Lightning-fast MDX-based dev server for progressive documentation 66 | 67 | 70 | 71 | GitHub 72 | 73 |
npm i -g mdx-go
74 |
75 | 78 | 91 |
92 |
93 | 94 | 95 | 96 | {intro} 97 | 98 | 99 | 106 | 107 | Zero-config dev server 108 | 109 | 110 | Write in markdown 111 | 112 | 113 | Import and use React components 114 | 115 | 116 | File-system based routing 117 | 118 | 119 | Customizable layouts 120 | 121 | 122 | Support for styled-components & emotion 123 | 124 | 125 | Export as static HTML 126 | 127 | 128 | Avoid lock-in and easily migrate to other MDX-based tools 129 | 130 | 131 | 132 | 133 | 134 | 135 | 141 | Docs 142 | GitHub 143 | Made by Jxnblk 144 | 145 | 146 | 147 | 150 | 151 | 152 | 153 | 154 | 155 | 156 |
157 | -------------------------------------------------------------------------------- /docs/src/configuration.md: -------------------------------------------------------------------------------- 1 | 2 | # Configuration 3 | 4 | Virtually all MDX Go configuration is handled with React components. 5 | MDX Go follows the philosophy of **components over configuration** instead of using custom plugins architectures and configuration objects in an effort to keep a minimal API surface area. 6 | 7 | You can even write your own components to customize the theme and layout of MDX Go. 8 | 9 | ## Root component 10 | 11 | Using a custom Root component is the primary means of customizing an app in MDX Go. It wraps the entire app with a React component that can provide themes and components via context, add page layouts, and intercept routing. 12 | 13 | To wrap your entire application with a React component, 14 | export a custom `Root` component from your main `index.mdx` file. 15 | Note that a Root component must be exported from the `index.mdx` file and **not** another route. 16 | 17 | ```mdx 18 | export const Root = props => 19 |
20 | {props.children} 21 |
22 | ``` 23 | 24 | Using a custom Root component will override the default centered layout of MDX Go, and can be used to provide custom themes and layouts to every route. 25 | 26 | ### Props 27 | 28 | The Root component will recieve the current page as the `children` prop and receive an array of `routes` for each page. 29 | Each route object will include the following: 30 | 31 | Key | Description 32 | ---|--- 33 | `key` | Key from wepback's `require.context` 34 | `extname` | The file extension of the route 35 | `name` | The file basename 36 | `dirname` | The directory of the file 37 | `path` | Route pathname used for routing 38 | `Component` | React component 39 | 40 | 41 | ## MDX Layouts 42 | 43 | Use a default export to wrap an individual route with a component. 44 | 45 | ```mdx 46 | export default props => 47 |
48 | {props.children} 49 |
50 | 51 | # Page Layout 52 | ``` 53 | 54 | This is a built-in feature of MDX. 55 | Learn more in the [MDX docs](https://mdxjs.com/syntax#export-default). 56 | 57 | ## Head 58 | 59 | To customize the document `` contents, use the `Head` component. 60 | 61 | ```mdx 62 | import { Head } from 'mdx-go' 63 | 64 | 65 | My Page Title 66 | 67 | ``` 68 | 69 | The Head component can be used in individual pages or in a [Root component](#root-component) to add head content across the entire app. 70 | 71 | Read more about the [Head component](/Head) 72 | 73 | ## MDX Components 74 | 75 | MDX includes a mechanism to change the components rendered for each HTML element. 76 | Use the `ComponentProvider` in a Root component to add custom components for MDX. 77 | 78 | ```js 79 | // example Root component 80 | import React from 'react' 81 | import styled from 'react-emotion' 82 | import { ComponentProvider } from 'mdx-go' 83 | 84 | const components = { 85 | h1: styled('h1')({ 86 | color: 'tomato' 87 | }) 88 | } 89 | 90 | export const Root = props => 91 | 92 | {props.children} 93 | 94 | ``` 95 | 96 | 97 | ## Theming 98 | 99 | MDX Go provides minimal styles by default. Use a custom Root component to disable any built-in styles. 100 | 101 | MDX Go contains almost no default styling, making it ideal for use with components that include their own styling. 102 | To add themes or custom styling, wrap your app with a [Root component](configuration/#root-component). 103 | 104 | To use optional, built-in styles, see the [StyleProvider](/StyleProvider) component. 105 | 106 | ## webpack 107 | 108 | The default webpack configuration includes support for Babel, React, and MDX. 109 | To customize the webpack config, add a `webpack.config.js` file to your project root, or pass a path to a custom webpack config via the `--webpack` CLI flag. 110 | The provided webpack config will be merged with the built-in config using [webpack-merge][]. 111 | 112 | [webpack-merge]: https://github.com/survivejs/webpack-merge 113 | 114 | ## Babel 115 | 116 | Add a `babel.config.js` file to customize the Babel configuration. 117 | 118 | ## CLI Options 119 | 120 | The following flags can be passed to the CLI. 121 | 122 | ``` 123 | -p --port Port for dev server 124 | --no-open Disable opening in default browser 125 | -d --out-dir Output directory for static export 126 | --basename Base path for routing 127 | --static Export HTML without JS bundle 128 | --webpack Path to custom webpack config 129 | ``` 130 | 131 | All CLI options can also be specified in an `mdx-go` field in your `package.json`. 132 | 133 | ```json 134 | "mdx-go": { 135 | "outDir": "site" 136 | } 137 | ``` 138 | -------------------------------------------------------------------------------- /docs/src/components.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | Head, 4 | Link as GoLink, 5 | StyleProvider, 6 | } from 'mdx-go' 7 | import { Box, Flex } from 'rebass' 8 | import Sidepane from 'sidepane' 9 | import Logo from './logo' 10 | 11 | const green = '#0d3' 12 | const darkgreen = '#0a6' 13 | const black = '#000619' 14 | const lightgray = '#f6f6ff' 15 | const blue = '#07c' 16 | 17 | 18 | const gradient = ` 19 | linear-gradient( 20 | 150deg, 21 | transparent 90%, 22 | rgba(0, 191, 0, 0.25) 90%, 23 | rgba(0, 191, 0, 0.25) 95%, 24 | rgba(0, 191, 0, 0.5) 95% 25 | ) 26 | ` 27 | 28 | const nav = [ 29 | { path: '/', name: 'Home' }, 30 | { path: '/getting-started', name: 'Getting-Started' }, 31 | { path: '/using-mdx', name: 'Using-MDX' }, 32 | { path: '/routing', name: 'Routing' }, 33 | { path: '/configuration', name: 'Configuration' }, 34 | { path: '/exporting', name: 'Exporting' }, 35 | { path: '/Head', name: 'Head' }, 36 | { path: '/Link', name: 'Link' }, 37 | { path: '/examples', name: 'Examples' }, 38 | { path: 'https://github.com/jxnblk/mdx-go', name: 'GitHub' }, 39 | 40 | // 'ComponentProvider', 41 | // 'Layout', 42 | // 'NavLinks', 43 | // 'Pagination', 44 | // 'StyleProvider', 45 | // 'DocsLayout', 46 | // 'DevLayout', 47 | // Examples 48 | // 'Typography', 49 | ] 50 | 51 | // todo: update 52 | const theme = { 53 | colors: { 54 | lightgray, 55 | black, 56 | blue, 57 | green, 58 | darkgreen, 59 | }, 60 | code: { 61 | color: darkgreen 62 | }, 63 | pre: { 64 | // color: darkgreen 65 | } 66 | } 67 | 68 | const PageLayout = props => props.location.pathname === '/' 69 | ? props.children 70 | : ( 71 | 72 | 74 | 75 | 76 | 77 | 78 | 79 | {nav.map(({ name, path }) => ( 80 | 96 | ))} 97 | {/* 98 | nav.includes(route.name)} 101 | order={nav} 102 | py={2} 103 | /> 104 | 105 | 109 | */} 110 | 111 | 112 | 113 | 114 | {props.children} 115 | 116 | 117 | 118 | ) 119 | 120 | export const Root = props => 121 | 122 | 123 | MDX Go 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | export const Banner = props => 138 | 147 | 148 | export const Title = props => 149 | 158 | 159 | export const Text = props => 160 | 168 | 169 | export const Button = props => 170 | 186 | 187 | export const ButtonOutline = props => 188 |