Remark Loader
Load markdown through remark with image resolving and some react-specific features.
Usage
Simply add the loader to your configuration, and pass options.
webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.md$/,
use: [
{
loader: 'remark-loader',
options: {
plugins: [
require('remark-kbd')
]
}
}
]
}
]
}
}
Here's the full list of remark
plugins. Note that remark-html
is always included as the last plugin and should not be included in the plugins
list.
Note that this loader makes use of the [
html-loader
][5] under the hood. The output, without thereact
option enabled, is the default output for thehtml-loader
.
There is one more option called react
. This option causes the loader to emit a JSX module that must be loaded through the babel-loader
. This feature is more of a test and should not be considered safe or reliable -- it's most likely riddled with bugs and weird edge case failures ;). That said, it enables some cool new features that should really be added via some sort of remark
plugin, e.g. remark-react
.
webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.md$/,
use: [
+ 'babel-loader'
{
loader: 'remark-loader',
options: {
+ react: true,
plugins: [
require('remark-kbd')
]
}
}
]
}
]
}
}
Now, in your markdown files, you can take advantage of two new YAML frontmatter attributes:
src/pages/index.md
---
title: An Interactive Page
template: '../components/template'
imports:
Selector: '../components/selector'
---
This page will now be wrapped in the given `template`. The `template` will receive a component containing this markdown via a `markdown` prop. You can pass the `Markdown` component props that will then be available for dynamic insertion here!
For example, let's insert `props.person` within the following blockquote:
> Hello { props.person }!
Not too shabby, huh? Note that for technical reasons you can only dynamically insert values within content (or components as shown )
You can also use any components from the given `imports`. Let's say you had an interactive `Selector` component, you could render it here, while still allowing the parent template to maintain control of its state and callbacks:
<Selector
value={ props.selection }
options={ props.options }
onChange={ props.onSelect } />
src/components/template.jsx
import React from 'react'
export default class Template extends React.Component {
state = {
selection: null
}
render() {
let { markdown: Markdown } = this.props
return (
<Markdown
person="John Doe"
selection={ this.state.selection }
options={[ 'French', 'Dutch', 'German', 'Japanese' ]}
onSelect={ this._changeSelection } />
)
}
_changeSelection = option => {
this.setState({
selection: option
})
}
}
Note that these features are optional, meaning that not every markdown file being processed has to take advantage of them. Also note that this will cause the loader to output a JSX module that will have to be processed further by the
babel-loader
or another transpiler that can handle the conversion of JSX to react statements.
This hack works for now but I'm hoping to discuss these features with the remark
and remark-react
maintainers to brainstorm a more stable implementation. If you have ideas, please create an issue so we can discuss.
Contributing
Pull requests and stars are always welcome. For bugs and feature requests, please create an issue.
Inspiration
This project was inspired the following open source work:
License
MIT (c) 2017