remark-render
Compiles markdown to Virtual DOM. Built on remark, an extensively tested and pluggable markdown processor.
- Supports raw HTML
- Support VNode keys
- Multiple modes and Optionally settings (hyperscript virtual-dom Vue React snabbdom)
- Custom Renderer / Extend Renderer
Installation
npm:
npm install remark-render
Usage
Say we have the following file, example.js
:
var renderer = require('remark-preact-renderer');
unified().use(render, {
renderer: renderer,
h: h,
rootClassName: 'markdown-body',
rootTagName: 'main'
})
=> <main class="markdown-body"></main>
options
remark | |
---|---|
renderer | framework renderer |
h | create element function |
rootClassName | vdom root element class name |
rootTagName | vdom root element tag type. default is div |
var unified = require('unified')
var parse = require('remark-parse')
var render = require('remark-render')
var h = require('hyperscript');
unified()
.use(parse)
.use(render, {
h: h, // create element function
rootClassName: 'markdown-body' // vdom root element class name,
rootTagName: 'main'
})
.process('# h1 \n## h2', function(err, file) {
if (err) throw err
console.dir(file.contents, {depth: null})
})
Renderers
renderers | |
---|---|
React | remark-preact-renderer |
Preact | remark-react-renderer |
Vue | remark-vue-renderer |
HyperScript | remark-hyperscript-renderer |
snabbdom | remark-snabbdom-renderer |
virtual-dom | remark-virtual-dom-renderer |
morphdom | morphdom |
Examples
Presets provide a potentially sharable way to render. They can contain multiple modes and optionally settings as well.
html
<div id="preview"></div>
HyperScript
npm install remark-render remark-hyperscript-renderer
var unified = require('unified')
var parse = require('remark-parse')
var render = require('remark-render')
var renderer = require('remark-hyperscript-renderer');
var h = require('hyperscript');
unified()
.use(parse)
.use(render, {
renderer: renderer,
h: h,
rootClassName: 'markdown-body'
})
.process('# h1 \n## h2', function(err, file) {
if (err) throw err
console.dir(file.contents, {depth: null})
var preview = document.getElementById('preview');
preview.appendChild(vdom);
})
React
npm install remark-react-renderer
var unified = require('unified')
var parse = require('remark-parse')
var render = require('remark-render')
var renderer = require('remark-react-renderer');
var React = require('react');
var h = React.createElement;
var processor = unified()
.use(parse)
.use(render, {
renderer: renderer,
h: h
});
var file = processor.processSync('# h1');
ReactDOM.render(
file.contents,
document.getElementById('preview')
);
Vue
npm install remark-vue-renderer
var unified = require('unified')
var parse = require('remark-parse')
var render = require('remark-render')
var renderer = require('remark-vue-renderer');
var Vue = require('vue');
var processor = unified()
.use(parse)
.use(render, {
renderer: renderer
}).freeze();
const app = new Vue({
el: '#preview',
render(h) {
var file = processor().data('h', h).processSync('# h1');
return file.contents;
}
});
Writing a custom renderer/Extend a renderer
var unified = require('unified')
var parse = require('remark-parse')
var render = require('remark-render')
var renderer = require('remark-hyperscript-renderer');
var h = require('hyperscript');
renderer.text = function(h, node, children) {
return h('span', {
key: node.properties.key,
style: {'font-size': '60px'}
}, node.value);
};
unified()
.use(parse)
.use(render, {
h: h,
renderer: renderer
})
.process('# h1 \n## h2', function(err, file) {
if (err) throw err
var preview = document.getElementById('preview');
preview.appendChild(vdom);
})
morphdom - Writing a custom renderer.
node MDAST
{
"type": "heading",
"depth": 1 <= number <= 6,
"tagName": "a",
"parent": parent,
"properties": {
"href": "href",
"id": "id",
"className": ["bravo"]
},
"children": []
}
renderer
{
/**
* root element (根元素)
* @param {*} h create element function (构建元素节点函数)
* @param {*} node current node (当前根元素节点)
* node.key is node index if node in array for key. default is 0 (如果当前节点在数组中,返回当前节点在数组中的序列,这是为了构建数组key)
* @param {*} children node create element children (当前节点的子节点)
*/
root : function(h, node, children) {},
text : function(h, node, children) {},
...
}
var unified = require('unified');
var parse = require('remark-parse');
var render = require('remark-render')
var morphdom = require('morphdom');
function createElement(type, props, children) {
let dom = document.createElement(type);
if(props.className) {
dom.className = props.className;
}
if(props.hasOwnProperty('id')) {
dom.id = props.id;
}
dom.appendChild( createElements(children) );
return dom;
}
function createElements(children) {
const doms = document.createDocumentFragment();
children && children.length > 0 && children.forEach(function (dom) {
dom && doms.appendChild(dom);
});
return doms;
}
var renderer = {
root: function(h, node, children) {
return h('div', node.props, children);
},
text: function(h, node, children) {
return document.createTextNode(node.value);
},
blockquote: function(h, node, children) {
return h('blockquote', node.props, children);
},
heading: function(h, node, children) {
return h('h'+node.depth, node.props, children);
}
...
}
var processor = unified()
.use(parse, {})
.use(render, {
renderer: renderer,
h: createElement
});
var file = processor.processSync('# h1\n## h2');
var markdownContainer = file.contents;
var previewContainer = document.getElementById('preview');
morphdom(previewContainer, markdownContainer);