Skip to content

Commit ca7649e

Browse files
author
Jon Sakas
committed
Create markdown-to-react-loader
1 parent 23828cb commit ca7649e

File tree

6 files changed

+229
-1
lines changed

6 files changed

+229
-1
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+

README.md

+80-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,81 @@
11
# markdown-to-react-loader
2-
A Webpack loader for Markdown files to React components
2+
3+
A Webpack loader for converting Markdown files to React components (JSX).
4+
5+
Currently supports ES6 imports and syntax highlighting.
6+
7+
This loader was built for the purpose of documenting React Components, but can be used for other static documents you want to convert to HTML.
8+
9+
Note: Requires React 16.2+
10+
11+
# Installation
12+
13+
```
14+
yarn add markdown-to-react-loader
15+
```
16+
17+
# Usage
18+
19+
First, update your Webpack config.
20+
21+
```
22+
{
23+
test: /\.md$/,
24+
use: [
25+
'babel-loader',
26+
'markdown-to-react-loader',
27+
],
28+
},
29+
```
30+
31+
Then, you can use the loader like:
32+
33+
#### HelloWorld.md
34+
35+
```
36+
# Hello, World
37+
38+
Its great to be here!
39+
```
40+
41+
#### App.js
42+
43+
```
44+
import React from 'react';
45+
import ReactDOM from 'react-dom';
46+
import HelloWorld from './HelloWorld.md';
47+
48+
ReactDOM.Render(<HelloWorld />, document.getElementById('app'));
49+
```
50+
51+
# Imports
52+
53+
You can write ES6 imports inline using front matter.
54+
55+
#### HelloWorldWithImport.md
56+
57+
```
58+
---
59+
imports: |
60+
import { SomeComponent } from './SomeComponent';
61+
---
62+
63+
# Hello, World
64+
65+
Heres a component rendered inline:
66+
67+
<SomeComponent />
68+
69+
```
70+
71+
# Syntax Highlighting
72+
73+
Syntax highlighting is done using PrismJS and is picked up automatically by tagging code blocks:
74+
75+
#### CodeSample.md
76+
77+
# Code Sample
78+
79+
```javascript
80+
console.log('This will be marked for highlighting
81+
```

index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./lib/markdown-to-react-loader');

lib/markdown-to-react-loader.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
const fm = require('front-matter');
2+
const marked = require('marked');
3+
const Prism = require('prismjs');
4+
const renderer = new marked.Renderer();
5+
6+
7+
renderer.code = function(code, lang) {
8+
let className, highlighter, replaced;
9+
10+
// users can easily type in any language they want,
11+
// we don't want the app to blow up in case of bad input.
12+
try {
13+
require(`prismjs/components/prism-${lang}`);
14+
className = `language-${lang}`;
15+
highlighter = Prism.languages[lang];
16+
} catch (e) {
17+
console.warn(`Could not find PrismJS language ${lang}`);
18+
className = '';
19+
highlighter = '';
20+
}
21+
22+
try {
23+
const wrapped = Prism.highlight(code, highlighter);
24+
replaced = wrapped.replace(/\n/g, '<br />');
25+
} catch (e) {
26+
console.error(`Failed to highlight syntax for language ${lang}`);
27+
console.error(e);
28+
29+
// fallback to the original input on error
30+
replaced = code;
31+
}
32+
33+
return `
34+
<pre class="${className}">
35+
<code class="${className}">
36+
${replaced}
37+
</code>
38+
</pre>
39+
`;
40+
};
41+
42+
module.exports = function (source, map) {
43+
const parsed = fm(source);
44+
const html = marked(parsed.body, {
45+
renderer: renderer,
46+
xhtml: true,
47+
});
48+
49+
const replaced = html
50+
.replace(/class="/g, 'className="')
51+
.replace(/\(/g, '&#40;')
52+
.replace(/\)/g, '&#41;')
53+
.replace(/\{/g, '&#123;')
54+
.replace(/\}/g, '&#125;');
55+
56+
const processed = `
57+
import React, { Fragment } from 'react';
58+
${parsed.attributes.imports ? parsed.attributes.imports : ''}
59+
export default (<Fragment>${replaced}</Fragment>);
60+
`;
61+
62+
return processed;
63+
};

package.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "markdown-to-react-loader",
3+
"version": "1.0.0",
4+
"description": "A Webpack loader for converting Markdown files to React components",
5+
"main": "index.js",
6+
"repository": "[email protected]:jsakas/markdown-to-react-loader.git",
7+
"author": "Jon Sakas <[email protected]>",
8+
"license": "MIT",
9+
"dependencies": {
10+
"front-matter": "^2.1.2",
11+
"marked": "^0.3.12",
12+
"prismjs": "^1.10.0"
13+
},
14+
"peerDependencies": {
15+
"react": "^16.2"
16+
}
17+
}

yarn.lock

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+
# yarn lockfile v1
3+
4+
5+
argparse@^1.0.7:
6+
version "1.0.10"
7+
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
8+
dependencies:
9+
sprintf-js "~1.0.2"
10+
11+
clipboard@^2.0.0:
12+
version "2.0.1"
13+
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.1.tgz#a12481e1c13d8a50f5f036b0560fe5d16d74e46a"
14+
dependencies:
15+
good-listener "^1.2.2"
16+
select "^1.1.2"
17+
tiny-emitter "^2.0.0"
18+
19+
delegate@^3.1.2:
20+
version "3.2.0"
21+
resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
22+
23+
esprima@^4.0.0:
24+
version "4.0.1"
25+
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
26+
27+
front-matter@^2.1.2:
28+
version "2.3.0"
29+
resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.3.0.tgz#7203af896ce357ee04e2aa45169ea91ed7f67504"
30+
dependencies:
31+
js-yaml "^3.10.0"
32+
33+
good-listener@^1.2.2:
34+
version "1.2.2"
35+
resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
36+
dependencies:
37+
delegate "^3.1.2"
38+
39+
js-yaml@^3.10.0:
40+
version "3.12.0"
41+
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
42+
dependencies:
43+
argparse "^1.0.7"
44+
esprima "^4.0.0"
45+
46+
marked@^0.3.12:
47+
version "0.3.19"
48+
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790"
49+
50+
prismjs@^1.10.0:
51+
version "1.15.0"
52+
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.15.0.tgz#8801d332e472091ba8def94976c8877ad60398d9"
53+
optionalDependencies:
54+
clipboard "^2.0.0"
55+
56+
select@^1.1.2:
57+
version "1.1.2"
58+
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
59+
60+
sprintf-js@~1.0.2:
61+
version "1.0.3"
62+
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
63+
64+
tiny-emitter@^2.0.0:
65+
version "2.0.2"
66+
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c"

0 commit comments

Comments
 (0)