zilker
zilker is a tool for converting input files into output files
the main idea is that you should edit your input files, and zilker will automatically re-build the output files that need to be refreshed.
input files are tracked in git : output files are deployed
a zilker project has 3 main sections:
zilker.js: a configuration file for how zilker should operateinputs/: a folder of your input filesoutputs/: a folder where zilker outputs are located
inputs
// zilker.js
export let inputs = {
pages: Pages(),
views: Views(),
assets: Assets()
}
this is how we map each sub-directory within /inputs to a type of input. all files within pages/ will be treated like pages, all files within views/ will be treated like UI components, all files in assets/ will be treated like assets.
sounds simple, but this is a huge unlock, because input types can be powerfully expressive without endless boilerplate!
outputs
// zilker.js
export let outputs = [
({ views }) => ({
'browser/': {
'hydration.js': views['hydration.js'],
'views.css': views['styles.css'],
}
}),
({ assets }) => ({
'public/(assets)/': assets['static/']
}),
]
outputs tells zilker which functions build files at what paths. it's a little weird at first but is extremely powerful.
the entity is traversed once all the inputs are loaded.
- for every array, each item is visited in series
- for every object, each item is visited in parallel, and each key represents a path segment
- for every function, all input folders are passed into the first argument, and the output is traversed. all output files (so far) are passed into the second argument, allowing for transforms that fit better in the output space
- when the value is a string or a buffer (leaf node), those contents are written as a file to the current path.
input folders are special objects. in one sense, they act like an array with .map, .filter functions. this allows you to traverse over all views and extract their css, or filter only pages that are static, etc. when defining an input, it's possible to define each builds and group builds. each is a virtual file for every input: something like page['meta.json']. group is a virtual file for a list of inputs: something like views['styles.css'].
behind the scenes, zilker tracks which inputs affect which outputs, so that invalidation and rebuilding is as quick as possible. all the user needs to do is configure their inputs, specify their outputs, and zilker handles the rest.
Complete Example
import { Assets, Pages, Views } from 'zilker/inputs'
import { jsFolder } from 'zilker/core'
import { Blogs } from './engine/Blogs'
import { hashSourcesHTML, bundleDirectory } from 'zilker/outputs'
import { getTransformedRoutes } from '@vercel/routing-utils'
const DEV = process.env.NODE_ENV !== "production"
export let server = {
port: 3004,
development: true,
live_reload: DEV,
static_dir: 'outputs/public',
fetch_handler: 'outputs/api/fetch.js',
static_headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Resource-Policy': 'same-origin',
}
}
export let inputs = {
utils: jsFolder(),
assets: Assets(),
pages: Pages({ _document: 'pages/_document.js' }),
views: Views(),
blogs: Blogs(),
}
export let outputs = [
/* INPUTS */
({ pages }) => ({
'public/(pages)/': pages['static-pages/'],
'bun/fetch.js': pages['itty-fetch.js'],
'browser/router.js': pages['client-nav.js'],
'vercel/source/api.func/index.js': pages['vercel-edge.js']
}),
({ views }) => ({
'browser/': {
'hydration.js': views['hydration.js'],
'views.css': views['styles.css'],
}
}),
({ assets }) => ({
'public/(assets)/': assets['static/']
}),
({ blogs }) => ({
'public/blog-content/': blogs['static-html/'],
// '../inputs/blogs/toc.json': blogs['toc.json']
}),
/* OUTPUTS */
{
'public/(js)/': bundleDirectory({ glob: "browser/**/*.js" }),
'public/(css)/': bundleDirectory({ glob: "browser/**/*.css", minify: true, splitting: false }),
'vercel/output/functions/': bundleDirectory({ glob: "vercel/source/**/*.js", target: 'bun', minify: false, splitting: false }),
'api/': bundleDirectory({ glob: "bun/**/*.js", target: 'bun' }),
},
/* OVERWRITE OUTPUTS */
{
'public/(html)/': hashSourcesHTML({ dir: './outputs/public' })
},
{
'vercel/output/config.json': JSON.stringify({
"version": 3,
"routes": getTransformedRoutes({
trailingSlash: false,
cleanUrls: true,
rewrites: [
{ source: '/posts/:name*', destination: '/api' },
],
}).routes
}, null, 2),
'vercel/output/functions/api.func/.vc-config.json': JSON.stringify({
entrypoint: 'index.js',
runtime: 'edge'
},null,2)
}
]