Vision
If I would need to describe what this is about in one sentence, I would say - database for your content. But this doesn’t really help to grasp the whole concept. Let’s take a closer look.
Content layer
Content layer exists in all static site generators (one way or another). Basically:
- there is folder with content (markdown, json, yaml, images etc)
- there is function to get list of all entries. Also it can sort, filter and paginate
- there is function to get one entry. It can parse content (frontmatter, markdown) and render (to html, for example)
- often there is caching layer and reactive interface
Let’s see examples.
Hugo
- folder with content: hardcoded to
content
- list of all entries:
.Site.Pages
- to sort:
.Site.Pages.ByTitle
- to paginate:
.Paginate collection pageNumber
- to filter:
.Site.RegularPages.ByTitle param value
- to filter:
.Resources.ByType value
,.Resources.GetMatch value
- to sort:
- one entry:
- data:
- html:
.Content
- git metadata:
.GitInfo
- frontmatter:
.Params.value
- html:
Astro: Content Collections
- folder with content: hardcoded to
src/content
- list of all entries:
await getCollection(collection);
- to filter:
await getCollection(collection, ({ data }) => {... });
- to sort:
.sort((a,b) => { ... })
(standard JS) - to paginate:
paginate(collection, { pageSize: 2 })
- to filter:
- one entry:
const entry = await getEntry(collection, slug);
- data:
const { Content, headings } = await entry.render();
- html:
<Content />
- frontmatter:
entry.data
- html:
But compared to Hugo we can as well specify schema for the content:
Contentlayer
- folder with content: defined in
defineDocumentType
- list of all entries:
allItems
- to filter:
allItems.filter(x => {...})
(standard JS) - to sort:
allItems.sort((a, b) => {...})
(standard JS)
- to filter:
- one entry:
allItems.find
(standard JS, I guess)
And we can define schema:
Other
Content graph
Articles (markdown files) plus hyperlinks ([some](/thing)
) form graph. Some solutions allows to treat content as graph:
- link resolution: wiki-links, portable markdown links
- backlinks
- visualize content as graph
- detect broken links
Obsidian
Quartz
Other
- detect broken links: remark-lint-no-dead-urls, mdv, markdown-link-check, remark-validate-links
- visualize content as graph: markdown-links, markmap.js, dundalek/markmap
- markdown links: obsidian-export
Query interface
Content layer already exposes some basic query interface. But there are solutions which brings this idea further, they expose query interface as query language.
Most notable solutions in this area are: docsql, obsidian-dataview. They allow to use SQL-like language to query the content.
Other options would be to use some kind of faceted search interface. Or use graph-query language, like Cypher or Datalog.
Core
Main disadvantage of all solutions mentioned above (maybe exept Contentlayer
) is that they are built-in into another applications and not reusable. I think it would be beneficial to implement core library which, later could be reused for:
- content layer for Astro (or Next.js, Nuxt etc.)
- Language Server (LSP)
- CLI to transform markdown files, for example, from Obsidian vault to Hugo format
- second-brain-note-taking app, like Obsidian or Foam