Markdown + frontmatter -> dynamically generated vuex stores + more.
Markdown + frontmatter -> dynamically generated vuex stores + more.
This project is pre-alpha and you should 100% not use it in a production environment!
fs.promises
(experimental API, requires node > 8
I believe).Finally, you should check out NuxtPress because it does kind of a similar-ish (but not really) thing but probably in a far far better way.
I chose to use Nuxt for my personal site and at some point decided that I wanted some kind of custom blog system.
It needed to allow one to:
So I worked on that for a little while and got it to a stage where I was vaguely happy with it (at least functionality-wise, as a proof of concept or early prototype).
At some point, I thought to myself - wouldn’t it be cool if I could use a similar system for the projects section of my site.
So I created a branch on my website repository and started playing with that idea. Then I figured, what the heck - why not just try to make it into a module/plugin? And here we are.
It basically takes directories that contain markdown files that contain YAML front matter and builds “entities” and the relationships (e.g. hasMany
) between them.
All of this gets dumped into JSON which in turn is pulled into Vuex. Also, getters/setters are dynamically generated for us to help us with our relationships (please note that it doesn’t help you with your real life relationships).
Finally, the DynamicMarkdown component helps us to quickly/easily render our strange Frankensteinesque creation.
If that didn’t make any sense then try the walkthrough!
You can check out the live demo if you’re so inclined.
The live demo is simply this example project deployed to Netlify.
If you don’t already have a nuxt project then create one:
IMPORTANT: Make sure to enable Vuex when prompted.
npx create-nuxt-app my-project
With either npm or yarn:
npm install --save nuxt-dynamic-markdown
# or
yarn add nuxt-dynamic-markdown
In nuxt.config.js
:
import NuxtDynamicMarkdown from "nuxt-dynamic-markdown";
export default {
modules: [
[
NuxtDynamicMarkdown,
{
/*
Sources are how you tell NDM what to load,
where from and how you define your relationships.
IMPORTANT: This data-source is presumed to be
present for the duration of this README.
*/
sources: [
{
nested: false,
name: "projects",
directory: "projects",
relationships: ["keywords"]
}
]
}
]
]
};
Installation complete. Well done, you made it this far!
Okay. Presume we have a directory called contents
in our Nuxt project with the following structure:
contents/
projects/
my-first-project/
content.md
And the following content.md
file:
---
title: Foo Project
keywords: [foo, bar, baz]
description: I am foo project!
components: [Bar]
---
# Foo
I am foo project! The one! The only!
## Attributes (frontmatter)
My keywords are: {{ keywords.join(", ") }}.
### Custom attributes
This is a custom attribute:
{{ custom }}
## Components
This is a component:
<Bar ></Bar>
Isn't it great?
There’s a lot going on there so let’s break it down:
keywords
and description
populate <meta>
.NOTE: Currently you must mix in the
getMeta
andsetHead
mixins in order for<meta>
to be populated.
The special attribute components
allows you to make components available within the markdown file.
The markdown can be anything you want, there are no real restrictions.
Next, we’ll create a projects
folder in pages
and within it we’ll create two files.
The first file will be called _project.vue
and will display an individual project:
<template>
<section>
<DynamicMarkdown
v-bind="project"
:custom-attributes="{ custom: 'Hello!' }"
></DynamicMarkdown>
</section>
</template>
<script>
import { getMeta, setHead, asyncData } from "nuxt-dynamic-markdown/lib/mixin";
export default {
mixins: [getMeta, setHead],
asyncData
};
</script>
Since the route parameter for a Nuxt page called _project.vue
is project
then the entity will be available via this.project
.
So we simply pass this in to the DynamicMarkdown.vue
component, which renders it for us.
NOTE: It’s important that you pass it in exactly as above -
v-bind="entity"
.
As you can see, this is also where we pass in the custom attributes mentioned earlier.
For now it is required that you, at a minimum, import the asyncData
helper and pass it to your component.
The getMeta
and setHead
mixins on the other hand are not required to be used.
Ideally none of this boilerplate would be necessary but for the time being it is, unfortunately.
I intend to look into ways to reduce and/or remove it.
The second file will be called index.vue
and will list all projects:
<template>
<section>
<h1>My Projects</h1>
<ul>
<li v-for="project in projects">
<nuxt-link
:to="{
name: 'projects-project',
params: { project: projectName }
}"
>
{{ project }}
</nuxt-link>
</li>
</ul>
</section>
</template>
<script>
import { getEntities } from "nuxt-dynamic-markdown/lib/mixin";
export default {
asyncData: getEntities("projects")
};
</script>
For this case (index/listing pages), it is not required that you use the getEntities
helper.
If you wanted to, you could just as well create a computed property that simply accesses the Vuex store - it’s roughly the same amount of code, to be honest.
Bar
componentFinally we’ll create a file called Bar.vue
in components
since we referenced it in our content.md
file earlier.
<template>
<div>
<p>I am bar component.</p>
</div>
</template>
If the stars were aligned properly and you uttered the incantations with the correct stress and prosody then you should see something like this:
NOTE: You may see something slightly more simple-looking presuming you didn’t use our example project (which uses Bulma).