npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nuxt-gustave

v0.5.4

Published

json generator from markdown files

Downloads

92

Readme

GUSTAVE

Transform your markdown or yaml files into static sites or blog with Nuxt.js. Gustave is designed to work with Nuxt npm run generate.

Gustave transform your markdown or yaml files into JSON files with customizable compilers. JSON files can then be easily consumed by your Vue.js components.

Features

  • Frontmatter support for markdown files
  • Handle dates in filenames for blogging, like Jekyll (e.g: 2018-08-21-apples.md)
  • Hot-reloading when markdown files are changed

Requirements

  • Node v10.12.0 (uses { recursive: true } option from fs.mkdir)

Installation

Install Gustave as a dev dependency only, as it is needed only to generate the html files from our markdown files.

npm install nuxt-gustave --save-dev

Add static/api directory to .gitignore file. This is where our JSON files will be generated by default.

# nuxt-gustave
static/api

Getting started

The core concept of Gustave are compilers : a compiler is just a function exporting a compile method. This compile method fetches data from somewhere (for example, local mardown files), save it as JSON and return to Nuxt an array of dynamic routes if needed ( for example : ['user/1', 'user/4', 'user/18']).

Thoses routes array are required for dynamic routes by npm run generate command, see https://nuxtjs.org/api/configuration-generate#routes . This is not required for static routes like /contact or /about. If you return them directly from your compiler, you don't need to add them manually to nuxt.generate.routes property from nuxt.config.js.

Create an "compiler"

Create an compilers/posts.js file that will turn mardown files from a content/posts directory into a static/api/posts.json file

const { parseMarkdownDirectory } = require('nuxt-gustave/lib/markdown')
const { saveToJsonDirectory } = require('nuxt-gustave/lib/gustave')

exports.compile = () => {
  const resources = parseMarkdownDirectory('content/posts')
  saveToJsonDirectory('posts.json', resources)
  return resources.map(resource => `/posts/${resource.$slug}`)
}

NOTA BENE : we declared here an array of routes with /posts/${resource.$slug} : this mean that we MUST create a corresponding pages/posts/_slug.vue component to handle thoses routes, to actually generate our html.

You can also convert a single to markdown :

const { parseMarkdownFile } = require('nuxt-gustave/lib/markdown')
const { saveToJsonDirectory } = require('nuxt-gustave/lib/gustave')

exports.compile = () => {
  const resource = parseMarkdownFile('content/settings.md')
  saveToJsonDirectory('settings.json', resource)
  return []
}

Register Gustave compilers

Now we have to configure nuxt.config.js file to use Gustave module and register our new compilers/posts.js compiler.

module.exports = {
  // ...
  // add nuxt-gustave module
  modules: ['nuxt-gustave'],
  // register compilers to use:
  gustave: {
    compilers: [
      'compilers/tags.js',
      'compilers/blocks.js',
      // you can passe options to an compiler with an array:
      ['compilers/posts.js', { hello: 'world' }]
    ]
  }
}

Create some posts in yaml

In content/posts directory, add two posts:

📝 content/posts/first-post.md

---
title: this is my firt blog post :D
date: 2019-01-02
---

Hello there, this is my first blog post with Gustave.

📝 content/posts/second-post.md

---
title: second post
date: 2019-01-03
---

Another post in mardown.

Generate our JSON files

Now , if we run npm run dev, npm run generate or npx nuxt-gustave command, a static/api/posts.json file will be automatically created.

[
  {
    "title": "second post",
    "date": "2019-01-03T00:00:00.000Z",
    "$html": "<p>Another post in mardown. This is the future.</p>\n",
    "$id": "second-post.md",
    "$slug": "another-post"
  },
  {
    "title": "this is my firt blog post :D",
    "date": "2019-01-02T00:00:00.000Z",
    "$html": "<p>Hello there, this is my first blog post with Gustave.</p>\n",
    "$id": "first-post.md",
    "$slug": "hello"
  }
]

Note that Gustave added some useful variables here :

  • $html : the mardkown rendered as html.
  • $id : a uniq id to identify this resource. Filename is used by default.
  • $slug : a slug generated from the filename, that can be used to build pretty urls like "/posts/my-second-post"

All thoses variables can be overriden inside the compiler, before the resources are saved as a JSON file or direclty in the markdown front-matter:

---
$slug: react-wordpress-reactpress-%f0%9f%92%9b
---

Displaying our posts

We now have a posts.json file that can be used from our components. Below are a simple example of how it could be done, but from this point; it's really up to you.

Display all posts : 📝 pages/posts/index.vue

<template>
  <div>
    <div v-for="post in posts" :key="post.$slug">
      <h2>
        <nuxt-link :to="`/posts/${post.$slug}`"
          >{{post.title}}</nuxt-link
        >
      </h2>
      <div v-html="post.$html" />
    </div>
  </div>
</template>

<script>
  import posts from 'static/api/posts.json'
  export default {
    computed: {
      posts() {
        return posts
      }
    }
  }
</script>

Display a single post : pages/posts/_slug.vue

<template>
  <div>
    <h1>{{post.title}}</h1>
    <div v-html="post.$html"></div>
  </div>
</template>

<script>
  import posts from 'static/api/posts.json'
  export default {
    computed: {
      post() {
        return posts.find(
          post => post.$slug === this.$route.params.slug
        )
      }
    }
  }
</script>

Customize markdown interpreter options

Custom mardown instance

Gustave is using Markdown-it to render markdown, with a default instance. We can pass our own markdownIt instance to get the full control about markdownIt configuration :

module.exports = {
  // ...
  gustave: {
    markdownIt() {
      const markdownIt = require('markdown-it')({
        html: false,
        linkify: true
      })
      // we can add plugins here too
      return markdownIt
    }
    // ...
  }
}

Syntaxic coloration

Code syntaxic coloration with markdownIt can be enable automatically with the highlight options (behind the hood, this will simply add CSS and JS from highlight.js npm package) :

module.exports = {
  // ...
  gustave: {
    highlight: true
    // ...
  }
}

Blogging with "jekyllMode"

If you have a lot of posts, it is easier to retrieve quickly a post if your filename starts with the date. This what the "jekyllMode" is for :

For the following directory structure:

📁 content
  📁 posts
    📝 2018-07-02-my-first-post.md
    📝 2018-08-03-my-last-post.md

You can create the following compiler :

exports.compile = () => {
  const resources = parseMarkdownDirectory('content/posts', {
    jekyllMode: true
  })
  saveToJsonDirectory('posts.json', resources)
  return resources.map(resource => `/blog/${resource.$slug}`)
}

It will create the following JSON in static/api, already sorted by date and with a $date field:

[
  {
    "$date": "2018-07-02",
    "$slug": "my-last-post",
    "$id": "my-last-post.md",
    "$html": "<div>html content of my last post</div>"
  },
  {
    "$date": "2018-07-02",
    "$slug": "my-first-post",
    "$id": "my-first-post.md",
    "$html": "<div>html content of my first post</div>"
  }
]

Note that the $slug and the $id

Sort by date

if you have a field with an ISO Date, you can use sortResoucesByDate function manually to sort resources before saving them as JSON.

resources = sortResourcesByDate(resources, '$date', 'asc')