Shuji is a Markdown to React JSX converter! It supports markdown including html, css, js, and even front-matter.
It was originally designed for being able to write blog files without the overhead of a framework like gatsby or jekyll. Templating frameworks used to be very beneficial, but often come with their own complexities and the biggest problem: you lose control over your build system. I got tired of waiting for bug-fixes, library updates, and having to work around their configurations. I just wanted an easy way to easily generate new blog articles without the overhead.
- Convert Markdown
.md
files to.jsx
files. It supports html, css, and js within markdown and front-matter support - Design and organize your own folder structure however you want
- Configure your build system however you want. You can use webpack, parcel, rollup, or whichever you prefer
- Easily and automatically generate new articles/pages from markdown files
- Extract front-matter metadata into a react context
.md
files within a provided folder (default:/markdown
) will be converted to.jsx
files containing an exported react functional component and generated in the provided output folder (default:/jsxMarkdown
).- If front-matter is detected, it is converted to react helmet format by default or the alternative react context object format for improved customization.
- See format examples below
- If you don't want to have Shuji parse front-matter, you can use a plugin to process it before Shuji runs.
- Shuji can be run through the CLI, as a library, or integration with your build tool (webpack, parcel, etc.)
- You can choose to run it against a folder or feed the
.md
string directly to Shuji.
- You can choose to run it against a folder or feed the
yarn add --dev shuji
or
npm install --dev shuji
package.json:
{
"scripts": {
"buildjsx": "shuji -h"
}
}
Alternatively, you can install shuji globally if you prefer not using yarn/npm scripts
Run shuji
with the -h
help command to see the full list of CLI options
Option 2: Directly import the package
yarn add --dev shuji
or
npm install --dev shuji
Import and call the async method transformMarkdownFiles
which takes an options
object and returns a 0
upon success or a 1
if there's an error.
import { transformMarkdownFiles } from 'shuji'
const shujiOptions = {
inputPath: 'blogArticles',
outputPath: 'compiledArticles'
}
const isSuccessful = await transformMarkdownFiles(shujiOptions)
Call the async method transformMarkdownFiles
which takes an options
object and returns a react component string
upon success or an ''
string if there's an error.
import { transformMarkdownString } from 'shuji'
const myMarkdownString = getMyString()
const shujiOptions = {
inputPath: 'blogArticles',
outputPath: 'compiledArticles'
}
const jsxString = await transformMarkdownString(myMarkdownString, shujiOptions)
Check out the properties of the options
object.
Option 3: Use the Parcel plugin
Install the parcel plugin
yarn add --dev parcel-plugin-shuji
or
npm install --dev parcel-plugin-shuji
Parcel will automatically look for .md
files in the ./markdown
folder and compile them into the ./jsxMarkdown
folder.
You can configure several options by adding a shuji.config.json
or .shujirc.json
file in your root directory and parcel will automatically load it.
See options below
Option 4: Use the Webpack plugin
...coming soon~
Front matter itself is a convention borrowed from books describing the title, contents, etc. In code it represents the meta data around an article like title, date, author, description, etc.
Front matter can be written in YAML
or JSON
format at the beginning of each markdown file
Here's an example format:
---
title: Hello World
date: 2013/7/13 20:46:25
---
"title": "Hello World",
"date": "2013/7/13 20:46:25"
;;;
See the front-matter example for the output
input: articles/simple.md
# Hello World
## test
This is a markdown test. Isn't markdown awesome?
### Reasons to use this
- It's awesome
- It's lightweight
- It doesn't replace your build pipeline.
output: jsxPages/simple.jsx
export const Simple = () => {
return (
<div className='simple'>
<h1>Hello World</h1>
<h2>test</h2>
<p>This is a markdown test. Isn't markdown awesome?</p>
<h3>Reasons to use this</h3>
<ul>
<li>It's awesome</li>
<li>It's lightweight</li>
<li>It doesn't replace your build pipeline.</li>
</ul>
</div>
)
}
input: articles/frontmatterexample.md
---
date: "2021-01-01"
title: node with react and redux
slug: node-react-redux
description: How to node with react and redux
tags:
- node
- react
- redux
---
# Node with react redux
## test
This with a test with yaml front matter.
Node react stuffs
### Reasons to use this
- It's awesome
- It's lightweight
- It doesn't replace your build pipeline.
#### The end
output: jsxPages/frontmatterexample.jsx
import { Helmet } from 'react-helmet'
export const Frontmatterexample = () => {
return (
<div className='frontmatterexample'>
<Helmet>
<meta name="date" content="2021-01-01" />
<title>node with react and redux</title>
<meta name="slug" content="node-react-redux" />
<meta name="description" content="How to node with react and redux" />
<meta name="tags" content="node,react,redux" />
</Helmet>
<h1>Node with react redux</h1>
<h2>test</h2>
<p>This with a test with yaml front matter.
Node react stuffs</p>
<h3>Reasons to use this</h3>
<ul>
<li>It's awesome</li>
<li>It's lightweight</li>
<li>It doesn't replace your build pipeline.</li>
</ul>
<h4>The end</h4>
</div>
)
}
If you set frontMatterMode='reactHead'
enabling the reactHead format, it will output your front-matter using a react context like this:
import { ReactHeadContext } from 'reactHead'
export const Frontmatterexample = () => {
const [reactHead, setReactHead] = useContext('ReactHeadContext')
setReactHead({
...reactHead,
date = '2021-01-01',
title = 'node with react and redux',
slug = 'node-react-redux',
description = 'How to node with react and redux',
tags = ['node','react','redux'],
})
return (
<div className='frontmatterexample'>
<h1>Node with react redux</h1>
<h2>test</h2>
<p>This with a test with yaml front matter.
Node react stuffs</p>
<h3>Reasons to use this</h3>
<ul>
<li>It's awesome</li>
<li>It's lightweight</li>
<li>It doesn't replace your build pipeline.</li>
</ul>
<h4>The end</h4>
</div>
)
}
Note: you will need to set up a custom module alias if your imported reactHead
context is in another folder level.
You can add this to your tsconfig.json
or jsconfig.json
By default, no options are required.
inputPath
(string
, default:'markdown'
)
Target folder or file with.md
files for Shuji to parse.outputPath
(string
, default:'jsxMarkdown'
)
Output destination folder to write the compiled.jsx
files.frontMatterMode
(string
, default:reacthelmet
)
Toggle output style of front matter. true uses react helmet syntax. false will set react context values you have more control over. This is referred to as "reactHead"reactHeadContextName
(string
, default:'ReactHeadContext'
)
The reactHead context name in which any detected front-matter will be set throughuseContext('${reactContextName}')
reactHeadContextVarName
(string
, default:'reactHead'
)
The name of the reactHead context object and set method assigned fromuseContext('${reactContextName}')
. ex.const [${yourVar}, set${YourVar}]
.
note: first letter will be automatically be lower case for the object and upper-cased for the set methoddeleteExistingOutputFolder
(boolean
, default:false
)
Delete existing content in the output folder (outputFolderPath
) before writing compiled fileslogLevel
(number
, default:2
)
Set the log level.1
=debug mode,2
=default,3
= no logs
react-component-name
(string
)
For setting the react component name. Useful if you want to name your component something different than the filename. Useful if your file names begin with a date. Example: filename:2030-02-02-shuji-is-awesome.md
, front matter:react-component-name:shujiIsAwesome
output:const ShujiIsAwesome = ...
title
(string
)
For replacing the page title<title>{shuji}</title>
description
(string
)
Description for your post.<meta name="description" content="{Shuji is awesome!}">
keywords
(string
)
SEO Keywords for your post.<meta name="keywords" content="{[shuji, react, markdown]}">
date
(string
)
Published Date. No official html5 support tag, so placed in a meta tag<meta name="date" content="{2030-01-01}">
tags
(array
)
Tags to categorize your post. No official html5 support tag, so placed in a meta tag<meta name="tags" content="{[shuji, react, markdown]}">
link
(array
)
Permanent/canonical/pretty url for your post. Replaces<link rel='canonical' href='{https://github.com/ermish/shuji}' />
your custom option
(string
)
You can add any additional front matter and it will be placed a meta tag based on the name.<meta name="hello" content="{world}">
These front matter options will be added to <Helmet>{front matter options}</Helmet>
These front matter options will be added to a react context.
This will not import react-helmet
and will not set anything in the <head>
section by default. This mode provides the ability to manage how you want to update the head.
Front-matter will be ignored.
- Fix parcel plugin
- Webpack support
- Improve logging
MIT