This website is built using Vuepress and a little bit of Vue magic. The entire source for this site is on GitHub, and the config.js file has been set to build the site to the /docs folder. In GitHub this repository has been set to publish the site at /docs and has been given a custom domain name - mark.honeychurch.org.

GitHub Pages

This solution allows me to have both the source and build for the website in the one GitHub repo, which is clean and simple. All that's needed is for Vuepress to be installed globally, along with the markdown-it extensions I use (video, fontawesome, abbr, sup, sub and attrs), and then for the NODE_PATH environment variable to point to the global node_modules folder.

A development version of the site, with hot reloading, can be launched by running:

vuepress dev

To build the static files for the production website, all I need to run is:

vuepress build

Then I commit the code, push it to GitHub, and the new version of my site is live.

Vue

Vue components can be created to display content. I've written custom components for listing posts, displaying a single post, etc, as well as writing components.

Components can be dropped into any markdown page by adding the component's HTML tag. For a component at .vuepress/components/code/rotx/decode.vue, for example, the HTML tag would be <code-rotx-decode />.

For a Vue component layout template that displays a single page, a <Content /> tag needs to be added where the markdown content of the page should be displayed.

Metadata

$page

For Vue components, there's metadata available for a single page in the $page object:

	
		{
	"title": "This Website",
	"frontmatter": {
		"title": "This Website",
		"date": "2018-09-12T00:00:00.000Z",
		"layout": "Post",
		"categories": [
			"Software"
		],
		"tags": [
			"Vue",
			"Vuepress",
			"Markdown"
		],
		"meta": [
			{
				"property": "article:published_time",
				"content": "2018-09-12T00:00:00.000Z"
			},
			{
				"property": "og:site_name",
				"content": "Mark Honeychurch"
			},
			{
				"property": "og:title",
				"content": "This Website"
			},
			{
				"property": "og:description",
				"content": "This website is built using Vuepress and a little bit of Vue magic. The entire source for this site is on GitHub, and the config.js file has been set to build the site to the /docs folder. In GitHub this repository has been set to publish the site at /docs and has been given a custom domain name - mark.honeychurch.org."
			},
			{
				"property": "og:type",
				"content": "article"
			},
			{
				"property": "og:url",
				"content": "/blog/code/website/"
			},
			{
				"property": "og:image",
				"content": "/media/images/blog/code/website.jpg"
			},
			{
				"name": "twitter:title",
				"content": "This Website"
			},
			{
				"name": "twitter:description",
				"content": "This website is built using Vuepress and a little bit of Vue magic. The entire source for this site is on GitHub, and the config.js file has been set to build the site to the /docs folder. In GitHub this repository has been set to publish the site at /docs and has been given a custom domain name - mark.honeychurch.org."
			},
			{
				"name": "twitter:url",
				"content": "/blog/code/website/"
			},
			{
				"name": "twitter:card",
				"content": "summary_large_image"
			},
			{
				"name": "twitter:image",
				"content": "/media/images/blog/code/website.jpg"
			},
			{
				"name": "twitter:label1",
				"content": "Written by"
			},
			{
				"name": "twitter:creator",
				"content": "@markhoney"
			},
			{
				"name": "twitter:label2",
				"content": "Filed under"
			},
			{
				"name": "twitter:data2",
				"content": "Vue, Vuepress, Markdown"
			},
			{
				"property": "article:tag",
				"content": "Vue"
			},
			{
				"property": "article:tag",
				"content": "Vuepress"
			},
			{
				"property": "article:tag",
				"content": "Markdown"
			}
		]
	},
	"regularPath": "/blog/code/website/",
	"relativePath": "blog/code/website/index.md",
	"key": "v-41174c0b",
	"path": "/blog/code/website/",
	"headers": [
		{
			"level": 2,
			"title": "Vue",
			"slug": "vue"
		},
		{
			"level": 2,
			"title": "Metadata",
			"slug": "metadata"
		},
		{
			"level": 3,
			"title": "$page",
			"slug": "page"
		},
		{
			"level": 3,
			"title": "$site",
			"slug": "site"
		},
		{
			"level": 3,
			"title": "window.location",
			"slug": "window-location"
		},
		{
			"level": 3,
			"title": "location.vue",
			"slug": "location-vue"
		},
		{
			"level": 3,
			"title": "Category Page",
			"slug": "category-page"
		},
		{
			"level": 2,
			"title": "This page",
			"slug": "this-page"
		}
	],
	"excerpt": "<p>This website is built using <a href=\"https://vuepress.vuejs.org/\" target=\"_blank\" rel=\"noopener noreferrer\">Vuepress<OutboundLink/></a> and a little bit of Vue magic. The <a href=\"https://github.com/markhoney/mark.honeychurch.org\" target=\"_blank\" rel=\"noopener noreferrer\">entire source<OutboundLink/></a> for this site is on GitHub, and the config.js file has been set to build the site to the /docs folder. In GitHub this repository has been set to publish the site at /docs and has been given a custom domain name - mark.honeychurch.org.</p>\n",
	"readingTime": {
		"text": "3 min read",
		"minutes": 2.64,
		"time": 158400,
		"words": 528
	}
}
	

