feat: load the sidebar data and titles/excerpts from the blog post markdown document and its frontmatter (#2981)

This commit is contained in:
Pete Davison
2026-08-16 12:14:08 +01:00
committed by GitHub
parent 1868ad2969
commit 1d0719b65a
12 changed files with 174 additions and 125 deletions

View File

@@ -0,0 +1,53 @@
import { createContentLoader } from 'vitepress';
export interface Post {
title: string;
url: string;
date: {
time: number;
string: string;
};
author: string;
tags: string[];
excerpt?: string;
}
declare const data: Post[];
export { data };
// extractExcerpt renders the whole document first so that links which have
// `[ref]: url` style definitions outside of the excerpt still resolve. The
// rendered HTML is then cut at the `<!-- more -->` marker leaving just the
// excerpt text.
function extractExcerpt(html: string): string | undefined {
const markerIndex = html.indexOf('<!-- more -->');
if (markerIndex === -1) return undefined;
return html
.slice(0, markerIndex)
.replace(/<h1[^>]*>[\s\S]*?<\/h1>/, '')
.replace(/<AuthorCard\b[^>]*\/?>/gi, '')
.trim();
}
export default createContentLoader('blog/*.md', {
render: true,
transform(raw) {
return raw
.filter(({ url }) => url !== '/blog/')
.map(({ frontmatter, html, url }) => {
const date = new Date(frontmatter.date);
return {
title: frontmatter.title,
url,
date: {
time: date.getTime(),
string: date.toISOString().slice(0, 10)
},
author: frontmatter.author,
tags: frontmatter.tags ?? [],
excerpt: html ? extractExcerpt(html) : undefined
};
})
.sort((a, b) => b.date.time - a.date.time);
}
});

View File

@@ -20,7 +20,7 @@
<div class="post-text">
<AuthorCard :author="author" />
<p class="post-description">{{ description }}</p>
<div class="post-description" v-html="description"></div>
<div class="post-footer">
<div class="post-tags" v-if="tags?.length">

View File

@@ -1,7 +1,8 @@
import { defineConfig, HeadConfig } from 'vitepress';
import githubLinksPlugin from './plugins/github-links';
import { readFileSync } from 'fs';
import { readdirSync, readFileSync } from 'fs';
import { resolve } from 'path';
import matter from 'gray-matter';
import { tabsMarkdownPlugin } from 'vitepress-plugin-tabs';
import {
groupIconMdPlugin,
@@ -19,6 +20,39 @@ const version = readFileSync(
'utf8'
).trim();
// Builds the "/blog/" sidebar from each blog post's frontmatter.
function buildBlogSidebar() {
const blogDir = resolve(__dirname, '../src/blog');
const posts = readdirSync(blogDir)
.filter((file) => file.endsWith('.md') && file !== 'index.md')
.map((file) => {
const { data: frontmatter } = matter(
readFileSync(resolve(blogDir, file), 'utf8')
);
return {
slug: file.replace(/\.md$/, ''),
title: frontmatter.sidebarTitle ?? frontmatter.title,
date: new Date(frontmatter.date)
};
})
.sort((a, b) => b.date.getTime() - a.date.getTime());
const byYear = new Map<number, { text: string; link: string }[]>();
for (const post of posts) {
const year = post.date.getFullYear();
if (!byYear.has(year)) byYear.set(year, []);
byYear.get(year)!.push({ text: post.title, link: `/blog/${post.slug}` });
}
return [...byYear.entries()]
.sort((a, b) => b[0] - a[0])
.map(([year, items]) => ({
text: String(year),
collapsed: false,
items
}));
}
const urlVersion =
process.env.NODE_ENV === 'development'
? {
@@ -311,56 +345,7 @@ export default defineConfig({
],
sidebar: {
'/blog/': [
{
text: '2026',
collapsed: false,
items: [
{
text: 'GitHub SOSF',
link: '/blog/github-secure-open-source-program'
},
{
text: 'Using `go tool task`',
link: '/blog/go-tool-task'
},
{
text: 'Conditionals Statements',
link: '/blog/if-and-variable-prompt'
}
]
},
{
text: '2025',
collapsed: false,
items: [
{
text: 'Built-in Core Utilities',
link: '/blog/windows-core-utils'
}
]
},
{
text: '2024',
collapsed: false,
items: [
{
text: 'Any Variables',
link: '/blog/any-variables'
}
]
},
{
text: '2023',
collapsed: false,
items: [
{
text: 'Introducing Experiments',
link: '/blog/task-in-2023'
}
]
}
],
'/blog/': buildBlogSidebar(),
'/': [
{
text: 'Installation',

View File

@@ -15,6 +15,7 @@
"devDependencies": {
"@types/markdown-it": "^14.1.2",
"@types/node": "^24.1.0",
"gray-matter": "^4.0.3",
"netlify-cli": "^27.0.0",
"prettier": "^3.6.2",
"vitepress": "^1.6.3",

60
website/pnpm-lock.yaml generated
View File

@@ -14,6 +14,9 @@ importers:
'@types/node':
specifier: ^24.1.0
version: 24.13.3
gray-matter:
specifier: ^4.0.3
version: 4.0.3
netlify-cli:
specifier: ^27.0.0
version: 27.1.1(@parcel/watcher@2.5.6)(@types/node@24.13.3)(picomatch@4.0.5)(rollup@4.46.2)(supports-color@10.2.2)
@@ -1720,6 +1723,9 @@ packages:
arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -2833,6 +2839,10 @@ packages:
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
gray-matter@4.0.3:
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
engines: {node: '>=6.0'}
h3@1.15.11:
resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==}
@@ -3255,6 +3265,10 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-yaml@3.15.1:
resolution: {integrity: sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==}
hasBin: true
js-yaml@4.3.1:
resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==}
hasBin: true
@@ -3648,11 +3662,6 @@ packages:
nan@2.28.0:
resolution: {integrity: sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==}
nanoid@3.3.16:
resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
nanoid@3.3.18:
resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -4029,10 +4038,6 @@ packages:
peerDependencies:
postcss: ^8.2.9
postcss@8.5.22:
resolution: {integrity: sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==}
engines: {node: ^10 || ^12 || >=14}
postcss@8.5.26:
resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==}
engines: {node: ^10 || ^12 || >=14}
@@ -4500,6 +4505,9 @@ packages:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
stack-generator@2.0.10:
resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==}
@@ -4572,6 +4580,10 @@ packages:
resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==}
engines: {node: '>=12'}
strip-bom-string@1.0.0:
resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
engines: {node: '>=0.10.0'}
strip-final-newline@2.0.0:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
@@ -6996,6 +7008,10 @@ snapshots:
arg@4.1.3: {}
argparse@1.0.10:
dependencies:
sprintf-js: 1.0.3
argparse@2.0.1: {}
array-buffer-byte-length@1.0.2:
@@ -8216,6 +8232,13 @@ snapshots:
graceful-fs@4.2.11: {}
gray-matter@4.0.3:
dependencies:
js-yaml: 3.15.1
kind-of: 6.0.3
section-matter: 1.0.0
strip-bom-string: 1.0.0
h3@1.15.11:
dependencies:
cookie-es: 1.2.3
@@ -8660,6 +8683,11 @@ snapshots:
js-tokens@4.0.0: {}
js-yaml@3.15.1:
dependencies:
argparse: 1.0.10
esprima: 4.0.1
js-yaml@4.3.1:
dependencies:
argparse: 2.0.1
@@ -9157,8 +9185,6 @@ snapshots:
nan@2.28.0:
optional: true
nanoid@3.3.16: {}
nanoid@3.3.18: {}
nanospinner@1.2.2:
@@ -9659,12 +9685,6 @@ snapshots:
postcss: 8.5.26
quote-unquote: 1.0.0
postcss@8.5.22:
dependencies:
nanoid: 3.3.16
picocolors: 1.1.1
source-map-js: 1.2.1
postcss@8.5.26:
dependencies:
nanoid: 3.3.18
@@ -10250,6 +10270,8 @@ snapshots:
split2@4.2.0: {}
sprintf-js@1.0.3: {}
stack-generator@2.0.10:
dependencies:
stackframe: 1.3.4
@@ -10346,6 +10368,8 @@ snapshots:
dependencies:
ansi-regex: 6.2.2
strip-bom-string@1.0.0: {}
strip-final-newline@2.0.0: {}
strip-final-newline@3.0.0: {}
@@ -10703,7 +10727,7 @@ snapshots:
vite@5.4.21(@types/node@24.13.3):
dependencies:
esbuild: 0.21.5
postcss: 8.5.22
postcss: 8.5.26
rollup: 4.46.2
optionalDependencies:
'@types/node': 24.13.3

View File

@@ -1,7 +1,11 @@
---
title: Any Variables
description:
Task now supports most variable types, including booleans, integers, floats
and arrays!
author: pd93
date: 2024-05-09
tags: ['experiments', 'variables']
outline: deep
editLink: false
---
@@ -17,6 +21,8 @@ simple problems. Starting from [v3.37.0][v3.37.0], this is no longer the case!
Task now supports most variable types, including **booleans**, **integers**,
**floats** and **arrays**!
<!-- more -->
## What's the big deal?
These changes allow you to use variables in a much more natural way and opens up

View File

@@ -1,9 +1,11 @@
---
title: GitHub Secure Open Source Fund
sidebarTitle: GitHub SOSF
description:
Task participated in the session 4 of the GitHub Secure Open Source program.
Task participated in session 4 of the GitHub Secure Open Source program.
author: andreynering
date: 2026-08-15
tags: ['github', 'security']
outline: deep
editLink: false
---
@@ -18,6 +20,8 @@ Did you know that GitHub has a special program to fund security in open source?
It's the [GitHub Secure Open Source Fund][fund]. We were selected to participate
in session 4 that happened in May 2026 and it was really special for us.
<!-- more -->
71 maintainers from 50 different open source projects and across 22 countries
were selected to participate in the program. It was amazing to meet so many
maintainers from other critical open source projects to learn how to make the
@@ -50,4 +54,5 @@ GitHub wrote a blog post about session 4 that [you can read here][ghblog].
[incident-response-plan]:
https://taskfile.dev/docs/security/incident-response-plan
[threat-model]: https://taskfile.dev/docs/security/threat-model
[ghblog]: https://github.blog/open-source/maintainers/what-50-open-source-projects-taught-us-about-security-in-the-ai-era/
[ghblog]:
https://github.blog/open-source/maintainers/what-50-open-source-projects-taught-us-about-security-in-the-ai-era/

View File

@@ -1,8 +1,9 @@
---
title: go tool task
title: Using `go tool task`
description: How to use Task using go tool.
author: andreynering
date: 2026-04-14
tags: ['installation']
outline: deep
editLink: false
---
@@ -16,6 +17,8 @@ Do you know that you can use Task without really needing to install it?
If you work with Go, you probably depend on external binaries like linters, code
generators and... Task.
<!-- more -->
But asking your coworkers or contributors to install dependencies can be messy.
Everyone is on a different operating system, use a different package manager,
etc. In fact, [Task supports several package managers][install], but even having

View File

@@ -1,8 +1,10 @@
---
title: New `if:` Control and Variable Prompt
title: Conditional Statements and Variable Prompts
sidebarTitle: Conditionals Statements
description: Introduction of the `if:` control and required variable prompts.
author: vmaerten
date: 2026-01-24
tags: ['new-features', 'variables']
outline: deep
editLink: false
---
@@ -14,6 +16,8 @@ editLink: false
The [v3.47.0][release] release is here, and it brings two exciting new features
to Task. Let's take a closer look at them!
<!-- more -->
## The New `if:` Control
This first feature is simply the second most upvoted issue of all time (!) with

View File

@@ -4,56 +4,17 @@ description: Latest news and updates from the Task team
editLink: false
---
<BlogPost
title="GitHub Secure Open Source Fund"
url="/blog/github-secure-open-source-program"
date="2026-04-14"
author="andreynering"
description='Task participated in the session 4 of the GitHub Secure Open Source program.'
:tags="['github', 'security']"
/>
<script setup>
import { data as posts } from '../../.vitepress/blog.data';
</script>
<BlogPost
title="Using `go tool task`"
url="/blog/go-tool-task"
date="2026-04-14"
author="andreynering"
description='How to use Task using "go tool".'
:tags="['installation']"
/>
<BlogPost
title='Conditional Statements and Variable Prompts'
url="/blog/if-and-variable-prompt"
date="2026-01-24"
author="vmaerten"
description="The v3.47.0 release is here, and it brings two exciting new features to Task. Let's take a closer look at them!"
:tags="['new-features', 'variables']"
/>
<BlogPost
title="Announcing Built-in Core Utilities for Windows"
url="/blog/windows-core-utils"
date="2025-09-15"
author="andreynering"
description="When I started Task back in 2017, one of my biggest goals was to build a task runner that would work well on all major platforms, including Windows. At the time, I was using Windows as my main platform, and it caught my attention how much of a pain it was to get a working version of Make on Windows, for example."
:tags="['windows', 'core-utils']"
/>
<BlogPost
title="Any Variables"
url="/blog/any-variables"
date="2024-05-09"
author="pd93"
description="Task has always had variables, but even though you were able to define them using different YAML types, they would always be converted to strings by Task. This limited users to string manipulation and encouraged messy workarounds for simple problems. Starting from v3.37.0, this is no longer the case! Task now supports most variable types, including booleans, integers, floats and arrays!"
:tags="['experiments', 'variables']"
/>
<BlogPost
title="Introducing Experiments"
url="/blog/task-in-2023"
date="2023-09-02"
author="pd93"
description="A look at where Task is, where it's going and how we're going to get there. Lately, Task has been growing extremely quickly and I've found myself thinking a lot about the future of the project and how we continue to evolve and grow. I'm not much of a writer, but I think one of the things we could do better is to communicate these kinds of thoughts to the community."
:tags="['roadmap', 'experiments', 'community']"
v-for="post in posts"
:key="post.url"
:title="post.title"
:url="post.url"
:date="post.date.string"
:author="post.author"
:description="post.excerpt"
:tags="post.tags"
/>

View File

@@ -3,7 +3,8 @@ title: Introducing Experiments
description:
A look at where task is, where it's going and how we're going to get there.
author: pd93
date: 2024-05-09
date: 2023-09-02
tags: ['roadmap', 'experiments', 'community']
outline: deep
editLink: false
---
@@ -19,6 +20,8 @@ communicate these kinds of thoughts to the community. So, with that in mind,
this is the first (hopefully of many) blog posts talking about Task and what
we're up to.
<!-- more -->
## :calendar: So, what have we been up to?
Over the past 12 months or so, @andreynering (Author and maintainer of the

View File

@@ -1,8 +1,10 @@
---
title: 'Announcing Built-in Core Utilities for Windows'
sidebarTitle: Built-in Core Utilities
description: The journey of enhancing Windows support in Task.
author: andreynering
date: 2025-09-15
tags: ['windows', 'core-utils']
outline: deep
editLink: false
---
@@ -16,6 +18,8 @@ runner that would work well on all major platforms, including Windows. At the
time, I was using Windows as my main platform, and it caught my attention how
much of a pain it was to get a working version of Make on Windows, for example.
<!-- more -->
## The very beginning
The very first versions, which looked very prototyp-ish, already supported