diff --git a/app/components/CodeBlock/CodeBlock.js b/app/components/CodeBlock/CodeBlock.js new file mode 100644 index 0000000..dcd6e15 --- /dev/null +++ b/app/components/CodeBlock/CodeBlock.js @@ -0,0 +1,22 @@ +import React from 'react' +import Highlight, { defaultProps } from 'prism-react-renderer' + +export default function CodeBlock({ children, className }) { + const language = className.replace(/language-/, '') + + return ( + + {({ className, style, tokens, getLineProps, getTokenProps }) => ( +
+          {tokens.map((line, i) => (
+            
+ {line.map((token, key) => ( + + ))} +
+ ))} +
+ )} +
+ ) +} diff --git a/app/components/CodeBlock/CodeBlock.stories.js b/app/components/CodeBlock/CodeBlock.stories.js new file mode 100644 index 0000000..e242500 --- /dev/null +++ b/app/components/CodeBlock/CodeBlock.stories.js @@ -0,0 +1,22 @@ +import React from 'react' +import CodeBlock from './CodeBlock' + +export default { title: 'CodeBlock' } + +export const JS = () => ( + +{`const a = doSomething() +const b = new Thing([ + a, b, c +])`} + +) + +export const CSS = () => ( + +{`.foo { + color: red; + background: url('blah.jpg') +}`} + +) diff --git a/app/components/cssReset.js b/app/components/cssReset.js index 8fa7a1f..2d2b8fc 100644 --- a/app/components/cssReset.js +++ b/app/components/cssReset.js @@ -1,8 +1,17 @@ export default function cssReset (felaRenderer) { felaRenderer.renderStatic({ + boxSizing: 'border-box', fontSize: '16px', fontFamily: 'sans-serif', lineHeight: 1.5, margin: 0 + }, ':root') + + felaRenderer.renderStatic({ + boxSizing: 'inherit', + }, '*, *:before, *:after') + + felaRenderer.renderStatic({ + margin: 0 }, 'body') } diff --git a/app/pages/example-post.mdx b/app/pages/example-post.mdx index b4abb7f..ea48b47 100644 --- a/app/pages/example-post.mdx +++ b/app/pages/example-post.mdx @@ -36,6 +36,14 @@ import ExamplePostList from '../components/ExamplePostList/ExamplePostList' --- +```javascript +function example () { + console.log('Code syntax highlighting works too!') +} +``` + +--- + Remember, components are only prerendered by default. If you want to automatically [hydrate](https://reactjs.org/docs/react-dom.html#hydrate) a component on the client, you'll need to import a component wrapped with the `asIsland` higher order component. diff --git a/app/prerender.js b/app/prerender.js index b0c1f6d..90f904e 100644 --- a/app/prerender.js +++ b/app/prerender.js @@ -20,17 +20,19 @@ import { createRenderer } from 'fela' import { RendererProvider } from 'react-fela' import { renderToMarkup } from 'fela-dom' import { Helmet } from 'react-helmet' +import { MDXProvider } from '@mdx-js/react' import cssReset from './components/cssReset' import DefaultLayout from './layouts/DefaultLayout' +import CodeBlock from './components/CodeBlock/CodeBlock' -export default function prerender (manifest, mode) { +export default function prerender(manifest, mode) { /* 1. Require every JS and MDX file in the `pages` directory and create a useful collection of 'page' objects. (uses Webpack's context module API, see https://webpack.js.org/guides/dependency-management/) */ const pages = [] const req = require.context('./pages', true, /^(?!.*\/_).*(js|mdx)$/) - req.keys().forEach(sourceFilePath => { + req.keys().forEach((sourceFilePath) => { const pageModule = req(sourceFilePath) const sourceFile = path.parse(sourceFilePath) @@ -52,7 +54,6 @@ export default function prerender (manifest, mode) { const pageProps = { posts } buildJSONFeedFile(pageProps) - /* 3. Build a HTML file for each page */ @@ -68,20 +69,13 @@ export default function prerender (manifest, mode) { }) } -function collectPosts (pages) { +function collectPosts(pages) { return pages .filter((page) => page.meta && page.meta.collection === 'posts') .sort((a, b) => new Date(b.meta.date) - new Date(a.meta.date)) } -function buildPageFile ({ - PageComponent, - meta, - urlPath, - manifest, - mode, - pageProps = {} -}) { +function buildPageFile({ PageComponent, meta, urlPath, manifest, mode, pageProps = {} }) { // 1. Create a Fela renderer to be provided for components in the page const felaRenderer = createRenderer({ devMode: mode === 'development' @@ -93,9 +87,16 @@ function buildPageFile ({ const Layout = meta.Layout || DefaultLayout const bodyHTML = ReactDOMServer.renderToString( - - - +
, + code: CodeBlock + }} + > + + + + ) @@ -114,7 +115,7 @@ function buildPageFile ({ if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true }) const outputFilePath = `${outputDir}/index.html` - fs.writeFile(outputFilePath, renderedDocument, err => { + fs.writeFile(outputFilePath, renderedDocument, (err) => { if (err) throw err console.log(chalk.green(`🏝 Page built: ${outputFilePath}`)) }) @@ -122,15 +123,11 @@ function buildPageFile ({ // Get clean URLs by naming all HTML files `index.html` in a folder with the same name as the source file. // (except source files called `index` - they can be output in place) -function cleanURLPathForPage (sourceFile) { - return path.join( - '/', - sourceFile.dir, - sourceFile.name === 'index' ? '' : sourceFile.name - ) +function cleanURLPathForPage(sourceFile) { + return path.join('/', sourceFile.dir, sourceFile.name === 'index' ? '' : sourceFile.name) } -function buildJSONFeedFile (pageProps) { +function buildJSONFeedFile(pageProps) { const { siteURL, feedTitle } = packageJSON.tropical const { posts } = pageProps @@ -157,18 +154,13 @@ function buildJSONFeedFile (pageProps) { const outputFilePath = path.resolve(__dirname, '../output/feed.json') - fs.writeFile(outputFilePath, JSON.stringify(feed), err => { + fs.writeFile(outputFilePath, JSON.stringify(feed), (err) => { if (err) throw err console.log(chalk.green(`🏝 JSON Feed built: ${outputFilePath}`)) }) } -function documentTemplate ({ - stylesHTML, - bodyHTML, - helmet, - clientBundlePath -}) { +function documentTemplate({ stylesHTML, bodyHTML, helmet, clientBundlePath }) { return ` @@ -184,3 +176,10 @@ function documentTemplate ({ ` } + +// By default prism-react-renderer only includes a subset of the languages Prism supports +// https://github.com/FormidableLabs/prism-react-renderer#faq +// Uncomment this to enable syntax highlighting for additional languages; +// import Prism from 'prism-react-renderer/prism' +// ;(typeof global !== 'undefined' ? global : window).Prism = Prism +// require('prismjs/components/prism-ruby') diff --git a/package.json b/package.json index 8b7611d..9baa2c7 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@babel/preset-env": "^7.8.4", "@babel/preset-react": "^7.8.3", "@mdx-js/loader": "^1.5.5", + "@mdx-js/react": "^1.6.16", "@storybook/react": "^5.3.13", "babel-loader": "^8.0.6", "chalk": "^4.1.0", @@ -20,6 +21,7 @@ "fela": "^11.1.2", "fela-dom": "^11.1.2", "file-loader": "^6.0.0", + "prism-react-renderer": "^1.1.1", "react": "^16.12.0", "react-dom": "^16.12.0", "react-fela": "^11.1.2", diff --git a/yarn.lock b/yarn.lock index d8577ae..42614f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1328,6 +1328,11 @@ resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.14.tgz#20c64d6691a894227cd04006b620e5fff85f79b1" integrity sha512-WN4OWXiSTN5x1Ee0ZeYQ9bjjSSgH3Mfx/ezcSV3T691C/PcHTNWwJa5qhcuq8V/NrVAeMc26aXuSdOAq6sRb1g== +"@mdx-js/react@^1.6.16": + version "1.6.16" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.16.tgz#538eb14473194d0b3c54020cb230e426174315cd" + integrity sha512-+FhuSVOPo7+4fZaRwWuCSRUcZkJOkZu0rfAbBKvoCg1LWb1Td8Vzi0DTLORdSvgWNbU6+EL40HIgwTOs00x2Jw== + "@mdx-js/util@1.6.14": version "1.6.14" resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.14.tgz#e3c14aef1c721b79ca7afa4d54ed7b5817a973c7" @@ -7233,6 +7238,11 @@ pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= +prism-react-renderer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.1.1.tgz#1c1be61b1eb9446a146ca7a50b7bcf36f2a70a44" + integrity sha512-MgMhSdHuHymNRqD6KM3eGS0PNqgK9q4QF5P0yoQQvpB6jNjeSAi3jcSAz0Sua/t9fa4xDOMar9HJbLa08gl9ug== + prismjs@^1.8.4: version "1.20.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.20.0.tgz#9b685fc480a3514ee7198eac6a3bf5024319ff03"