$site

There's a $site object which holds metadata for the entire site. I've created a separate page for it, as it's pretty long:

$site

window.location

We also have all the usual Javascript data available to us, such as window.location (but bear in mind the gotcha described below):

	
		null
	

This can come in handy for clever hacks like using window.location.search to offer a dynamic page that lists posts in a single category, for example. However, because the window object is only available in the browser, we have to make sure that the code is only run on the client side. This can be done by creating an empty reactive data object, and then populating it on mount with the frontend data.

location.vue

Here's the component I used above to get the window.location object:

<template>
	<pre>
		<code class="language-json">
			{{JSON.stringify(location, null, '\t')}}
		</code>
	</pre>
</template>

<script>
	export default {
		data() {
			return {
				location: null
			};
		},
		mounted() {
			this.location = window.location;
		}
	};
</script>

Category Page

For example, to list a single category of posts on this site, I have a reactive data object called "category" which is initialised as null. Then, on mounted(), I get the URL query from window.location.search to find out what category I need to show, and dynamically compute a list of pages that match that category:

<template>
	<span v-if="categories">
		<router-link v-for="(category, index) in categories" :key="index" :to="'/blog/category/?name=' + category">{{category}}<span v-if="index + 1 < categories.length">, </span></router-link>
	</span>
</template>

<script>
	export default {
		props: ["categories"]
	};
</script>

This page

As an example, here is the markdown for this web page. There is a Front Matter section at the top of the page, followed by the page markdown.

---
title: This Website
date: 2018-09-12
layout: Post
categories:
  - Software
tags:
  - Vue
  - Vuepress
  - Markdown
---

This website is built using [Vuepress](https://vuepress.vuejs.org/) and a little bit of Vue magic. The [entire source](https://github.com/markhoney/mark.honeychurch.org) for this site is on GitHub, and the config.js file has been set to build the site to the /docs folder. In GitHub this repository has been set to publish the site at /docs and has been given a custom domain name - mark.honeychurch.org.

<!-- more -->

![GitHub Pages](./Screenshot_1.jpg)

This solution allows me to have both the source and build for the website in the one GitHub repo, which is clean and simple. All that's needed is for Vuepress to be installed globally, along with the markdown-it extensions I use (video, fontawesome, abbr, sup, sub and attrs), and then for the NODE_PATH environment variable to point to the global node_modules folder.

A development version of the site, with hot reloading, can be launched by running:

```bash
vuepress dev
```

To build the static files for the production website, all I need to run is:

```bash
vuepress build
```

Then I commit the code, push it to GitHub, and the new version of my site is live.

## Vue

Vue components can be created to display content. I've written custom components for listing posts, displaying a single post, etc, as well as writing components.

Components can be dropped into any markdown page by adding the component's HTML tag. For a component at .vuepress/components/code/rotx/decode.vue, for example, the HTML tag would be &lt;code-rotx-decode /&gt;.

For a Vue component layout template that displays a single page, a &lt;Content /&gt; tag needs to be added where the markdown content of the page should be displayed.

## Metadata

### $page

For Vue components, there's metadata available for a single page in the $page object:

<code-vuepress-page />

### $site

There's a $site object which holds metadata for the entire site. I've created a separate page for it, as it's pretty long:

[$site](./site.md)

<!--
### $route

There's a $route object as well:

[$route](./route.md)
-->

### window.location

We also have all the usual Javascript data available to us, such as window.location (but bear in mind the gotcha described below):

<code-vuepress-location />

This can come in handy for clever hacks like using window.location.search to offer a dynamic page that lists posts in a single category, for example. However, because the window object is only available in the browser, we have to make sure that the code is only run on the client side. This can be done by creating an empty reactive data object, and then populating it on mount with the frontend data.

### location.vue

Here's the component I used above to get the window.location object:

<<< ./src/.vuepress/components/code/vuepress/location.vue

### Category Page

For example, to list a single category of posts on this site, I have a reactive data object called "category" which is initialised as null. Then, on mounted(), I get the URL query from window.location.search to find out what category I need to show, and dynamically compute a list of pages that match that category:

<<< ./src/.vuepress/theme/components/post/categories.vue

## This page

As an example, here is the markdown for this web page. There is a [Front Matter](https://jekyllrb.com/docs/front-matter/) section at the top of the page, followed by the page markdown.

<<< ./src/blog/code/website/index.md