{"id":18074102,"url":"https://github.com/sustained/nuxt-dynamic-markdown","last_synced_at":"2026-04-09T07:02:01.298Z","repository":{"id":44080624,"uuid":"203699302","full_name":"sustained/nuxt-dynamic-markdown","owner":"sustained","description":"Markdown + frontmatter -\u003e dynamically generated vuex stores + more.","archived":false,"fork":false,"pushed_at":"2023-01-07T08:57:17.000Z","size":405,"stargazers_count":2,"open_issues_count":18,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-05T18:52:09.844Z","etag":null,"topics":["blog","dynamic","frontmatter","markdown","nuxt","nuxt-module","nuxtjs","relationship","state","store","vue","vuejs","vuex","yaml"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sustained.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-22T02:28:13.000Z","updated_at":"2020-06-02T14:37:18.000Z","dependencies_parsed_at":"2023-02-06T17:46:08.084Z","dependency_job_id":null,"html_url":"https://github.com/sustained/nuxt-dynamic-markdown","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/sustained/nuxt-dynamic-markdown","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sustained%2Fnuxt-dynamic-markdown","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sustained%2Fnuxt-dynamic-markdown/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sustained%2Fnuxt-dynamic-markdown/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sustained%2Fnuxt-dynamic-markdown/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sustained","download_url":"https://codeload.github.com/sustained/nuxt-dynamic-markdown/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sustained%2Fnuxt-dynamic-markdown/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268281846,"owners_count":24225160,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-01T02:00:08.611Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blog","dynamic","frontmatter","markdown","nuxt","nuxt-module","nuxtjs","relationship","state","store","vue","vuejs","vuex","yaml"],"created_at":"2024-10-31T10:11:15.604Z","updated_at":"2025-12-30T21:52:28.324Z","avatar_url":"https://github.com/sustained.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nuxt-dynamic-markdown\n\n\u003e Markdown + frontmatter -\u003e dynamically generated vuex stores + more.\n\n## Table of Contents\n\n- [Disclaimer](#disclaimer)\n- [Rationale / Origin](#rationale--origin)\n  - [Evolution](#evolution)\n- **[What is it?](#what-is-it)**\n- **[What does it look like?](#what-does-it-look-like)**\n  - **[Example project](#example-project)**\n- **[How do I install it?](#how-do-i-install-it)**\n  1. [Create nuxt project](#create-nuxt-project)\n  2. [Install the module](#install-the-module)\n  3. [Register the module](#register-the-module)\n- **[Walkthrough / guide](#walkthrough--guide)**\n  - [Directory structure](#directory-structure)\n  - [Defining entities](#defining-entities)\n    - [YAML front matter](#yaml-front-matter)\n    - [Registering components](#registering-components)\n    - [Markdown content](#markdown-content)\n  - [Creating pages](#creating-pages)\n    - [The view project page](#the-view-project-page)\n      - [Accessing the entity](#accessing-the-entity)\n      - [Passing custom attributes](#passing-custom-attributes)\n      - [Mixins and helpers (entity)](#mixins-and-helpers-entity)\n      - [A note on boilerplate](#a-note-on-boilerplate)\n    - [The project listing page](#the-project-listing-page)\n      - [Mixins and helpers (index)](#mixins-and-helpers-index)\n    - [Creating the component](#creating-the-bar-component)\n  - [Result](#result)\n    - [Notes](#notes-result)\n\n---\n\n## Disclaimer\n\nThis project is **pre-alpha** and you should 100% not use it in a production environment!\n\n- Some parts of the code don't have proper error checking.\n- **There are no tests**. Zero. Nada. Keine. Zilch.\n- I haven't tried running any of this in other browsers; on other OSes; with different versions of Nuxt, Vue etc. nor can I guarantee that it works in parallel dimensions, different universes or alternate timelines.\n- It currently relies on `fs.promises` (experimental API, requires `node \u003e 8` I believe).\n- This README presumes a decent understanding of both Nuxt and Vue.\n- Just because the README mentions a feature, that doesn't mean that said feature is ready, or that it has even been started, or that it will ever come, or that it's possible, or that you'd like it if any of those things were true.\n- While there is a basic guide/walkthrough there is no actual documentation (API or otherwise) at this early stage.\n- I'm really new to Nuxt and I'm learning as I go so this may well be the worst Nuxt module of all time!\n\nFinally, you should check out [NuxtPress](https://github.com/nuxt/press) because it does kind of a similar-ish (but not really) thing but probably in a far far better way.\n\n_[Back to top](#nuxt-dynamic-markdown)_\n\n---\n\n## Rationale / Origin\n\nI chose to use Nuxt for my personal site and at some point decided that I wanted some kind of custom blog system.\n\nIt needed to allow one to:\n\n- \"define\" a category by creating a directory\n- create a post by creating a markdown file\n- be able to add things like tags etc. to YAML frontmatter\n- a way to use arbitrary components within my posts\n- and so on...\n\nSo 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).\n\n### Evolution\n\nAt 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.\n\nSo 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.\n\n_[Back to top](#nuxt-dynamic-markdown)_\n\n---\n\n## What is it?\n\nIt basically takes directories that contain markdown files that contain YAML front matter and builds \"entities\" and the relationships (e.g. `hasMany`) between them.\n\nAll 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).\n\nFinally, the **DynamicMarkdown** component helps us to quickly/easily render our strange Frankensteinesque creation.\n\nIf that didn't make any sense then try the [walkthrough](#walkthrough)!\n\n_[Back to top](#nuxt-dynamic-markdown)_\n\n---\n\n## What does it look like?\n\nYou can check out the [live demo](https://serene-chandrasekhar-209033.netlify.com/projects/) if you're so inclined.\n\n### Example project\n\nThe live demo is simply [this example project](https://www.github.com/sustained/nuxt-dynamic-markdown-example-project) deployed to Netlify.\n\n---\n\n## How do I install it?\n\n### Create nuxt project\n\nIf you don't already have a nuxt project then create one:\n\n\u003e **IMPORTANT:** Make sure to enable Vuex when prompted.\n\n```sh\nnpx create-nuxt-app my-project\n```\n\n### Install the module\n\nWith either npm or yarn:\n\n```sh\nnpm install --save nuxt-dynamic-markdown\n# or\nyarn add nuxt-dynamic-markdown\n```\n\n### Register the module\n\nIn `nuxt.config.js`:\n\n```js\nimport NuxtDynamicMarkdown from \"nuxt-dynamic-markdown\";\n\nexport default {\n  modules: [\n    [\n      NuxtDynamicMarkdown,\n      {\n        /*\n          Sources are how you tell NDM what to load, \n          where from and how you define your relationships.\n          \n          IMPORTANT: This data-source is presumed to be \n          present for the duration of this README.\n        */\n        sources: [\n          {\n            nested: false,\n            name: \"projects\",\n            directory: \"projects\",\n            relationships: [\"keywords\"]\n          }\n        ]\n      }\n    ]\n  ]\n};\n```\n\nInstallation complete. Well done, you made it this far!\n\n_[Back to top](#nuxt-dynamic-markdown)_\n\n---\n\n## Walkthrough / guide\n\n### Directory structure\n\nOkay. Presume we have a directory called `contents` in our Nuxt project with the following structure:\n\n```\ncontents/\n  projects/\n    my-first-project/\n      content.md\n```\n\n### Defining entities\n\nAnd the following `content.md` file:\n\n```markdown\n---\ntitle: Foo Project\nkeywords: [foo, bar, baz]\ndescription: I am foo project!\ncomponents: [Bar]\n---\n\n# Foo\n\nI am foo project! The one! The only!\n\n## Attributes (frontmatter)\n\nMy keywords are: {{ keywords.join(\", \") }}.\n\n### Custom attributes\n\nThis is a custom attribute:\n\n{{ custom }}\n\n## Components\n\nThis is a component:\n\n\u003cBar /\u003e\n\nIsn't it great?\n```\n\nThere's a lot going on there so let's break it down:\n\n#### YAML front matter\n\n- You can attach arbitrary data to an entity using the YFM block.\n- All attributes can be accessed within the markdown.\n- You can pass custom (non-YFM) attributes.\n- By convention, `keywords` and `description` populate `\u003cmeta\u003e`.\n\n\u003e **NOTE:** Currently you must mix in the `getMeta` and `setHead` mixins in order for `\u003cmeta\u003e` to be populated.\n\n#### Registering components\n\nThe special attribute `components` allows you to make components available within the markdown file.\n\n#### Markdown content\n\nThe markdown can be anything you want, there are no real restrictions.\n\n_[Back to top](#nuxt-dynamic-markdown)_\n\n---\n\n### Creating pages\n\n#### The view project page\n\nNext, we'll create a `projects` folder in `pages` and within it we'll create two files.\n\nThe first file will be called `_project.vue` and will display an individual project:\n\n```html\n\u003ctemplate\u003e\n  \u003csection\u003e\n    \u003cDynamicMarkdown\n      v-bind=\"project\"\n      :custom-attributes=\"{ custom: 'Hello!' }\"\n    /\u003e\n  \u003c/section\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n  import { getMeta, setHead, asyncData } from \"nuxt-dynamic-markdown/lib/mixin\";\n\n  export default {\n    mixins: [getMeta, setHead],\n    asyncData\n  };\n\u003c/script\u003e\n```\n\n##### Accessing the entity\n\nSince the route parameter for a Nuxt page called `_project.vue` is `project` then the entity will be available via `this.project`.\n\nSo we simply pass this in to the `DynamicMarkdown.vue` component, which renders it for us.\n\n\u003e **NOTE:** It's important that you pass it in exactly as above - `v-bind=\"entity\"`.\n\n##### Passing custom attributes\n\nAs you can see, this is also where we pass in the custom attributes mentioned earlier.\n\n##### Mixins and helpers (entity)\n\nFor now it is **required** that you, at a minimum, import the `asyncData` helper and pass it to your component.\n\nThe `getMeta` and `setHead` mixins on the other hand are *not required* to be used.\n\n##### A note on boilerplate\n\nIdeally none of this boilerplate would be necessary but for the time being it is, unfortunately.\n\nI intend to look into ways to reduce and/or remove it.\n\n#### The project listing page\n\nThe second file will be called `index.vue` and will list all projects:\n\n```html\n\u003ctemplate\u003e\n  \u003csection\u003e\n    \u003ch1\u003eMy Projects\u003c/h1\u003e\n\n    \u003cul\u003e\n      \u003cli v-for=\"project in projects\"\u003e\n        \u003cnuxt-link\n          :to=\"{\n            name: 'projects-project',\n            params: { project: projectName }\n          }\"\n        \u003e\n          {{ project }}\n        \u003c/nuxt-link\u003e\n      \u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/section\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n  import { getEntities } from \"nuxt-dynamic-markdown/lib/mixin\";\n\n  export default {\n    asyncData: getEntities(\"projects\")\n  };\n\u003c/script\u003e\n```\n\n##### Mixins and helpers (index)\n\nFor this case (index/listing pages), it is **not required** that you use the `getEntities` helper.\n\nIf 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.\n\n_[Back to top](#nuxt-dynamic-markdown)_\n\n---\n\n### Creating the `Bar` component\n\nFinally we'll create a file called `Bar.vue` in `components` since we referenced it in our `content.md` file earlier.\n\n```html\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003cp\u003eI am bar component.\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n_[Back to top](#nuxt-dynamic-markdown)_\n\n---\n\n### Result\n\nIf the stars were aligned properly and you uttered the incantations with the correct stress and prosody then you should see something like this:\n\n![Project listing.](docs/images/projects.png)\n\n![Individual project.](docs/images/project.png)\n\n\u003e **NOTE:** You may see something slightly more simple-looking presuming you didn't use our [example project](https://www.github.com/sustained/nuxt-dynamic-markdown-example-project) (which uses Bulma).\n\n_[Back to top](#nuxt-dynamic-markdown)_\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsustained%2Fnuxt-dynamic-markdown","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsustained%2Fnuxt-dynamic-markdown","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsustained%2Fnuxt-dynamic-markdown/lists"}