upwrite
v2.0.1
Published
Configuring a blog is annoying, let's do better.
Downloads
3
Maintainers
Readme
Configuring a blog is annoying, let's do better.
- Maintains folder structure of files for posts
- Uses
markdown-it
to transform Markdown into HTML (post.html
in templates). - Provides all page data for building navigation or recent article lists (
posts
in templates). - Enhances
front-matter
to setnunjucks
filters in templates for string processing. - Pipes
front-matter
tonunjucks
templates underfm
key (post.fm.title
). - Setup
front-matter
for RSS feed metadata. - Write RSS feed from posts using
feed
. - Write
sitemap.txt
from contents.
Install
npm i upwrite
Usage
Assuming you've completed the setup, using the CLI:
upwrite [options]
Or using the API:
const upwrite = require('upwrite');
upwrite(options).then(done).catch(err);
Options
| Key | CLI shortcut | Default | Description |
| --- | ------------ | ------- | ----------- |
| input
| -i
| posts/
| Directory where your content to be transformed exists. More |
| output
| -o
| _site/
| Directory where the final output should be written. More |
| rss
| -r
| feed.json
| The .json
file which informs the RSS feed also indicates the working directory. More |
| template
| -t
| templates/post.njk
| The nunjucks
template to use for the transformation. More |
| copy
| -c
| true
| Copies non-markdown files into the output
directory in the same structure. More |
CLI options example:
upwrite -i blog -o public -r rss.json -t nunjucks/blog.html
- Looks at the
blog/
directory for files. - Outputs to the
public/
directory; creatingpublic/blog/
- References the
rss.json
file to initialize the feed. Writespublic/rss.xml
- Uses template found at
nunjucks/blog.html
Setup
📁 ./
├── 📁 _site
├── 📁 posts
├── 📁 templates
└── 📄 feed.json
- The
_site/
directory will be created duringupwrite
execution. - The
posts/
directory holds.md
files withfront-matter
. - The
templates/
directory holds.njk
files for use withnunjucks
. - The
feed.json
file has initial feed information.
Posts
Each post is a .md
file with front-matter
at the top with metadata expected to populate the RSS feed. The metadata is piped into the addItem()
method of the feed
project.
---
title: My first post
description: And I think you all should read it
date: 2013-12-29 17:16:55
---
If you want the post to be rendered within the RSS feed, you must include the date
field. To render without including in the RSS feed, omit the date
field.
You may include a special template
key to override the base template for specific posts.
---
title: My second post
description: You should all still read it
date: 2022-03-11 07:16:55
template: templates/no-date.njk
---
Notice that the template
key is expecting the path relative to the feed.json
Templates
The templates are transformed using nunjucks
. Much of the data collected through processing is found on a post
key within the file. You'll commonly have the following basic template setup:
<!doctype>
<html>
<head>
<!-- Any metadata found in the front-matter is at `post.fm` -->
<title>{{ post.fm.title }}</title>
<meta name="description" content="{{ post.fm.description }}">
</head>
<body>
<datetime>{{ post.fm.date }}</datetime>
<!-- Use the "safe" filter in Nunjucks to render `post.html` as html -->
<main>{{ post.html | safe }}</main>
</body>
</html>
Filters
The ability to filter incoming data is important in nunjucks
. You can prepare front-matter
-like filters at the top of your entry template to include filters for your nunjucks
environment. This can only occur in the templates referenced within the transformation (either the template
key in the options, or the template
key in a .md
front-matter
). The process cannot read front-matter
added to files that are
included along the way.
---
humandate: (date) => new Date(date).toDateString()
---
<!doctype>
<html>
<head>
<!-- front-matter cannot be parsed in the head.njk file -->
{% include "head.njk" %}
</head>
<body>
<!-- Use the "humandate" filter created in the front-matter above -->
<datetime>{{ post.fm.date | humandate }}</datetime>
<main>{{ post.html | safe }}</main>
</body>
</html>
Navigation
You can generate navigation using the different keys injected into each page.
<!doctype>
<html>
<head>
<!--
page are the keys found in feed.json.
post.fm are the keys written in the .md front-matter
-->
{{ page.title }} - {{ post.fm.title }}
{% include "head.njk" %}
</head>
<body>
<nav>
<ul>
<!--
Using item to indicate the posts in the loop versus this current post.
We only want entries that do NOT have a date.
These are static pages (like 'home' or 'about').
You can also sort by giving these pages additional front-matter to sort by.
-->
{% for item in posts %} {% if not item.fm.date %}
<li>
<a href="{{ item.pathname }}">{{ item.fm.title }}</a>
</li>
{% endif %} {% endfor %}
</ul>
</nav>
</body>
</html>
| parent | keys | definition |
| ------ | ---- | ---------- |
| page
| { title, description, url }
| Data direct from feed.json
|
| posts
| [{ fm, html, pathname, link }]
| Represents all posts as an array of post objects |
| post
| { fm, html, pathname, link }
| Represents this post with the front-matter (fm
) and markdown rendered as HTML (html
) |
The pathname
is the relative path to the post. The link
is the absolute path to the post.
feed.json
This .json
file is the starting point to create the RSS feed. It has the following required fields:
{
"title": "The best blog",
"description": "The one and only",
"link": "https://example.com"
}
The link
field is especially required as it's used to construct post urls alongside the file structure of your project. The name of this file (feed
) is used to name the resulting .xml
file of the feed (feed.xml
) and can be changed in the options.
The path to the feed.json
also sets the base of your working directory. This allows you to change where all the other filepaths start from.
await upwrite({
rss: 'website/feed.json',
input: 'posts', // actually at website/posts
output: '_site/', // actually at website/_site
template: 'post.njk', // actually at website/post.njk
});
Output
📁 ./
└── 📁 _site
├── 📄 feed.xml
├── 📄 sitemap.txt
└── 📁 posts
└── 📁 [markdown-filename]
└── 📄 index.html
- The
feed.xml
file is your RSS feed based onfeed.json
and the.md
files found in theposts/
directory. - The
sitemap.txt
is a list of all the urls processed by the transformer, used as a sitemap. - The
posts/
directory in_site/
will maintain the same structure of the source.md
files but writeindex.html
files instead of[markdown-filename].html
. This allows for clean urls.
- https://example.com/posts/first-post.html
+ https://example.com/posts/first-post
- https://example.com/posts/nested/third-post.html
+ https://example.com/posts/nested/third-post
Non-markdown files
All files found within the input
directory that are not .md
will be copied to the new directory using the same structure they were found with.
- ./posts/nested/media.jpg
+ ./_site/posts/nested/media.jpg
You can skip this by setting copy
to false
.