Sep 26, 2020
You can put a YAML header at the top (must be at the very top) of your markdown files with all the meta-data you want such as title, author, date, etc. The header fields used to specify the route for that file when it is rendered are published, slug, and slugs. Let's go through the different combinations one by one. Before we start though, I am using the contentFolder route for my blog markdown files, in a folder called "posts." Here is the relevant part of the config file:
//scully.<project>.config.ts
export const config: ScullyConfig = {
projectRoot: "./src",
projectName: "your-project-name",
outDir: './dist/static',
routes: {
'/posts/:id': {
type: 'contentFolder',
id: {
folder: "./posts"
}
},
}
};
The first part of the route will follow the folder structure of the contentFolder. So, for example, since this post is in the "posts/2020/09" folder, the full route will be thedomain.com/posts/2020/09/route-name-from-yaml
. The rest of this post is concerned with how to set the route-name-from-yaml
.
One caveat to keep in mind: Scully will keep all previous routes you have ever had in the /dist/static
folder unless you specifically remove them. The current routes are in the scully-routes.json
folder, but you could have additional old routes leftover. This could be a good thing, as it reduces the chance for broken links to your site, but Scully provides a command line option for clearing the static directory before starting a new build if you wish to get rid of any old routes. All the Scully Command Line Options are listed out on Github, but the one of interest here is --removeStaticDist
. The command npm run scully -- --removeStaticDist --scanRoutes
will clean up the static output folder and scan your app for all the routes to make a new scully-routes.json
file.
published: false
: route will be automatically generated in a slugs
field.slug
field: route will be the slug, not the filenameslugs
field: you must use a list. The routes will be every item in your slugs
list, plus the slug
OR filename if you don't have a slug
field.If there is no header at all in the markdown file, the end of the route will be the file name. Any spaces in the file name will be filled in with "-" dashes for the route. Since this file is named markdown-file-route-slug-vs-slugs.md
, the full route will be thedomain.com/posts/2020/09/markdown-file-route-slug-vs-slugs
. Here is the route info given in scully-routes.json
(as a reminder, you can auto-format the json files in VS Code with Shift+Alt+F to make it easier to read):
//scully-routes.json
{
"route": "/posts/2020/09/markdown-file-route-slug-vs-slugs",
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
If you have a header with a title only, the end of the route will still be the filename. The title does not affect the route.
published: false
If you have a header with published: false
in it, it will not be in the available$
routes observable of the Scully Route Service, but it will still be in allRoutes$
and unPublished$
. Scully will automatically add a slugs
field to your file with an auto-generated route when you run it (that you could share with reviewers but would be hard to find unless you have a direct link). Here is an example:
# Markdown file frontmatter
---
title: 'How to specify the route(s) for your rendered markdown files using "slug" and "slugs" in your markdown YAML header'
published: false
slugs:
- ___UNPUBLISHED___kfga5ogt_NzHqTkqmVU3cAVuYx7sChz0oNtUheFGR
---
Now your only route is the generated UNPUBLISHED slug. Here is the route in scully-routes.json
:
//scully-routes.json
{
"route": "/posts/2020/09/___UNPUBLISHED___kfhn0g54_kxACcnisceR9M8ErzdRTLo5LNXe8psY1",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": false,
"slugs": [
"___UNPUBLISHED___kfhn0g54_kxACcnisceR9M8ErzdRTLo5LNXe8psY1"
],
"slug": "___UNPUBLISHED___kfhn0g54_kxACcnisceR9M8ErzdRTLo5LNXe8psY1",
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
slug
fieldIf you set published: true
and add a slug
field, the route will change to whatever you put in the slug
field. Example header:
# Markdown file frontmatter
---
title: 'How to specify the route(s) for your rendered markdown files using "slug" and "slugs" in your markdown YAML header'
published: true
slug: markdown-file-route
---
and here is the resulting route in scully-routes.json
:
//scully-routes.json
{
"route": "/posts/2020/09/markdown-file-route",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slug": "markdown-file-route",
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
}
slugs
fieldIf you set published: true
and have a slugs
field but no slug
field, the primary route will be the filename, but all the slugs
will also work as a route. However, you must make the slugs
field a list for this to work. If you have a value in the slugs
field that is not in a list it will be ignored. Here is an example:
# don't do this
---
title: 'How to specify the route(s) for your rendered markdown files using "slug" and "slugs" in your markdown YAML header'
published: true
slugs: markdown-file-route
---
// the value in slugs is not a route
{
"route": "/posts/2020/09/markdown-file-route-slug-vs-slugs",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": "markdown-file-route",
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
This is the proper way to use slugs
with a list:
# Markdown file frontmatter
---
title: 'How to specify the route(s) for your rendered markdown files using "slug" and "slugs" in your markdown YAML header'
published: true
slugs:
- a-first-slug
---
and the result is that both the filename and the slug is a route:
//scully-routes.json
{
"route": "/posts/2020/09/markdown-file-route-slug-vs-slugs",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": [
"a-first-slug"
],
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
{
"route": "/posts/2020/09/a-first-slug",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": [
"a-first-slug"
],
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
If you have multiple values in the slugs
list, you will get a route for the filename as well as a route for each slug. Here is the header and resulting routes:
# Markdown file frontmatter
---
title: 'How to specify the route(s) for your rendered markdown files using "slug" and "slugs" in your markdown YAML header'
published: true
slugs:
- a-first-slug
- a-second-slug
---
//scully-routes.json
{
"route": "/posts/2020/09/markdown-file-route-slug-vs-slugs",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": [
"a-first-slug",
"a-second-slug"
],
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
{
"route": "/posts/2020/09/a-first-slug",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": [
"a-first-slug",
"a-second-slug"
],
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
{
"route": "/posts/2020/09/a-second-slug",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": [
"a-first-slug",
"a-second-slug"
],
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
The last combination is having both slug
and slugs
fields:
# Markdown file frontmatter
---
title: 'How to specify the route(s) for your rendered markdown files using "slug" and "slugs" in your markdown YAML header'
published: true
slugs:
- a-first-slug
- a-second-slug
slug: the-primary-slug
---
As you might guess, the filename is no longer a route. Instead, the slug
is the primary route and the slugs
are alternate routes:
//scully-routes.json
{
"route": "/posts/2020/09/the-primary-slug",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": [
"a-first-slug",
"a-second-slug"
],
"slug": "the-primary-slug",
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
{
"route": "/posts/2020/09/a-first-slug",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": [
"a-first-slug",
"a-second-slug"
],
"slug": "the-primary-slug",
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
{
"route": "/posts/2020/09/a-second-slug",
"title": "How to specify the route(s) for your rendered markdown files using \"slug\" and \"slugs\" in your markdown YAML header",
"published": true,
"slugs": [
"a-first-slug",
"a-second-slug"
],
"slug": "the-primary-slug",
"sourceFile": "markdown-file-route-slug-vs-slugs.md"
},
I hope this guide helps you set the routes for your blog posts the way you want, and saves you unnecessary headaches!