A simple build tool that assembles a static site from components, templates, and data. I used it to build v6 of https://tnixc.space
-
Proper error handling (no unwraps please)
-
Switch to using a .config file for configuration
-
Implement caching based on file hashes to avoid unnecessary rebuilds
-
Handle port collisions in dev server
- Improve Template parsing strictness
- Implement type safety-ish warnings for template-data mismatches
- Add CSS scoping in components (waiting for @scope general support)
- Provide warnings for unused and unfound components
- Resolve dual sources of truth for Markdown frontmatter in blog posts (can't fix without proper Markdown parsing into entries)
- Improve JSON parsing error handling
- Implement OG Image and meta generation, especially for Markdown posts
- Exact file and line in error messages
- Implement selective component caching to reduce disk reads
- Conduct and analyze more extensive speed tests
- Improve escaping for special characters ({}, "", etc.) (needed?)
- Bi-directional editing: You can now double click on a rendered
<markdown>
element to edit it, and it's reflected in the source code. - Implement proper Markdown rendering from .md files -> template entries
- Minify after build with minify_html, minifiy-js, lightningcss
- Multiple errors at once
- Better errs with file and more specific messages
- Fix Markdown element indentation issues
- Fix errors to more accurately reflect the source of the error
- Made it much faster by threadding at page_handler
- Enhance flexibility of Markdown syntax highlighting themes (now uses css)
- Check for circular dependencies
- Implement file watcher and Hot Module Reloading (HMR)
- Enhance logging with color, status, etc.
- Add component
- Implement commands: dev, build, new
- Add support for props and slots in components
- Ignore commented out lines during parsing
- Improve error handling (ongoing process)
- Implement templating system
- Implement component system
- Set up file copying from /public to /dist
src
├── components
│ ├── Common
│ │ └── Pill.component.html
│ └── PostLayout.component.html
├── data
│ └── Projects.data.json
├── pages
│ ├── content
│ │ └── about.html
│ └── index.html
├── public
│ ├── assets
│ │ └── image.webp
│ ├── favicon.png
│ ├── fonts
│ │ └── Inter.woff2
│ ├── input.css
│ └── output.css
└── templates
└── Projects.template.html
To use the above, you would run the following command, where target contains a
folder src
.
simple <build|dev|new> /path/to/target
To use components in markup, do the following:
<Component />
<!-- for a self closing component -->
<Layout><h1>Hello world</h1></Layout>
<!-- for a component which contains a <slot></slot> -->
If no content inside a slot component is provided, it will use the fallbacks
inside the <slot>
tags. To access components in folders, use a :
to separate
them like so:
<Folder:Component />
To pass props to a component, use the following syntax:
<Component prop="value" />
Which will be accessible in the component as ${prop}
.
<!-- e.g. in index.html -->
<-Template{Name} />
Think of this like a for each
, where Name
will be used to search for
src/data/Name.data.json
to populate instances of
src/templates/Name.template.html
Below is an example of a template file:
<!-- Posts.template.json -->
<a class="bg-neutral-400/20 p-4 block post relative group" href="${link}">
<h1 class="font-grotesk text-2xl">${title}</h1>
<p class="text-neutral-700 pt-1">Published ${date}</p>
<p class="text-neutral-700 pt-3">${description}</p>
</a>
Note the ${}
items. They will match with the following in Posts.data.json
[
{
"title": "Title",
"description": "desc",
"link": "./content/simple.html",
"date": "dd/mm/yyyy"
},
{...}
]
The data.json
file must contain an array of objects with the keys for the
template.
There's also a <markdown>
component:
<markdown>
# Hello world
<img src="image.webp" alt="alt" />
</markdown>
Will render out to:
<h1>Hello world</h1>
<img src="image.webp" alt="alt" />
You can also use the template syntax to render entries from files.
Take this src/data/Posts.data.json
:
[
{
"link": "./content/simple.html",
"date": "dd/mm/yyyy",
"--entry-path": "content/simple.md"
"--result-path": "content/simple.html"
},
{...}
]
The keys starting with --
are special. The entry-path
key is the path to the
file to be rendered, the base path is src/data
. The result-path
is the path
to the file to be written to.
If the key --entry-path
or --result-path
is present, the program will look
for the file src/templates/Posts.frame.html
and render the entry using that
frame file. Inside that frame file, the string ${--content}
will be inlined as
rendered markdown if the --entry-path
is a markdown file, or the file contents
if it is not a markdown file. Note that the key-value pairs in the object will
work on both the rendered entry file AND the template file. The idea is that you
can use one template for both the table of contents and the individual pages.
If either of these keys are present, the other one must also be present.
Syntax highlighting is supported. It outputs to codeblocks with the syntect highlighting classes. There's tools to convert vscode themes to .tmTheme(textmate theme) files into the css. I made a web app for the process.
Components, templates, and data must following CamalCase
, not contain spaces,
and cannot start with a number. They can contain underscores.