Use your markdown as Vue SFC, check out the Demo here.
remark-vue-loader
is a webpack loader that process your markdown file and transform into a Vue SFC (Single-File Component).
remark-vue-loader
fully embraces the power of AST, it uses unified and Babel under the hood.
Also, it allows you to write your own AST transformer, and hook into the lifecycle of the loader process, make it eazy to extend.
To begin, you'll need to install remark-vue-loader
:
# using yarn
yarn add remark-vue-loader -D
# using npm
npm install remark-vue-loader -D
Then add the loader into your webpack
config, for example:
module.export = {
module: {
rules: [
{
test: /\.md$/,
use: ['vue-loader', 'remark-vue-loader']
}
]
}
}
Make sure to place vue-loader
after the remark-vue-loader
in the loader chain !
You can reference Vue components directly in markdown:
# Hello World
<SomeComponent />
Before you do that, you need to specify where to find the component, add a components
option in loader options:
module.export = {
module: {
rules: [
{
test: /\.md$/,
use: [
{
loader: 'vue-loader'
},
{
loader: 'remark-vue-loader',
options: {
components: [
'../src/components/*.vue'
]
}
}
]
}
]
}
}
You can use glob pattern to find all the components.
Notice that, if you use glob pattern, all the components will be registered using Pascal Case of the component's file name, for example:
some-component.vue -> SomeComponent
, then you can either use <some-component></some-component>
or <SomeComponent />
to reference the component in markdown.
you can also specify the components using object format, but the property value
must be a specific file:
components: {
'someComponent': '../src/components/some-component.vue'
}
And if you change the content of any of theres component file, the loader result will immediately regenerate.
There's another powerful feature that lets you write Vue single-file component code in markdown, that is the custom container, just like markdown-it-container
remark-vue-loader
has a builtin custom container block support for Vue SFC, for example:
This is normal markdown paragraph
::: SFC
<template>
<h1>{{msg}}</h1>
</template>
<script>
export default {
data () {
return {
msg: 'Hello World'
}
}
}
</script>
:::
As you see above, the SFC
container will be rendered as its content, you can even write import
statements inside the script
block
You can check out more examples in the online demo.
What's more, you can even define your own custom blocks, it will be covered later.
One other feature, is that you can write your own transformer to manipulate the markdown ast.
First, specify your trnasformer in loader options:
module.export = {
module: {
rules: [
{
test: /\.md$/,
use: [
{
loader: 'vue-loader'
},
{
loader: 'remark-vue-loader',
options: {
transformers: [
function MyTransformer (ast, options) {
ast.children.forEach(node => {
if (node.type === 'heading') {
const value = node.children[0].value
node.type = 'html'
node.value = `<h${node.depth} style="color: DarkViolet;">${value}</h${node.depth}>`
delete node.children
}
})
return ast
}
]
}
}
]
}
]
}
}
The example above defines a transformer which turns all the heading
into HTML tag and set their color to DarkViolet
.
Transformers are just pure functions that receive ast and return new ast, yet ast is far more convenient that plain text in the aspect of manipulating.
There are different stages throughout the lifecycle of loader's process, which are preprocess
, beforetransform
, aftertransform
, postprocess
:
You can hook into theres different stages by providing lifecycle methods in loader options, and leverage your own functionality to process the ast or raw sources.
There is also an api
for you to use during some of the lifecycle which provide some convenient functionalities like adding
components, add containers etc.
You can find details about these functions in later chapters.
Name | Type | Default | Description |
---|---|---|---|
context |
String |
loader.rootContext |
Base path for resolving components and watch files |
cahce |
Boolean |
true |
Whether loader result is cacheable |
preprocess |
Function |
- | Hook function to be executed before parsing markdown into an ast |
beforetransform |
Function |
- | Hook function to be executed before applying transformers to markdown ast |
aftertransform |
Function |
- | Hook function to be executed after transformers applied to markdown ast |
postprocess |
Function |
- | Hook function to be executed when markdown transformed into a vue single file component |
components |
Object|Array |
[] |
Components which should be resolved and registered in markdown |
transformers |
Array |
[] |
An array of transformers to manipulate the markdown ast |
watchFiles |
Array |
[] |
Files which should be included as dependencies of the loader result |
Type: String
Default: loader.rootContext
context
is the base directory of your modules, it will be used as a base path for resolving components and watch files.
Type: Boolean
Default: true
Whether loader result is cacheable, we strongly recommend setting it to true
Type: Array
Default: []
You can define sets of functions in transformers
, the member of transformers
must be a function.
Type: Function
Arguments: ast
Transformer function are just pure function that recieve the ast object, and must return a new ast object.
Note: all newly returned ast must comply the Mdast format
Type: Function
Default: value => value
Arguments: content
Handling raw markdown content before any transformation applies.
Return value will be used for further processing.
Type: Function
Default: (ast, api) => {}
Arguments: (ast, api)
Handling markdown ast before any ast transformers apply to the markdown ast.
You don't need to return ast explicitly, just manipulate the ast object directly.
Type: Function
Default: (ast, api) => {}
Arguments: (ast, api)
Handling markdown ast after all the ast transformers were applied to the markdown ast. Also, using api.addContainer
is meaningless in this phase, becauce container handler get evaluated along with those transformers.
You don't need to return ast explicitly, just manipulate the ast object directly.
Type: Function
Default: sfc => sfc
Arguments: sfc
In this phase, the original markdown content has transformed into Vue SFC
. You must explicitly return a vaild Vue SFC code if you desire to using this hook function.
Type: Array|Object
Default: []
Type: Array
Default: []
Array of glob patterns. Files that match these glob patterns will be added as dependencies of loader result, changes of these files will cause loader to re-process the content.
If you specify relative path, it will be resolved from options.context
.
Give a ⭐️ if this project helped you! PR are welcomed.