diff --git a/.dependency-cruiser.json b/.dependency-cruiser.json
deleted file mode 100644
index 2651faa..0000000
--- a/.dependency-cruiser.json
+++ /dev/null
@@ -1,129 +0,0 @@
-{
- "forbidden": [
- {
- "name": "not-to-test",
- "comment": "Don't allow dependencies from outside the test folder to test",
- "severity": "error",
- "from": {
- "pathNot": "^(test|spec)"
- },
- "to": {
- "path": "^(test|spec)"
- }
- },
- {
- "name": "not-to-spec",
- "comment": "Don't allow dependencies to (typescript/ javascript/ coffeescript) spec files",
- "severity": "error",
- "from": {},
- "to": {
- "path": "\\.spec\\.(js|ts|ls|coffee|litcoffee|coffee\\.md)$"
- }
- },
- {
- "name": "no-circular",
- "severity": "warn",
- "comment": "Warn in case there's circular dependencies",
- "from": {},
- "to": {
- "circular": true
- }
- },
- {
- "name": "no-deprecated-core",
- "comment": "Warn about dependencies on deprecated core modules.",
- "severity": "warn",
- "from": {},
- "to": {
- "dependencyTypes": [
- "core"
- ],
- "path": "^(punycode|domain|constants|sys|_linklist)$"
- }
- },
- {
- "name": "no-deprecated-npm",
- "comment": "These npm modules are deprecated - find an alternative.",
- "severity": "warn",
- "from": {},
- "to": {
- "dependencyTypes": [
- "deprecated"
- ]
- }
- },
- {
- "name": "not-to-unresolvable",
- "comment": "Don't allow dependencies on modules dependency-cruiser can't resolve to files on disk (which probably means they don't exist)",
- "severity": "error",
- "from": {},
- "to": {
- "couldNotResolve": true
- }
- },
- {
- "name": "not-to-dev-dep",
- "severity": "error",
- "comment": "Don't allow dependencies from src/app/lib to a development only package",
- "from": {
- "path": "^(src|app|lib)",
- "pathNot": "\\.spec\\.(js|ts|ls|coffee|litcoffee|coffee\\.md)$"
- },
- "to": {
- "dependencyTypes": [
- "npm-dev"
- ]
- }
- },
- {
- "name": "no-non-package-json",
- "severity": "error",
- "comment": "Don't allow dependencies to packages not in package.json (except from within node_modules)",
- "from": {
- "pathNot": "^node_modules"
- },
- "to": {
- "dependencyTypes": [
- "unknown",
- "undetermined",
- "npm-no-pkg",
- "npm-unknown"
- ]
- }
- },
- {
- "name": "optional-deps-used",
- "severity": "info",
- "comment": "nothing serious - but just check you have some serious try/ catches around the import/ requires of these",
- "from": {},
- "to": {
- "dependencyTypes": [
- "npm-optional"
- ]
- }
- },
- {
- "name": "peer-deps-used",
- "comment": "Warn about the use of a peer dependency (peer dependencies are deprecated with the advent of npm 3 - and probably gone with version 4).",
- "severity": "warn",
- "from": {},
- "to": {
- "dependencyTypes": [
- "npm-peer"
- ]
- }
- },
- {
- "name": "no-duplicate-dep-types",
- "comment": "Warn if a dependency you're actually using occurs in your package.json more than once (technically: has more than one dependency type)",
- "severity": "warn",
- "from": {},
- "to": {
- "moreThanOneDependencyType": true
- }
- }
- ],
- "options": {
- "doNotFollow": "^node_modules"
- }
-}
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 31ae44d..152df60 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -5,31 +5,157 @@ version: 2
updates:
# Enable version updates for npm
- package-ecosystem: "npm"
- # Look for `package.json` and `lock` files in the `root` directory
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ preact:
+ patterns:
+ - "preact"
+ - "preact-render-to-string"
+ - "htm"
directory: "/"
- # Check the npm registry for updates every day (weekdays)
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/examples/basic"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: "npm"
+ directory: "/examples/css-modules/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/examples/default-layout/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: "npm"
+ directory: "/examples/esbuild-settings"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: "npm"
+ directory: "/examples/markdown-settings/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/examples/nested-dest/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: "npm"
+ directory: "/examples/preact-isomorphic/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
schedule:
interval: "daily"
- package-ecosystem: "npm"
- directory: "/examples/preact/"
+ directory: "/examples/react/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ react:
+ patterns:
+ - "react"
+ - "react-dom"
+ - "@types/react"
+ - "@types/react-dom"
schedule:
interval: "daily"
- package-ecosystem: "npm"
directory: "/examples/string-layouts/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: "npm"
+ directory: "/examples/tailwind/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: "npm"
+ directory: "/examples/type-stripping/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: "npm"
+ directory: "/examples/uhtml-isomorphic/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
+ schedule:
+ interval: "daily"
+ - package-ecosystem: "npm"
+ directory: "/examples/worker-examples/"
+ groups:
+ typescript:
+ patterns:
+ - "@voxpelli/tsconfig"
+ - "@types/node"
+ - "typescript"
schedule:
interval: "daily"
+ # Enable version updates for pnpm
# Enable updates to github actions
- package-ecosystem: "github-actions"
directory: "/"
diff --git a/.github/workflows/neocities-old.yml b/.github/workflows/neocities-old.yml
new file mode 100644
index 0000000..9e067a5
--- /dev/null
+++ b/.github/workflows/neocities-old.yml
@@ -0,0 +1,36 @@
+name: Deploy old website to neociteis
+
+on:
+ push:
+ branches:
+ - master
+
+env:
+ FORCE_COLOR: 1
+
+concurrency: # prevent concurrent deploys doing starnge things
+ group: deploy-to-neocities-old
+ cancel-in-progress: true
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Use Node.js
+ uses: actions/setup-node@v6
+ with:
+ node-version-file: package.json
+ check-latest: true
+ - run: npm i
+ - run: npm run build
+
+ - name: Deploy to neocities
+ uses: bcomnes/deploy-to-neocities@v3
+ with:
+ api_key: ${{ secrets.NEOCITIES_API_TOKEN }}
+ cleanup: true
+ neocities_supporter: true
+ preview_before_deploy: true
diff --git a/.github/workflows/neocities.yml b/.github/workflows/neocities.yml
index c2db337..592f0e6 100644
--- a/.github/workflows/neocities.yml
+++ b/.github/workflows/neocities.yml
@@ -1,9 +1,9 @@
-name: Deploy to neociteis
+name: Deploy domstack website to neociteis
on:
push:
branches:
- - master
+ - next
env:
FORCE_COLOR: 1
@@ -17,10 +17,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Use Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version-file: package.json
check-latest: true
@@ -30,7 +30,7 @@ jobs:
- name: Deploy to neocities
uses: bcomnes/deploy-to-neocities@v3
with:
- api_token: ${{ secrets.NEOCITIES_API_TOKEN }}
+ api_key: ${{ secrets.NEOCITIES_DOMSTACK_API_TOKEN }}
cleanup: true
- neocoties_supporter: true
+ neocities_supporter: true
preview_before_deploy: true
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9ec483a..5e776f2 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -14,12 +14,12 @@ jobs:
version_and_release:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
with:
# fetch full history so things like auto-changelog work properly
fetch-depth: 0
- name: Use Node.js
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version-file: package.json
check-latest: true
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 9d3e1dd..bde822b 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -15,9 +15,9 @@ jobs:
node-version: [lts/*, '23']
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
check-latest: true
@@ -34,7 +34,7 @@ jobs:
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- files: .tap/report/lcov.info
+ files: coverage/lcov.info
parallel: true
coverage:
diff --git a/.gitignore b/.gitignore
index dae330e..f30cc4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,5 @@ coverage
*.d.ts
*.d.ts.map
+!types/**/*.d.ts
+!types/**/*.d.ts.map
diff --git a/CHANGELOG.md b/CHANGELOG.md
index eb7d515..75c008f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,72 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
-## [v10.5.3](https://github.com/bcomnes/top-bun/compare/v10.5.2...v10.5.3)
+## [v11.0.0-beta.7](https://github.com/bcomnes/top-bun/compare/v11.0.0-beta.6...v11.0.0-beta.7)
+
+### Commits
+
+- Add Async type variants for the various layout and page functions [`4bd6bdb`](https://github.com/bcomnes/top-bun/commit/4bd6bdbc10f595a80205e5928a63120292230835)
+
+## [v11.0.0-beta.6](https://github.com/bcomnes/top-bun/compare/v11.0.0-beta.5...v11.0.0-beta.6) - 2025-08-17
+
+### Merged
+
+- Bump the typescript group with 2 updates [`#200`](https://github.com/bcomnes/top-bun/pull/200)
+
+### Commits
+
+- Dependabot groups [`9c68781`](https://github.com/bcomnes/top-bun/commit/9c68781c2e371dd8f628f51a8c3abc3eed422668)
+- Remove @async tag [`518fe7e`](https://github.com/bcomnes/top-bun/commit/518fe7e7fef398ede48b65250c255447c775c115)
+- More update groups [`14062fb`](https://github.com/bcomnes/top-bun/commit/14062fb8b297f1a0cdc82b1d5e559a4cc106d822)
+
+## [v11.0.0-beta.5](https://github.com/bcomnes/top-bun/compare/v11.0.0-beta.4...v11.0.0-beta.5) - 2025-08-16
+
+### Commits
+
+- Fix children types on LayoutFunction [`33b93a3`](https://github.com/bcomnes/top-bun/commit/33b93a3382a4f20ff198268d80e0bb535890245a)
+
+## [v11.0.0-beta.4](https://github.com/bcomnes/top-bun/compare/v11.0.0-beta.3...v11.0.0-beta.4) - 2025-08-16
+
+### Commits
+
+- Rename template variables [`9a9f3d3`](https://github.com/bcomnes/top-bun/commit/9a9f3d34f6f66e975aef640265259cf475cd492d)
+- Remove logging [`e6717c5`](https://github.com/bcomnes/top-bun/commit/e6717c561a0e5dc6262c9d74fd7ba465550cb73d)
+
+## [v11.0.0-beta.3](https://github.com/bcomnes/top-bun/compare/v11.0.0-beta.2...v11.0.0-beta.3) - 2025-08-16
+
+### Commits
+
+- Update docs [`5aa5778`](https://github.com/bcomnes/top-bun/commit/5aa5778621190e4147b39e3084222325f0ea0c77)
+
+## [v11.0.0-beta.2](https://github.com/bcomnes/top-bun/compare/v11.0.0-beta.1...v11.0.0-beta.2) - 2025-08-16
+
+### Commits
+
+- Allow customization of the PageFunction return type [`eae282a`](https://github.com/bcomnes/top-bun/commit/eae282a5f547289a30bbc1b08b1ceb1af15f5aea)
+- Enable customization of LayoutFunction types [`0e1939a`](https://github.com/bcomnes/top-bun/commit/0e1939a78f37620fcd93705a9df0b848e93ddb6d)
+
+## [v11.0.0-beta.1](https://github.com/bcomnes/top-bun/compare/v11.0.0-beta.0...v11.0.0-beta.1) - 2025-08-16
+
+### Merged
+
+- Bump @types/react from 18.3.23 to 19.1.10 in /examples/react [`#199`](https://github.com/bcomnes/top-bun/pull/199)
+- Bump actions/checkout from 4 to 5 [`#196`](https://github.com/bcomnes/top-bun/pull/196)
+
+### Commits
+
+- Fix warning [`e60b67e`](https://github.com/bcomnes/top-bun/commit/e60b67e139490495ad30acf3550f473865cfc7ba)
+- Set up new website action [`a8b0563`](https://github.com/bcomnes/top-bun/commit/a8b0563b805ed9528f99e6faa19b11a37bb8d9c8)
+- Allow for sync PageFunctions [`701c42e`](https://github.com/bcomnes/top-bun/commit/701c42e163050f8d9213368fba378095cf97ab1c)
+
+## [v11.0.0-beta.0](https://github.com/bcomnes/top-bun/compare/v10.5.3...v11.0.0-beta.0) - 2025-07-20
+
+### Commits
+
+- Switch examples over to use preact and general improvements [`289719d`](https://github.com/bcomnes/top-bun/commit/289719d53a69b3e3d7798794eca541628fdd59cd)
+- More docs improvements [`0f16d6a`](https://github.com/bcomnes/top-bun/commit/0f16d6ae23930092f5a3fc82601152fb127c328d)
+- Move to @import syntax [`debc2ae`](https://github.com/bcomnes/top-bun/commit/debc2aec4b81d19bac9aa91d689ec7fe6a6c2627)
+
+## [v10.5.3](https://github.com/bcomnes/top-bun/compare/v10.5.2...v10.5.3) - 2025-07-20
### Merged
diff --git a/README.md b/README.md
index e4621ae..bfa6062 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,26 @@
-# π₯ top-bun
-[](https://npmjs.org/package/top-bun)
-[](https://github.com/bcomnes/top-bun/actions)
-[](https://coveralls.io/github/bcomnes/top-bun?branch=master)
+# domstack
+[](https://npmjs.org/package/@domstack/static)
+[](https://github.com/bcomnes/domstack/actions)
+[](https://coveralls.io/github/bcomnes/domstack?branch=master)
[](https://github.com/voxpelli/types-in-js)
-[![Neocities][neocities-img]](https://top-bun.org)
+[![Neocities][neocities-img]](https://domstack.net)
-`top-bun`: a traditional web bakery made with html, md, css and js.
+`domstack`: Cut the [gordian knot](https://en.wikipedia.org/wiki/Gordian_Knot) of modern web development and build websites with a stack of html, md, css, ts, tsx, (and/or js/jsx).
-(A bakery themed static site generator that's as fun as making bread.)
+DOMStack provides a few project conventions around esbuild ande Node.js that lets you quickly, cleanly and easily build websites and web apps using all of your favorite technolgies without any framework specific impurities, unlocking the web platform as a freeform canvas.
+
+It's fast to learn, quick to build with, and performs better than you are used to.
+
+`domstack` currently ships a static site generator tool which is great for building static wesbites, and static PWA/MPAs.
+There is an experimental fastify plugin in the works that will unlock dynamic hypermedia webapps using the same project structure.
```console
-npm install top-bun
+npm install @domstack/static
```
-- π [`top-bun` docs website](https://top-bun.org)
+- π [domstack docs website](https://domstack.net)
- π¬ [Discord Chat](https://discord.gg/AVTsPRGeR9)
+- π’ [v11 - top-bun is now domstack](https://bret.io/blog/2023/top-bun-is-now-domstack/)
- π’ [v7 Announcement](https://bret.io/blog/2023/reintroducing-top-bun/)
- π [Full TypeScript Support](#typescript-support)
@@ -25,39 +31,39 @@ npm install top-bun
## Usage
```console
-$ top-bun --help
-Usage: top-bun [options]
+$ domstack --help
+Usage: domstack [options]
- Example: top-bun --src website --dest public
+ Example: domstack --src website --dest public
--src, -s path to source directory (default: "src")
--dest, -d path to build destination directory (default: "public")
--ignore, -i comma separated gitignore style ignore string
- --drafts Build draft pages with the `.draft.{md,js,html}` page suffix.
- --target, -t comma separated target strings for esbuild
- --noEsbuildMeta skip writing the esbuild metafile to disk
- --eject, -e eject the top bun default layout, style and client into the src flag directory
+ --drafts Build draft pages with the `.draft.{md,js,ts,html}` page suffix.
+ --eject, -e eject the DOMStack default layout, style and client into the src flag directory
--watch, -w build, watch and serve the site build
--watch-only watch and build the src folder without serving
--copy path to directories to copy into dist; can be used multiple times
--help, -h show help
--version, -v show version information
-top-bun (v10.5.1)
+domstack (v11.0.0)
```
-`top-bun` builds a `src` directory into a `dest` directory (default: `public`).
-`top-bun` is also aliased to a `tb` bin.
+`domstack` builds a `src` directory into a `dest` directory (default: `public`).
+`domstack` is also aliased to a `dom` bin.
-- Running `top-bun` will result in a `build` by default.
-- Running `top-bun --watch` or `top-bun -w` will build the site and start an auto-reloading development web-server that watches for changes.
-- Running `top-bun --eject` or `top-bun -e` will extract the default layout, global styles, and client-side JavaScript into your source directory and add the necessary dependencies to your package.json.
+- Running `domstack` will result in a `build` by default.
+- Running `domstack --watch` or `domstack -w` will build the site and start an auto-reloading development web-server that watches for changes (provided by [Browsersync](https://browsersync.io)).
+- Running `domstack --eject` or `domstack -e` will extract the default layout, global styles, and client-side JavaScript into your source directory and add the necessary dependencies to your package.json.
-`top-bun` is primarily a unix `bin` written for the [Node.js](https://nodejs.org) runtime that is intended to be installed from `npm` as a `devDependency` inside a `package.json` committed to a `git` repository.
+`domstack` is primarily a unix `bin` written for the [Node.js](https://nodejs.org) runtime that is intended to be installed from `npm` as a `devDependency` inside a `package.json` committed to a `git` repository.
It can be used outside of this context, but it works best within it.
## Core Concepts
-`top-bun` builds a website from "pages" in a `src` directory, nearly 1:1 into a `dest` directory.
+`domstack` is a static site generator that builds a website from "pages" in a `src` directory, nearly 1:1 into a `dest` directory.
+By building "pages" from their `src` location to the `dest` destination, the directory structure inside of `src` becomes a "filesystem router" naturally, without any additional moving systems or structures.
+
A `src` directory tree might look something like this:
```bash
@@ -65,47 +71,53 @@ src % tree
.
βββ md-page
β βββ README.md # directories with README.md in them turn into /md-page/index.html.
-β βββ client.js # Every page can define its own client.js script that loads only with it.
+β βββ client.ts # Every page can define its own client.ts script that loads only with it.
β βββ style.css # Every page can define its own style.css style that loads only with it.
β βββ loose-md-page.md # loose markdown get built in place, but lacks some page features.
β βββ nested-page # pages are built in place and can nest.
β βββ README.md # This page is accessed at /md-page/nested-page/.
-β βββ client.js # nested pages are just pages, so they also can have a page scoped client and style.
-β βββ style.css
+β βββ style.css # nested pages are just pages, so they also can have a page scoped client and style.
+β βββ client.js # Anywhere JS loads, you can use .js or .ts
βββ html-page
-β βββ client.jsx # client bundles can also be written in .jsx/.tsx
+β βββ client.tsx # client bundles can also be written in .jsx/.tsx
β βββ page.html # Raw html pages are also supported. They support handlebars template blocks.
-β βββ page.vars.js # pages can define page variables in a page.vars.js.
+β βββ page.vars.ts # pages can define page variables in a page.vars.ts
β βββ style.css
βββ js-page
-β βββ page.js # A page can also just be a plain javascript function that returns content
+β βββ page.js # A page can also just be a plain javascript function that returns content. They can also be type checked.
βββ ts-page
-β βββ client.ts # client bundles can be written in typescript via type stripping
-β βββ page.vars.ts # pages can define page variables in a page.vars.js.
-β βββ page.ts # Anywhere you can use js in top-bun, you can also use typescript files. They compile via speedy type stripping.
+β βββ client.ts # domstack provides type-stripping via Node.JS and esbuild
+β βββ page.vars.ts # use tsc to run typechecking
+β βββ page.ts
βββ feeds
-β βββ feeds.template.js # Templates let you generate any file you want from variables and page data.
+β βββ feeds.template.ts # Templates let you generate any file you want from variables and page data.
+βββ page-with-workers
+β βββ client.ts
+β βββ page.ts
+β βββ counter.worker.ts # Web workers use a .worker.{ts,js} naming convention and are auto-bundled
+β βββ analytics.worker.js
βββ layouts # layouts can live anywhere. The inner content of your page is slotted into your layout.
-β βββ blog.layout.js # pages specify which layout they want by setting a `layout` page variable.
+β βββ blog.layout.ts # pages specify which layout they want by setting a `layout` page variable.
β βββ blog.layout.css # layouts can define an additional layout style.
-β βββ blog.layout.client.js # layouts can also define a layout client.
-β βββ article.layout.js # layouts can extend other layouts, since they are just functions.
-β βββ typescript.layout.ts # layouts can also be written in typescript
-β βββ root.layout.js # the default layout is called root.
+β βββ blog.layout.client.ts # layouts can also define a layout client.
+β βββ article.layout.ts # layouts can extend other layouts, since they are just functions.
+β βββ javascript.layout.js # layouts can also be written in javascript
+β βββ root.layout.ts # the default layout is called "root"
βββ globals # global assets can live anywhere. Here they are in a folder called globals.
-β βββ global.client.js # you can define a global js client that loads on every page.
+β βββ global.client.ts # you can define a global client that loads on every page.
β βββ global.css # you can define a global css file that loads on every page.
-β βββ global.vars.js # site wide variables get defined in global.vars.js.
-β βββ esbuild.settings.js # You can even customize the build settings passed to esbuild!
+β βββ global.vars.ts # site wide variables get defined in global.vars.ts
+β βββ markdown-it.settings.ts # You can customize the markdown-it instance used to render markdown
+β βββ esbuild.settings.ts # You can even customize the build settings passed to esbuild
βββ README.md # This is just a top level page built from a README.md file.
-βββ client.js # the top level page can define a page scoped js client.
-βββ style.js # the top level page can define a page scoped Css style.
+βββ client.ts # the top level page can define a page scoped js client.
+βββ style.css # the top level page can define a page scoped css style.
βββ favicon-16x16.png # static assets can live anywhere. Anything other than JS, CSS and HTML get copied over automatically.
```
-The core idea of `top-bun` is that a `src` directory of markdown, html and js "inner" documents will be transformed into layout wrapped html documents in the `dest` directory, along with page scoped js and css bundles, as well as a global stylesheet and global js bundle.
+The core idea of `domstack` is that a `src` directory of markdown, html and ts/js "inner" documents will be transformed into layout wrapped html documents in the `dest` directory, along with page scoped js and css bundles, as well as a global stylesheet and global js bundle.
-It ships with sane defaults so that you can point `top-bun` at a standard [markdown documented repository](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github) and have it build a website with near-zero preparation.
+It ships with sane defaults so that you can point `domstack` at a standard [markdown documented repository](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github) and have it build a website with near-zero preparation.
## Examples
@@ -113,23 +125,26 @@ A collection of examples can be found in the [`./examples`](./examples) folder.
To run examples:
-```console
-$ git clone git@github.com:bcomnes/top-bun.git
-$ cd top-bun
+```bash
+$ git clone git@github.com:bcomnes/domstack.git
+$ cd domstack
+# install the top level deps
$ npm i
-$ npm run example:{example-name}
+$ cd example:{example-name}
+# install the example deps
$ npm i
+# start the example
$ npm start
```
### Additional examples
-Here are some additional external examples of larger top-bun projects.
-If you have a project that uses top-bun and could act as a nice example, please PR it to the list!
+Here are some additional external examples of larger domstack projects.
+If you have a project that uses domstack and could act as a nice example, please PR it to the list!
-- [Blog Example](https://github.com/bcomnes/bret.io/)
-- [Isomorphic Static/Client App](https://github.com/hifiwi-fi/breadcrum.net/tree/master/packages/web/client)
-- [Zero-Conf Markdown Docs](https://github.com/bcomnes/deploy-to-neocities/blob/70b264bcb37fca5b21e45d6cba9265f97f6bfa6f/package.json#L38)
+- [Blog Example](https://github.com/bcomnes/bret.io/) - A personal blog written with DOMStack
+- [Isomorphic Static/Client App](https://github.com/hifiwi-fi/breadcrum.net/tree/master/packages/web/client) - Pages build from client templates and hydrate on load.
+- [Zero-Conf Markdown Docs](https://github.com/bcomnes/deploy-to-neocities/blob/70b264bcb37fca5b21e45d6cba9265f97f6bfa6f/package.json#L38) - A npm package with markdown docs, transformed into a website without any any configuration
## Pages
@@ -137,17 +152,17 @@ Pages are a named directories inside of `src`, with **one of** the following pag
- `md` pages are [CommonMark](https://commonmark.org) markdown pages, with an optional [YAML](https://yaml.org) front-matter block.
- `html` pages are an inner [html](https://developer.mozilla.org/en-US/docs/Web/HTML) fragment that get inserted into the page layout.
-- `js` pages are a [js](https://developer.mozilla.org/en-US/docs/Web/JavaScript) file that exports a default function that resolves into an inner-html fragment that is inserted into the page layout.
+- `ts`/`js` pages are a [ts](https://developer.mozilla.org/en-US/docs/Glossary/TypeScript)/[js](https://developer.mozilla.org/en-US/docs/Web/JavaScript) file that exports a default function that resolves into an inner-html fragment that is inserted into the page layout.
-Variables are available in all pages. `md` and `html` pages support variable access via [handlebars][hb] template blocks. `js` pages receive variables as part of the argument passed to them. See the [Variables](#variables) section for more info.
+Variables are available in all pages. `md` and `html` pages support variable access via [handlebars][hb] template blocks. `ts`/`js` pages receive variables as part of the argument passed to them. See the [Variables](#variables) section for more info.
-A special variable called `layout` determines which layout the page is rendered into.
+Pages can define a special variable called `layout` determines which layout the page is rendered into.
-Because pages are just directories, they nest and structure naturally. Directories in the `src` folder that lack one of these special page files can exist along side page directories and can be used to store co-located code or static assets without conflict.
+Because pages are just directories, they nest and structure naturally as a filesystem router. Directories in the `src` folder that lack one of these special page files can exist along side page directories and can be used to store co-located code or static assets without conflict.
### `md` pages
-A `md` page looks like this:
+A `md` page looks like this on the filesystem:
```bash
src/page-name/README.md
@@ -167,15 +182,15 @@ An example of a `md` page:
```md
---
-title: A title for my markdown
-favoriteBread: 'Baguette'
+title: A title for a markdown page
+favoriteColor: 'Blue'
---
-Just writing about baking.
+Just writing about web development.
-## Favorite breads
+## Favorite colors
-My favorite bread is \{{ vars.favoriteBread }}.
+My favorite color is {{ vars.favoriteColor }}.
```
### `html` pages
@@ -187,7 +202,7 @@ src/page-name/page.html
```
- `html` pages are named `page.html` inside an associated page folder.
-- `html` pages are the simplest page type in `top-bun`. They let you build with raw html for when you don't want that page to have access to markdown features. Some pages are better off with just raw `html`.
+- `html` pages are the simplest page type in `domstack`. They let you build with raw html for when you don't want that page to have access to markdown features. Some pages are better off with just raw `html`, and the rules with building `html` in a real `html` file are much more flexible than inside of a `md` file.
- `html` page variables can only be set in a `page.vars.js` file inside the page directory.
- `html` pages support [handlebars][hb] template placeholders.
- You can disable `html` page [handlebars][hb] processing by setting the `handlebars` variable to `false`.
@@ -195,35 +210,44 @@ src/page-name/page.html
An example `html` page:
```html
-
Favorite breads
+
Favorite frameworks
-
French
-
Sour dough
-
Dutch crunch
-
-
\{{ vars.favoriteBread }}
+
React
+
Vue
+
Svelte
+
+
{{ vars.favoriteFramework }}
```
-### `js` pages
+### `ts`/`js` pages
-A `js` page looks like this:
+A `ts`/`js` page looks like this:
```bash
+src/page-name/page.ts
+# or
src/page-name/page.js
```
-- `js` pages consist of a named directory with a `page.js` inside of it, that exports a default function that returns the contents of the inner page.
-- a `js` page needs to `export default` a function (async or sync) that accepts a variables argument and returns a string of the inner html of the page, or any other type that your layout can accept.
-- A `js` page can export a `vars` object or function (async or sync) that takes highest variable precedence when rendering the page. `export vars` is similar to a `md` page's front matter.
-- A `js` page receives the standard `top-bun` [Variables](#variables) set.
-- There is no built in handlebars support in `js` pages, however you are free to use any template library that you can import.
-- `js` pages are run in a Node.js context only.
+- `js`/`ts` pages consist of a named directory with a `page.js` or `page.ts` inside of it, that exports a default function that returns the contents of the inner page.
+- a `js`/`ts` page needs to `export default` a function (async or sync) that accepts a variables argument and returns a string of the inner html of the page, or any other type that your layout can accept.
+- You can specify the return type using `PageFunction` where `T` is the variables type and `U` is the return type (defaults to `any`).
+- A `js`/`ts` page can export a `vars` object or function (async or sync) that takes highest variable precedence when rendering the page. `export vars` is similar to a `md` page's front matter.
+- A `js`/`ts` page receives the standard `domstack` [Variables](#variables) set.
+- There is no built in handlebars support in `js`/`ts` pages, however you are free to use any template library that you can import.
+- `js`/`ts` pages are run in a Node.js context only.
-An example `js` page:
+An example TypeScript page:
-```js
-export default async ({
+```typescript
+import type { PageFunction } from '@domstack/static'
+
+export const vars = {
+ favoriteCookie: 'Chocolate Chip with Sea Salt'
+}
+
+export default const page: PageFunction = async ({
vars
}) => {
return /* html */`
@@ -232,35 +256,28 @@ export default async ({
`
}
-export const vars = {
- favoriteCookie: 'Chocolate Chip with Sea Salt'
-}
```
-It is it's recommended to use some level of template processing over raw string templates so that html is well formed and you default escape variable values. Here is a more realistic `js` example that uses [`uhtml`](https://github.com/WebReflection/uhtml) and [types-in-js](https://github.com/voxpelli/types-in-js) and `top-bun` page introspection.
+It is recommended to use some level of template processing over raw string templates so that HTML is well-formed and variable values are properly escaped. Here is a more realistic TypeScript example that uses [`preact`](https://preactjs.com/) with [`htm`](https://github.com/developit/htm) and `domstack` page introspection.
-```js
-// @ts-ignore
-import { html } from 'uhtml-isomorphic'
+```typescript
+import { html } from 'htm/preact'
import { dirname, basename } from 'node:path'
+import type { PageFunction } from '@domstack/static'
-/**
- * @template T
- * @typedef {import('top-bun').LayoutFunction} LayoutFunction
- */
-
-/**
- * @type {LayoutFunction<{
- * favoriteCake: string
- * }>}
- */
-export default async function blogIndex ({
- vars: {
- favoriteCake
- },
+type BlogVars = {
+ favoriteCake: string
+}
+
+export const vars = {
+ favoriteCake: 'Chocolate Cloud Cake'
+}
+
+export default const blogIndex: PageFunction = async ({
+ vars: { favoriteCake },
pages
-}) {
+}) => {
const yearPages = pages.filter(page => dirname(page.pageInfo.path) === 'blog')
return html`
I love ${favoriteCake}!!
@@ -269,10 +286,6 @@ export default async function blogIndex ({
`
}
-
-export const vars = {
- favoriteCake: 'Chocolate Cloud Cake'
-}
```
### Page Styles
@@ -301,17 +314,17 @@ An example of a page `style.css` file:
### Page JS Bundles
-You can create a `client.js` file in any page folder.
+You can create a `client.ts` or `client.js` file in any page folder.
Page bundles are client side JS bundles that are loaded on that one page only.
-You can import common code and modules from relative paths, or `npm` modules.
-The `client.js` page bundles are bundle-split with every other client-side js entry-point, so importing common chunks of code are loaded in a maximally efficient way.
+You can import common code and modules from relative paths, or `npm` modules out of `node_modules`.
+The `client.js` page bundles are bundle-split with every other client-side js/ts entry-point, so importing common chunks of code are loaded in a maximally efficient way.
Page bundles are run in a browser context only, however they can share carefully crafted code that also runs in a Node.js or layout context.
-`js` page bundles are bundled using [`esbuild`][esbuild].
+`ts`/`js` page bundles are bundled using [`esbuild`][esbuild].
An example of a page `client.js` file:
-```js
-/* /some-page/client.js */
+```typescript
+/* /some-page/client.ts */
import { funnyLibrary } from 'funny-library'
import { someHelper } from '../helpers/foo.js'
@@ -321,13 +334,14 @@ await funnyLibrary()
#### .tsx/.jsx
-Client bundles support .jsx and .tsx. They default to preact, so if you want mainlain recat, customize your esbuild settings to load that instead.
+Client bundles support .jsx and .tsx. They default to preact, so if you want mainlain react, customize your esbuild settings to load that instead.
+See the [react](./examples/react/) example for more details.
### Page variable files
-Each page can also have a `page.vars.js` file that exports a `default` function or object that contains page specific variables.
+Each page can also have a `page.vars.ts` or `page.vars.js` file that exports a `default` sync/async function or object that contains page specific variables.
-```js
+```typescript
// export an object
export default {
my: 'vars'
@@ -344,11 +358,11 @@ export default async () => {
}
```
-Page variable files have higher precedent than `global.vars.js` variables, but lower precedent than frontmatter or `vars` page exports.
+Page variable files have higher precedent than `global.vars.ts` variables, but lower precedent than frontmatter or `vars` ts/js page exports.
### Draft pages
-If you add a `.draft.{md,html,js}` to any of the page types, the page is considered a draft page.
+If you add a `.draft.{md,html,ts,js}` to any of the page types, the page is considered a draft page.
Draft pages are not built by default.
If you pass the `--drafts` flag when building or watching, the draft pages will be built.
When draft pages are omitted, they are completely ignored.
@@ -359,6 +373,50 @@ It is a good idea to display something indicating the page is a draft in your te
Any static assets near draft pages will still be copied because static assets are processed in parallel from page generation (to keep things fast).
If you have an idea on how to relate static assets to a draft page for omission, please open a discussion issue.
+Draft pages let you work on pages before they are ready and easily omit them from a build when deploying pages that are ready.
+
+## Web Workers
+
+You can easily write [web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) for a page by adding a file called `${name}.worker.ts` or `${name}.worker.js` where `name` becomes the name of the worker filename in the `workers.json` file.
+DOMStack will build these similarly to page `client.ts` bundles, and will even bundle split their contents with the rest of your site.
+
+```
+page-directory/
+ βββ page.js
+ βββ client.js
+ βββ counter.worker.js # Worker with counter functionality
+ βββ data.worker.js # Worker for data processing
+```
+
+To use a woker, load in a `./workers.json` file that is generated along with the worker bundle to get the final name of the worker entrypoint and then create a worker with that filename.
+
+```typescript
+// First, fetch the workers.json to get worker paths in your client.ts
+async function initializeWorkers() {
+ const response = await fetch('./workers.json');
+ const workersData = await response.json();
+
+ // Initialize workers with the correct hashed filenames
+ const counterWorker = new Worker(
+ new URL(`./${workersData.counter}`, import.meta.url),
+ { type: 'module' }
+ );
+
+ // Use the worker
+ counterWorker.postMessage({ action: 'increment' });
+
+ counterWorker.onmessage = (e) => {
+ console.log(e.data);
+ };
+
+ return counterWorker;
+}
+
+const worker = await initializeWorkers();
+```
+
+See the [Web Workers Example](https://github.com/domstack/domstack/tree/master/examples/worker-example) for a complete implementation.
+
## Layouts
Layouts are "outer page templates" that pages get rendered into.
@@ -367,6 +425,11 @@ You can define as many as you want, and they can live anywhere in the `src` dire
Layouts are named `${layout-name}.layout.js` where `${layout-name}` becomes the name of the layout.
Layouts should have a unique name, and layouts with duplicate name will result in a build error.
+Layouts can be typed using `LayoutFunction` where:
+- `T` is the variables type
+- `U` is the type of content received from pages (defaults to `any`)
+- `V` is the layout's return type (defaults to `string` for HTML output)
+
Example layout file names:
```bash
@@ -374,7 +437,7 @@ src/layouts/root.layout.js # this layout is references as 'root'
src/other-layouts/article.layout.js # this layout is references as 'article'
```
-At a minimum, your site requires a `root` layout (a file named `root.layout.js`), though `top-bun` ships a default `root` layout so defining one in your `src` directory is optional, though recommended.
+At a minimum, your site requires a `root` layout (a file named `root.layout.js`), though `domstack` ships a default `root` layout so defining one in your `src` directory is optional, though recommended.
All pages have a `layout` variable that defaults to `root`. If you set the `layout` variable to a different name, pages will build with a layout matching the name you set to that variable.
@@ -393,7 +456,7 @@ A page referencing a layout name that doesn't have a matching layout file will r
### The default `root.layout.js`
-A layout is a js file that `export default`'s an async or sync function that implements an outer-wrapper html template that will house the inner content from the page (`children`) being rendered. Think of the bread in a sandwich. That's a layout. π₯ͺ
+A layout is a `ts`/`js` file that `export default`'s an async or sync function that implements an outer-wrapper html template that will house the inner content from the page (`children`) being rendered. Think of the frame around a picture. That's a layout. πΌοΈ
It is always passed a single object argument with the following entries:
@@ -404,104 +467,108 @@ It is always passed a single object argument with the following entries:
- `pages`: An array of page data that you can use to generate index pages with, or any other page-introspection based content that you desire.
- `page`: An object with metadata and other facts about the current page being rendered into the template. This will also be found somewhere in the `pages` array.
-The default `root.layout.js` is featured below, and is implemented with [`uhtml`][uhtml], though it could just be done with a template literal or any other template system.
-
-`root.layout.js` can live anywhere in the `src` directory.
-
-```js
-// @ts-ignore
-import { html, render } from 'uhtml-isomorphic'
-
-/**
- * @template {Record} T
- * @typedef {import('top-bun').LayoutFunction} LayoutFunction
- */
-
-/**
- * Build all of the bundles using esbuild.
- *
- * @type {LayoutFunction<{
- * title: string,
- * siteName: string,
- * defaultStyle: boolean
- * }>}
- */
-export default function defaultRootLayout ({
+The default `root.layout.ts` is featured below, and is implemented with [`preact`](https://preactjs.com/) and [`htm`](https://github.com/developit/htm), though it could just be done with a template literal or any other template system that runs in Node.js.
+
+`root.layout.ts` can live anywhere in the `src` directory.
+
+```typescript
+import { html } from 'htm/preact'
+import { render } from 'preact-render-to-string'
+import type { LayoutFunction } from '@domstack/static'
+
+type RootLayoutVars = {
+ title: string,
+ siteName: string,
+ defaultStyle: boolean,
+ basePath?: string
+}
+
+export default const defaultRootLayout: LayoutFunction = ({
vars: {
title,
- siteName = 'TopBun'
+ siteName = 'Domstack',
+ basePath,
/* defaultStyle = true Set this to false in global or page vars to disable the default style in the default layout */
},
scripts,
styles,
- children
- /* pages */
- /* page */
-}) {
- return render(String, html`
+ children,
+ pages,
+ page,
+}) => {
+ return /* html */`
-
-
- ${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName}
-
- ${scripts
- ? scripts.map(script => html``)
- : null}
- ${styles
- ? styles.map(style => html``)
- : null}
-
-
-
- ${typeof children === 'string' ? html([children]) : children /* Support both uhtml and string children. Optional. */}
-
-
+ ${render(html`
+
+
+ ${title ? `${title}` : ''}${title && siteName ? ' | ' : ''}${siteName}
+
+ ${scripts
+ ? scripts.map(script => html``)
+ : null}
+ ${styles
+ ? styles.map(style => html``)
+ : null}
+
+ `)}
+ ${render(html`
+
+ ${typeof children === 'string'
+ ? html``
+ : html`${children}`
+ }
+
+ `)}
-`)
+ `
}
```
-If your `src` folder doesn't have a `root.layout.js` file somewhere in it, `top-bun` will use the default [`default.root.layout.js`](./lib/defaults/default.root.layout.js) file it ships. The default `root` layout includes a special boolean variable called `defaultStyle` that lets you disable a default page style (provided by [mine.css](http://github.com/bcomnes/mine.css)) that it ships with.
+If your `src` folder doesn't have a `root.layout.js` file somewhere in it, `domstack` will use the default [`default.root.layout.js`](./lib/defaults/default.root.layout.js) file it ships. The default `root` layout includes a special boolean variable called `defaultStyle` that lets you disable a default page style (provided by [mine.css](http://github.com/bcomnes/mine.css)) that it ships with.
### Nested layouts
-Since layouts are just functionsβ’οΈ, they nest naturally. If you define the majority of your html page meta detritus in a `root.layout.js`, you can define additional layouts that act as child wrappers, without having to re-define everything in `root.layout.js`.
+Since layouts are just functionsβ’οΈ, they nest naturally. If you define the majority of your html page meta detritus in a `root.layout.js`, you can define additional layouts that act as child wrappers, without having to re-define everything in `root.layout.ts`.
-For example, you could define a `blog.layout.js` that re-uses the `root.layout.js`:
+For example, you could define a `blog.layout.ts` that re-uses the `root.layout.ts`:
-```js
+```typescript
import defaultRootLayout from './root.layout.js'
-// @ts-ignore
-import { html } from 'uhtml-isomorphic'
-
-/**
- * @template {Record} T
- * @typedef {import('top-bun').LayoutFunction} LayoutFunction
- */
-
-/**
- * @typedef {import('./root.layout.js').SiteVars} SiteVars
- */
+import { html } from 'htm/preact'
+import { render } from 'preact-render-to-string'
+import type { LayoutFunction } from '@domstack/static'
+
+// Import the type from root layout
+import type { RootLayoutVars } from './root.layout'
+
+// Extend the RootLayoutVars with blog-specific properties
+interface BlogLayoutVars extends RootLayoutVars {
+ authorImgUrl?: string;
+ authorImgAlt?: string;
+ authorName?: string;
+ authorUrl?: string;
+ publishDate?: string;
+ updatedDate?: string;
+}
-/** @type {LayoutFunction} */
-export default function blogLayout (layoutVars) {
+const blogLayout: LayoutFunction = (layoutVars) => {
const { children: innerChildren, ...rest } = layoutVars
const vars = layoutVars.vars
- const children = html`
-
-
-
-
+
${typeof innerChildren === 'string'
- ? html([innerChildren])
- : innerChildren /* Support both uhtml and string children. Optional. */
+ ? html``
+ : innerChildren
}
-
-
- `
+ `)
const rootArgs = { ...rest, children }
return defaultRootLayout(rootArgs)
}
+
+export default blogLayout
```
Now the `blog.layout.js` becomes a nested layout of `root.layout.js`. No magic, just functions.
-Alternatively, you could compose your layouts from re-usable template functions and strings. If you find your layouts nesting more than one or two levels, perhaps composition would be a better strategy.
+Alternatively, you could compose your layouts from re-usable template functions and strings.
+If you find your layouts nesting more than one or two levels, perhaps composition would be a better strategy.
### Layout styles
You can create a `${layout-name}.layout.css` next to any layout file.
+While the layout file can live anywhere in `src`, the layout style must live next to the associated layout file.
```css
/* /layouts/article.layout.css */
@@ -566,24 +631,25 @@ You can create a `${layout-name}.layout.css` next to any layout file.
Layout styles are loaded on all pages that use that layout.
Layout styles are bundled with [`esbuild`][esbuild] and can bundle relative and `npm` css using css `@import` statements.
-### Layout JS Bundles
+### Layout TS/JS Bundles
-You can create a `${layout-name}.layout.client.js` next to any layout file.
+You can create a `${layout-name}.layout.client.ts` or `${layout-name}.layout.client.js` next to any layout file.
+While the layout file can live anywhere in `src`, the layout client bundles must live next to the associated layout file.
-```js
-/* /layouts/article.layout.client.js */
+```typescript
+/* /layouts/article.layout.client.ts */
console.log('I run on every page rendered with the \'article\' layout')
/* This layout client is included in every page rendered with the 'article' layout */
```
-Layout js bundles are loaded on all pages that use that layout.
-Layout js bundles are bundled with [`esbuild`][esbuild] and can bundle relative and `npm` modules using ESM `import` statements.
+Layout ts/js bundles are loaded on all pages that use that layout.
+Layout ts/js bundles are bundled with [`esbuild`][esbuild] and can bundle relative and `npm` modules using ESM `import` statements.
-### Nested layout JS bundles and styles
+### Nested layout TS/JS bundles and styles
-If you create a nested layout that imports another layout file, **and** that imported layout has a layout style and/or layout js bundle, there is no magic that will include those layout styles and clients into the importing layout. To include those layout styles and clients into an additional layout, just import them into the additional layout client and style files. For example:
+If you create a nested layout that imports another layout file, **and** that imported layout has a layout style and/or layout js bundle, there is no magic that will include those layout styles and clients into the importing layout. To include those layout styles and clients into an additional layout, just import them into the additional layout client and style files. For example, if `article.layout.ts` wraps `root.layout.ts`, you must do the following:
```css
/* article.layout.css */
@@ -592,41 +658,43 @@ If you create a nested layout that imports another layout file, **and** that imp
This will include the layout style from the `root` layout in the `article` layout style.
-```js
-/* article.layout.client.js */
-import './root.layout.client.js'
+```typescript
+/* article.layout.client.ts */
+import './root.layout.client.ts'
```
-These imports will include the `root.layout.js` layout assets into the `blog.layout.js` asset files.
+Adding these imports will include the `root.layout.ts` layout assets into the `blog.layout.ts` asset files.
## Static assets
-All static assets in the `src` directory are copied 1:1 to the `public` directory. Any file in the `src` directory that doesn't end in `.js`, `.css`, `.html`, or `.md` is copied to the `dest` directory.
+All static assets in the `src` directory are copied 1:1 to the `public` directory. Any file in the `src` directory that doesn't end in `.ts`, `.js`, `.css`, `.html`, or `.md` is copied to the `dest` directory.
### `--eject` flag
-The `--eject` (or `-e`) flag extracts top-bun's default layout, global CSS, and client-side JavaScript into your source directory. This allows you to fully customize these files while maintaining the same functionality.
+The `--eject` (or `-e`) flag extracts DOMStack's default layout, global CSS, and client-side JavaScript into your source directory. This allows you to fully customize these files while maintaining the same functionality.
-When you run `top-bun --eject`, it will:
+When you run `domstack --eject`, it will:
1. Create a default root layout file at `layouts/root.layout.js` (or `.mjs` depending on your package.json type)
2. Create a default global CSS file at `globals/global.css`
-3. Create a default client-side JavaScript file at `globals/global.client.js` (or `.mjs`)
+3. Create a default client-side JavaScript file at `globals/global.client.js`
4. Add the necessary dependencies to your package.json:
- mine.css
- - uhtml-isomorphic
+ - preact
+ - htm
+ - preact-render-to-string
- highlight.js
-This is useful when you want to heavily customize the default theme or behavior while still leveraging top-bun's core functionality.
+It is recomended to eject early in your project so that you can customize the root layout as you see fit, and de-couple yourself from potential unwanted changes in the default layout as new versions of DOMStack are released.
### `--copy` directories
You can specify directories to copy into your `dest` directory using the `--copy` flag. Everything in those directories will be copied as-is into the destination, including js, css, html and markdown, preserving the internal directory structure. Conflicting files are not detected or reported and will cause undefined behavior.
-Copy folders must live **outside** of the `dest` directory. Copy directories can be in the src directory allowing for nested builds. In this case they are added to the ignore glob and ignored by the rest of `top-bun`.
+Copy folders must live **outside** of the `dest` directory. Copy directories can be in the src directory allowing for nested builds. In this case they are added to the ignore glob and ignored by the rest of `domstack`.
-This is useful when you have legacy or archived site content that you want to include in your site, but don't want `top-bun` to process or modify it.
-In general, static content should live in your primary `src` directory, however for merging in old static assets over your top-bun build is sometimes easier to reason about when it's kept in a separate folder and isn't processed in any way.
+This is useful when you have legacy or archived site content that you want to include in your site, but don't want `domstack` to process or modify it.
+In general, static content should live in your primary `src` directory, however for merging in old static assets over your domstack build is sometimes easier to reason about when it's kept in a separate folder and isn't processed in any way.
For example:
@@ -656,38 +724,34 @@ public/
Template files let you write any kind of file type to the `dest` folder while customizing the contents of that file with access to the site [Variables](#variables) object, or inject any other kind of data fetched at build time. Template files can be located anywhere and look like:
```bash
-name-of-template.txt.template.js
-
-${name-portion}.template.js
+name-of-template.txt.template.ts
+${name-portion}.template.ts
```
-Template files are a `js` file that default exports one of the following sync/async functions:
+Template files are a `ts`/`js` file that default exports one of the following sync/async functions:
### Simple string template
A function that returns a string. The `name-of-template.txt` portion of the template file name becomes the file name of the output file.
-```js
-/**
- * @template T
- * @typedef {import('top-bun').TemplateFunction} TemplateFunction
- */
-
-/**
- * @type {TemplateFunction<{
- * foo: string,
- * testVar: string
- * }>}
- */
-export default async ({
+```typescript
+// name-of-template.txt.template.ts
+import type { TemplateFunction } from '@domstack/static'
+
+interface TemplateVars {
+ foo: string;
+ testVar: string;
+}
+
+export default const simpleTemplate: TemplateFunction = async ({
vars: {
- foo
+ foo,
+ testVar
}
}) => {
- return `{Hello world
+ return `Hello world
-This is just a file with access to global vars: ${foo}
-`
+This is just a file with access to global vars: ${foo}`
}
```
@@ -695,17 +759,12 @@ This is just a file with access to global vars: ${foo}
A function that returns a single object with a `content` and `outputName` entries. The `outputName` overrides the name portion of the template file name.
-```js
-/**
- * @template T
- * @typedef {import('top-bun').TemplateFunction} TemplateFunction
- */
-
-/**
- * @type {TemplateFunction<{
- * foo: string,
- * }>}
- */
+```typescript
+import type { TemplateFunction } from '@domstack/static'
+
+interface TemplateVars {
+ foo: string;
+}
export default async ({
vars: { foo }
}) => ({
@@ -720,24 +779,20 @@ This is just a file with access to global vars: ${foo}`,
A function that returns an array of objects with a `content` and `outputName` entries. This template file generates more than one file from a single template file.
-```js
-/**
- * @template T
- * @typedef {import('top-bun').TemplateFunction} TemplateFunction
- */
-
-/**
- * @type {TemplateFunction<{
- * foo: string,
- * testVar: string
- * }>}
- */
-export default async function objectArrayTemplate ({
+```typescript
+import type { TemplateFunction } from '@domstack/static'
+
+interface TemplateVars {
+ foo: string;
+ testVar: string;
+}
+
+export default const objectArrayTemplate: TemplateFunction = async ({
vars: {
foo,
testVar
}
-}) {
+}) => {
return [
{
content: `Hello world
@@ -759,17 +814,15 @@ This is just a file with access to global vars: ${testVar}`,
An [AsyncIterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator) that `yields` objects with `content` and `outputName` entries.
-```js
-/**
- * @template T
- * @typedef {import('top-bun').TemplateAsyncIterator} TemplateAsyncIterator
- */
-
-/** @type {TemplateAsyncIterator<{
- * foo: string,
- * testVar: string
- * }>} */
-export default async function * ({
+```typescript
+import type { TemplateAsyncIterator } from '@domstack/static'
+
+interface TemplateVars {
+ foo: string;
+ testVar: string;
+}
+
+export default const templateIterator: TemplateAsyncIterator = async function * ({
vars: {
foo,
testVar
@@ -780,7 +833,7 @@ export default async function * ({
content: `Hello world
This is just a file with access to global vars: ${foo}`,
- outputName: 'async-iterator-1.txt'
+ outputName: 'yielded-1.txt'
}
// Second item
@@ -788,7 +841,7 @@ This is just a file with access to global vars: ${foo}`,
content: `Hello world again
This is just a file with access to global vars: ${testVar}`,
- outputName: 'async-iterator-2.txt'
+ outputName: 'yielded-2.txt'
}
}
```
@@ -799,43 +852,37 @@ Templates receive the standard variables available to pages, so its possible to
The following example shows how to generate an [RSS](https://www.rssboard.org) and [JSON feed](https://www.jsonfeed.org) of the last 10 date sorted pages with the `blog` layout using the AsyncIterator template type.
-```js
+```typescript
import pMap from 'p-map'
-// @ts-ignore
import jsonfeedToAtom from 'jsonfeed-to-atom'
+import type { TemplateAsyncIterator } from '@domstack/static'
+
+interface TemplateVars {
+ title: string;
+ layout: string;
+ siteName: string;
+ homePageUrl: string;
+ authorName: string;
+ authorUrl: string;
+ authorImgUrl?: string;
+ siteDescription: string;
+ language: string;
+}
-/**
- * @template T
- * @typedef {import('top-bun').TemplateAsyncIterator} TemplateAsyncIterator
- */
-
-/** @type {TemplateAsyncIterator<{
- * title: string,
- * layout: string,
- * siteName: string,
- * homePageUrl: string,
- * authorName: string,
- * authorUrl: string,
- * authorImgUrl: string,
- * publishDate: string,
- * siteDescription: string
- * }>}
-*/
-export default async function * feedsTemplate ({
+export default const feedsTemplate: TemplateAsyncIterator = async function * ({
vars: {
siteName,
+ siteDescription,
homePageUrl,
+ language = 'en-us',
authorName,
authorUrl,
authorImgUrl,
- siteDescription
},
pages
}) {
const blogPosts = pages
- // @ts-ignore
.filter(page => page.pageInfo.path.startsWith('blog/') && page.vars['layout'] === 'blog')
- // @ts-ignore
.sort((a, b) => new Date(b.vars.publishDate) - new Date(a.vars.publishDate))
.slice(0, 10)
@@ -875,14 +922,14 @@ export default async function * feedsTemplate ({
## Global Assets
-There are a few important (and optional) global assets that live anywhere in the `src` directory. If duplicate named files that match the global asset file name pattern are found, a build error will occur until the duplicate file is removed.
+There are a few important (and optional) global assets that live anywhere in the `src` directory. If duplicate named files that match the global asset file name pattern are found, a build error will occur until the duplicate file error is resolved.
-### `global.vars.js`
+### `global.vars.ts`
-The `global.vars.js` file should `export default` a variables object or a (sync or async) function that returns a variable object.
+The `global.vars.ts` or `global.vars.js` file should `export default` a variables object or a (sync or async) function that returns a variable object.
The variables in this file are available to all pages, unless the page sets a variable with the same key, taking a higher precedence.
-```js
+```typescript
export default {
siteName: 'The name of my website',
authorName: 'Mr. Wallace'
@@ -891,22 +938,22 @@ export default {
#### `browser` variable
-`global.vars.js` can uniquely export a `browser` object. These object variables are made available in all js bundles. The `browser` export can be an object, or a sync/async function that returns an object.
+`global.vars.ts` can uniquely export a `browser` object. These object variables are made available in all js bundles. The `browser` export can be an object, or a sync/async function that returns an object.
-```js
+```typescript
export const browser = {
- 'process.env.TRANSPORT': transport,
- 'process.env.HOST': host
+ 'process.env.TRANSPORT': 'http',
+ 'process.env.HOST': 'localhost'
}
```
The exported object is passed to esbuild's [`define`](https://esbuild.github.io/api/#define) options and is available to every js bundle.
-### `global.client.js`
+### `global.client.ts`
This is a script bundle that is included on every page. It provides an easy way to inject analytics, or other small scripts that every page should have. Try to minimize what you put in here.
-```js
+```typescript
console.log('I run on every page in the site!')
```
@@ -916,31 +963,109 @@ This is a global stylesheet that every page will use.
Any styles that need to be on every single page should live here.
Importing css from `npm` modules work well here.
-### `esbuild.settings.js`
+### `esbuild.settings.ts`
This is an optional file you can create anywhere.
-It should export a default sync or async function that accepts a single argument (the esbuild settings object generated by top-bun) and returns a modified build object.
+It should export a default sync or async function that accepts a single argument (the esbuild settings object generated by domstack) and returns a modified build object.
Use this to customize the esbuild settings directly.
-You can break top-bun with this, so be careful.
+You can break domstack with this, so be careful.
Here is an example of using this file to polyfill node builtins in the browser bundle:
-```js
+```typescript
import { polyfillNode } from 'esbuild-plugin-polyfill-node'
+// BuildOptions re-exported from esbuild
+import type { BuildOptions } from '@domstack/static'
-export default async function esbuildSettingsOverride (esbuildSettings) {
- esbuildSettings.plugins = [
- polyfillNode(),
- ]
+export default const esbuildSettingsOverride = async (esbuildSettings: BuildOptions): Promise => {
+ esbuildSettings.plugins = [polyfillNode()]
return esbuildSettings
}
```
+Important esbuild settings you may want to set here are:
+
+- [target](https://esbuild.github.io/api/#target) - Set the `target` to make `esbuild` run a few small transforms on your CSS and JS code.
+- [jsx](https://esbuild.github.io/api/#jsx) - Unset this if you want default react transform.
+- [jsxImportSource](https://esbuild.github.io/api/#jsx-import-source) - Unset this if you want default react transform.
+
+### `markdown-it.settings.ts`
+
+This is an optional file you can create anywhere.
+It should export a default sync or async function that accepts a single argument (the markdown-it instance configured by domstack) and returns a modified markdown-it instance.
+Use this to add custom markdown-it plugins or modify the parser configuration.
+Here are some examples:
+
+```typescript
+import markdownItContainer from 'markdown-it-container'
+import markdownItPlantuml from 'markdown-it-plantuml'
+import type { MarkdownIt } from 'markdown-it'
+
+export default const markdownItSettingsOverride = async (md: MarkdownIt) => {
+ // Add custom plugins
+ md.use(markdownItContainer, 'spoiler', {
+ validate: (params: string) => {
+ return params.trim().match(/^spoiler\s+(.*)$/) !== null
+ },
+ render: (tokens: any[], idx: number) => {
+ const m = tokens[idx].info.trim().match(/^spoiler\s+(.*)$/)
+ if (tokens[idx].nesting === 1) {
+ return '' + md.utils.escapeHtml(m[1]) + '\n'
+ } else {
+ return '\n'
+ }
+ }
+ })
+
+ md.use(markdownItPlantuml)
+
+ return md
+}
+```
+
+```typescript
+import markdownIt, { MarkdownIt } from 'markdown-it'
+import myCustomPlugin from './my-custom-plugin'
+
+export default const markdownItSettingsOverride = async (md: MarkdownIt) => {
+ // Create a new instance with different settings
+ const newMd = markdownIt({
+ html: false, // Disable HTML tags in source
+ breaks: true, // Convert \n to
+ linkify: false, // Disable auto-linking
+ })
+
+ // Add only the plugins you want
+ newMd.use(myCustomPlugin)
+
+ return newMd
+}
+
+markdownItSettingsOverride
+```
+
+By default, DOMStack ships with the following markdown-it plugins enabled:
+
+- [markdown-it](https://github.com/markdown-it/markdown-it)
+- [markdown-it-footnote](https://github.com/markdown-it/markdown-it-footnote)
+- [markdown-it-highlightjs](https://github.com/valeriangalliat/markdown-it-highlightjs)
+- [markdown-it-emoji](https://github.com/markdown-it/markdown-it-emoji)
+- [markdown-it-sub](https://github.com/markdown-it/markdown-it-sub)
+- [markdown-it-sup](https://github.com/markdown-it/markdown-it-sup)
+- [markdown-it-deflist](https://github.com/markdown-it/markdown-it-deflist)
+- [markdown-it-ins](https://github.com/markdown-it/markdown-it-ins)
+- [markdown-it-mark](https://github.com/markdown-it/markdown-it-mark)
+- [markdown-it-abbr](https://github.com/markdown-it/markdown-it-abbr)
+- [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists)
+- [markdown-it-anchor](https://github.com/valeriangalliat/markdown-it-anchor)
+- [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs)
+- [markdown-it-table-of-contents](https://github.com/cmaas/markdown-it-table-of-contents)
+
## Variables
Pages, Layouts, and `postVars` all receive an object with the following parameters:
-- `vars`: An object with the variables of `global.vars.js`, `page.vars.js`, and any front-matter,`vars` exports and `postVars` from the page merged together.
-- `pages`: An array of [`PageData`](https://github.com/bcomnes/top-bun/blob/master/lib/build-pages/page-data.js) instances for every page in the site build. Use this array to introspect pages to generate feeds and index pages.
+- `vars`: An object with the variables of `global.vars.ts`, `page.vars.ts`, and any front-matter,`vars` exports and `postVars` from the page merged together.
+- `pages`: An array of [`PageData`](https://github.com/bcomnes/d omstack/blob/master/lib/build-pages/page-data.js) instances for every page in the site build. Use this array to introspect pages to generate feeds and index pages.
- `page`: An object of the page being rendered with the following parameters:
- `type`: The type of page (`md`, `html`, or `js`)
- `path`: The directory path for the page.
@@ -953,39 +1078,38 @@ Pages, Layouts, and `postVars` all receive an object with the following paramete
Template files receive a similar set of variables:
-- `vars`: An object with the variables of `global.vars.js`
-- `pages`: An array of [`PageData`](https://github.com/bcomnes/top-bun/blob/master/lib/build-pages/page-data.js) instances for every page in the site build. Use this array to introspect pages to generate feeds and index pages.
+- `vars`: An object with the variables of `global.vars.ts`
+- `pages`: An array of [`PageData`](https://github.com/bcomnes/domstack/blob/master/lib/build-pages/page-data.js) instances for every page in the site build. Use this array to introspect pages to generate feeds and index pages.
- `template`: An object of the template file data being rendered.
-Where `T` is your set of variables in the `vars` object.
-
### `postVars` post processing variables (Advanced) {#postVars}
-In `page.vars.js` files, you can export a `postVars` sync/async function that returns an object. This function receives the same variable set as pages and layouts. Whatever object is returned from the function is merged into the final `vars` object and is available in the page and layout. This is useful if you want to apply advanced rendering page introspection and insert it into a markdown document (for example, the last few blog posts on a markdown page.)
+In `page.vars.ts` files, you can export a `postVars` sync/async function that returns an object. This function receives the same variable set as pages and layouts. Whatever object is returned from the function is merged into the final `vars` object and is available in the page and layout. This is useful if you want to apply advanced rendering page introspection and insert it into a markdown document (for example, the last few blog posts on a markdown page.)
For example:
-```js
-// page.vars.js
-import { html, render } from 'uhtml-isomorphic'
+```typescript
+import { html } from 'htm/preact'
+import { render } from 'preact-render-to-string'
+import type { PostVarsFunction } from '@domstack/static'
-export async function postVars ({
+export const postVars: PostVarsFunction = async ({
pages
-}) {
+}) => {
const blogPosts = pages
.filter(page => page.vars.layout === 'article')
.sort((a, b) => new Date(b.vars.publishDate) - new Date(a.vars.publishDate))
.slice(0, 5)
- const blogpostsHtml = render(String, html`
`)
- const pageVars = {
+ return {
blogPostsHtml: blogpostsHtml
}
-
- return pageVars
}
```
@@ -1008,22 +1130,22 @@ This `postVars` renders some html from page introspection of the last 5 blog pos
## [Blog](./blog/)
-\{{{ vars.blogPostsHtml }}}
+{{{ vars.blogPostsHtml }}}
```
-
## TypeScript Support
-`top-bun` now supports **TypeScript** via native type-stripping in Node.js.
+`domstack` supports **TypeScript** via native type-stripping in Node.js.
-- **Requires Node.js β₯23** *(built-in)* or **Node.js 22** with the `NODE_OPTIONS="--experimental-strip-types" top-bun` env variable.
+- **Requires Node.js β₯23** *(built-in)* or **Node.js 22** with the `NODE_OPTIONS="--experimental-strip-types" domstack` env variable.
- Seamlessly mix `.ts`, `.mts`, `.cts` files alongside `.js`, `.mjs`, `.cjs`.
- No explicit compilation step neededβNode.js handles type stripping at runtime.
-- Fully compatible with existing `top-bun` file naming conventions.
+- Fully compatible with existing `domstack` file naming conventions.
+- Anywhere DOMStack loads JS files, it can now load TS files.
### Supported File Types
-Anywhere you can use a `.js`, `.mjs` or `.cjs` file in top-bun, you can now use `.ts`, `.mts`, `.cts`.
+Anywhere you can use a `.js`, `.mjs` or `.cjs` file in domstack, you can now use `.ts`, `.mts`, `.cts`.
When running in a Node.js context, [type-stripping](https://nodejs.org/api/typescript.html#type-stripping) is used.
When running in a web client context, [esbuild](https://esbuild.github.io/content-types/#typescript) type stripping is used.
Type stripping provides 0 type checking, so be sure to set up `tsc` and `tsconfig.json` so you can catch type errors while editing or in CI.
@@ -1054,70 +1176,62 @@ Install [@voxpelli/tsconfig](https://ghub.io/@voxpelli/tsconfig) which provides
}
```
-### Using TypeScript with top-bun Types
+### Using TypeScript with domstack Types
-You can use `top-bun`'s built-in types to strongly type your layout, page, and template functions. The following types are available:
+You can use `domstack`'s built-in types to strongly type your layout, page, and template functions. The following types are available:
```ts
import type {
LayoutFunction,
+ AsyncLayoutFunction,
PostVarsFunction,
+ AsyncPostVarsFunction,
PageFunction,
+ AsyncPageFunction,
TemplateFunction,
TemplateAsyncIterator
-} from 'top-bun'
+} from '@domstack/static'
```
-They are all generic and accept a variable template that you can develop and share between files.
-
-### TypeScript Examples
+> **Note:** All function types have both synchronous and asynchronous variants (e.g., `LayoutFunction` and `AsyncLayoutFunction`). Use the async variants when your function is an `async` function.
-#### Page Function
-
-```typescript
-// page.ts
-import type { PageFunction } from 'top-bun'
+They are all generic and accept a variable template that you can develop and share between files.
-export const vars = {
- message: 'TypeScript pages are easy!'
-}
+#### Advanced Type Parameters for PageFunction and LayoutFunction
-const page: PageFunction = async ({ vars }) => {
- return `
Hello from TypeScript!
${vars.message}
`
-}
+`PageFunction` and `LayoutFunction` support additional template parameters for precise return type control:
-export default page
-```
+**PageFunction**
+- `T` - The type of variables passed to the page (required)
+- `U` - The return type of the page function (optional, defaults to `any`)
-#### Layout Function
+**LayoutFunction**
+- `T` - The type of variables passed to the layout (required)
+- `U` - The type of content received from pages as `children` (optional, defaults to `any`)
+- `V` - The return type of the layout function (optional, defaults to `string`)
-```typescript
-// root.layout.ts
-import type { LayoutFunction } from 'top-bun'
-import { html, render } from 'uhtml-isomorphic'
+This allows pages to return custom types (like VDOM or JSON) while ensuring layouts produce HTML strings:
-type Vars = {
- siteName: string,
- title?: string
+```ts
+// Define custom types
+type VDOMNode = {
+ type: string
+ props: Record
+ children: Array
}
-const layout: LayoutFunction = ({ vars, scripts, styles, children }) => {
- return render(String, html`
-
-
-
- ${vars.title ? `${vars.title} | ` : ''}${vars.siteName}
- ${styles?.map(style => html``)}
- ${scripts?.map(script => html``)}
-
-
- ${children}
-
-
- `)
-}
+// Page returns VDOM
+const page: PageFunction<{title: string}, VDOMNode> = ({ vars }) => ({
+ type: 'h1',
+ props: {},
+ children: [vars.title]
+})
-export default layout
+// Layout accepts VDOM, returns HTML string
+const layout: LayoutFunction<{site: string}, VDOMNode, string> = ({ children }) => {
+ const html = renderVDOM(children) // Convert VDOM to HTML
+ return `${html}`
+}
```
## Design Goals
@@ -1132,8 +1246,8 @@ export default layout
- Library agnostic. Strings are the interchange format.
- Pages are shallow apps. New page, new blank canvas.
- Just a program. `js` pages and layouts are just JavaScript programs. This provides an escape hatch to do anything. Use any template language want, but probably just use tagged template literals.
-- Steps remain orthogonal. Static file copying, css and js bundling, are mere optimizations on top of the `src` folder. The `src` folder should essentially run in the browser. Each step in a `top-bun` build should work independent of the others. This allows for maximal parallelism when building.
-- Standardized entrypoints. Every page in a `top-bun` site has a natural and obvious entrypoint. There is no magic redirection to learn about.
+- Steps remain orthogonal. Static file copying, css and js bundling, are mere optimizations on top of the `src` folder. The `src` folder should essentially run in the browser. Each step in a `domstack` build should work independent of the others. This allows for maximal parallelism when building.
+- Standardized entrypoints. Every page in a `domstack` site has a natural and obvious entrypoint. There is no magic redirection to learn about.
- Pages build into `index.html` files inside of named directories. This allows for naturally colocated assets next to the page, pretty URLs and full support for relative URLs.
- No parallel directory structures. You should never be forced to have two directories with identical layouts to put files next to each other. Everything should be colocatable.
- Markdown entrypoints are named README.md. This allows for the `src` folder to be fully navigable in GitHub and other git repo hosting providing a natural hosted CMS UI.
@@ -1146,31 +1260,191 @@ export default layout
## FAQ
-Top-**Bun**? Like the JS runtime?
+Why DOMStack?
-: No, like the bakery from Wallace and Gromit in ["A Matter of Loaf and Death"](https://www.youtube.com/watch?v=zXBmZLmfQZ4s)
+: DOMStack is named after the DOM (Document Object Model) and the concept of stacking technologies together to build websites. It represents the layering of HTML, CSS, and JavaScript in a cohesive build system.
-How does `top-bun` relate to [`sitedown`](https://ghub.io/sitedown)
+How does `domstack` relate to [`sitedown`](https://ghub.io/sitedown)
-: `top-bun` used to be called `siteup` which is sort of like "markup", which is related to "markdown", which inspired the project `sitedown` to which `top-bun` is a spiritual off-shot of. Put a folder of web documents in your `top-bun` oven, and bake a website.
+: `domstack` used to be called `siteup` which is sort of like "markup", which is related to "markdown", which inspired the project `sitedown` to which `domstack` is a spiritual off-shoot of. Put a folder of web documents in your `domstack` build system, and generate a website.
## Examples
-Look at [examples](./examples/) and `top-bun` [dependents](https://github.com/bcomnes/top-bun/network/dependents) for some examples how `top-bun` can work.
+Look at [examples](./examples/) and `domstack` [dependents](https://github.com/bcomnes/domstack/network/dependents) for some examples how `domstack` can work.
## Implementation
-`top-bun` bundles the best tools for every technology in the stack:
+`domstack` bundles the best tools for every technology in the stack:
- `js` and `css` is bundled with [`esbuild`](https://github.com/evanw/esbuild).
- `md` is processed with [markdown-it](https://github.com/markdown-it/markdown-it).
- static files are processed with [cpx2](https://github.com/bcomnes/cpx2).
+- `ts` support via native typestripping in Node.js and esbuild.
+- `jsx/tsx` support via esbuild.
These tools are treated as implementation details, but they may be exposed more in the future. The idea is that they can be swapped out for better tools in the future if they don't make it.
+### Build Process Flow
+
+The following diagram illustrates the DomStack build process:
+
+```
+ βββββββββββββββ
+ β START β
+ ββββββββ¬βββββββ
+ β
+ βΌ
+ ββββββββββββββββββββ
+ β identifyPages() β
+ β β
+ β β’ Find pages β
+ β β’ Find layouts β
+ β β’ Find templates β
+ β β’ Find globals β
+ β β’ Find settings β
+ ββββββββββ¬ββββββββββ
+ β
+ β
+ βββββββββββββββββββββΌββββββββββββββββββββ
+ β β β
+ βΌ βΌ βΌ
+βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
+β buildEsbuild() β β buildStatic() β β buildCopy() β
+β β β β β β
+β β’ Bundle JS/CSS β β β’ Copy static β β β’ Copy extra β
+β β’ Generate β β files β β directories β
+β metafile β β (if enabled) β β from opts β
+ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ
+ β β β
+ βββββββββββββββββββββΌββββββββββββββββββββ
+ β
+ βΌ
+ ββββββββββββββββββββ
+ β buildPages() β
+ β β
+ β β’ Process HTML β
+ β β’ Process MD β
+ β β’ Process JS β
+ β β’ Apply layouts β
+ ββββββββββ¬ββββββββββ
+ β
+ βΌ
+ ββββββββββββββββββββ
+ β Return Results β
+ β β
+ β β’ siteData β
+ β β’ esbuildResults β
+ β β’ staticResults β
+ β β’ copyResults β
+ β β’ pageResults β
+ β β’ warnings β
+ ββββββββββββββββββββ
+```
+
+The build process follows these key steps:
+
+1. **Page identification** - Scans the source directory to identify all pages, layouts, templates, and global assets
+2. **Destination preparation** - Ensures the destination directory is ready for the build output
+3. **Parallel asset processing** - Three operations run concurrently:
+ - JavaScript and CSS bundling via esbuild
+ - Static file copying (when enabled)
+ - Additional directory copying (from `--copy` options)
+4. **Page building** - Processes all pages, applying layouts and generating final HTML
+
+This architecture allows for efficient parallel processing of independent tasks while maintaining the correct build order dependencies.
+
+#### buildPages() Detail
+
+The `buildPages()` step processes pages in parallel with a concurrency limit:
+
+```
+ ββββββββββββββββββββ
+ β buildPages() β
+ ββββββββββ¬ββββββββββ
+ β
+ ββββββββββΌββββββββββ
+ β Resolve Once: β
+ β β’ Global vars β
+ β β’ All layouts β
+ ββββββββββ¬ββββββββββ
+ β
+ ββββββββββββββΌββββββββββββββββ
+ β Parallel Page Queue β
+ β(Concurrency: min(CPUs, 24))β
+ ββββββββββββββ¬ββββββββββββββββ
+ β
+ ββββββββββββββββββββββΌβββββββββββββββββββββ
+ β β β
+ βΌ βΌ βΌ
+βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
+β MD Page Task β β HTML Page Task β β JS Page Task β
+βββββββββββββββββββ€ βββββββββββββββββββ€ βββββββββββββββββββ€
+β βββββββββββββββ β β βββββββββββββββ β β βββββββββββββββ β
+β β1. Read .md β β β β1. Read .htmlβ β β β1. Import .jsβ β
+β β file β β β β file β β β β module β β
+β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β
+β βΌ β β βΌ β β βΌ β
+β βββββββββββββββ β β βββββββββββββββ β β βββββββββββββββ β
+β β2. Extract β β β β2. Variable β β β β2. Variable β β
+β β frontmatter β β β β Resolution β β β β Resolution β β
+β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β
+β βΌ β β βΌ β β βΌ β
+β βββββββββββββββ β β βββββββββββββββ β β βββββββββββββββ β
+β β Frontmatter β β β βpage.vars.js β β β β Exported β β
+β β vars β β β β β β β β vars β β
+β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β
+β βΌ β β βΌ β β βΌ β
+β βββββββββββββββ β β βββββββββββββββ β β βββββββββββββββ β
+β βpage.vars.js β β β β postVars β β β βpage.vars.js β β
+β β β β β β β β β β β β
+β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β
+β βΌ β β βΌ β β βΌ β
+β βββββββββββββββ β β βββββββββββββββ β β βββββββββββββββ β
+β β postVars β β β β3. Handlebarsβ β β β postVars β β
+β β β β β β (if enabled)β β β β β β
+β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β
+β βΌ β β βΌ β β βΌ β
+β βββββββββββββββ β β βββββββββββββββ β β βββββββββββββββ β
+β β3. Render MD β β β β4. Render β β β β3. Execute β β
+β β to HTML β β β β with layoutβ β β β page func β β
+β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β β ββββββββ¬βββββββ β
+β βΌ β β βΌ β β βΌ β
+β βββββββββββββββ β β βββββββββββββββ β β βββββββββββββββ β
+β β4. Extract β β β β5. Write HTMLβ β β β4. Render β β
+β β title (h1) β β β β β β β β with layoutβ β
+β ββββββββ¬βββββββ β β βββββββββββββββ β β ββββββββ¬βββββββ β
+β βΌ β β β β βΌ β
+β βββββββββββββββ β β β β βββββββββββββββ β
+β β5. Render β β β β β β5. Write HTMLβ β
+β β with layoutβ β β β β β β β
+β ββββββββ¬βββββββ β β β β βββββββββββββββ β
+β βΌ β β β β β
+β βββββββββββββββ β β β β β
+β β6. Write HTMLβ β β β β β
+β βββββββββββββββ β β β β β
+βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
+ β β β
+ ββββββββββββββββββββββββΌβββββββββββββββββββββββ
+ β
+ βΌ
+ ββββββββββββββββββββ
+ β Complete when β
+ β all pages done β
+ ββββββββββββββββββββ
+```
+
+Variable Resolution Layers:
+- **Global vars** - Site-wide variables from `global.vars.js` (resolved once)
+- **Layout vars** - Layout-specific variables from layout functions (resolved once)
+- **Page-specific vars** vary by type:
+ - **MD pages**: frontmatter β page.vars.js β postVars
+ - **HTML pages**: page.vars.js β postVars
+ - **JS pages**: exported vars β page.vars.js β postVars
+- **postVars** - Post-processing function that can modify variables based on all resolved data
+
## Roadmap
-`top-bun` works and has a rudimentary watch command, but hasn't been battle tested yet.
+`domstack` works and has a rudimentary watch command, but hasn't been battle tested yet.
If you end up trying it out, please open any issues or ideas that you have, and feel free to share what you build.
Some notable features are included below, see the [roadmap](https://github.com/users/bcomnes/projects/3/) for a more in depth view of whats planned.
@@ -1199,7 +1473,7 @@ Some notable features are included below, see the [roadmap](https://github.com/u
- [x] Handlebars template support in `md` and `html`
- [x] `mjs` and `cjs` file extension support
- [x] Improved watch log output
-- [x] Docs website built with `top-bin`: https://top-bun.org
+- [x] Docs website built with `domstack`: https://domstack.net
- [x] `--eject` cli flag
- [x] Global assets can live anywhere
- [x] Built in browsersync dev server
@@ -1208,10 +1482,17 @@ Some notable features are included below, see the [roadmap](https://github.com/u
- [x] Copy folders
- [x] Full Typescript support via native type stripping
- [x] JSX+TSX support in client bundles
+- [x] Rename to domstack
+- [x] markdown-it.settings.ts support
+- [x] page-worker.worker.ts page worker support
- ...[See roadmap](https://github.com/users/bcomnes/projects/3/)
## History
+DOMStack started its life as `top-bun` in 2023, named after the bakery from Wallace and Gromit. The project was created to provide a simple, fast, and flexible static site generator that could handle modern web development needs while staying true to web standards.
+
+The project was renamed to DOMStack in version 11 to better reflect its purpose and avoid confusion with the Bun JavaScript runtime. The name DOMStack represents the layering of web technologies (HTML, CSS, JavaScript).
+It is also an homage to [substack](https://substack.net) as well as a play on the productname that stole his name.
## Links
@@ -1223,7 +1504,8 @@ Some notable features are included below, see the [roadmap](https://github.com/u
[MIT](LICENSE)
-[uhtml]: https://github.com/WebReflection/uhtml
+[preact]: https://preactjs.com/
+[htm]: https://github.com/developit/htm
[hb]: https://handlebarsjs.com
[esbuild]: http://esbuild.github.io
-[neocities-img]: https://img.shields.io/website/https/top-bun.neocities.org?label=neocities&logo=data:image/png;base64,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
+[neocities-img]: https://img.shields.io/website/https/domstack.neocities.org?label=neocities&logo=data:image/png;base64,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
diff --git a/bin.js b/bin.js
index c92d18f..9d8cbf6 100755
--- a/bin.js
+++ b/bin.js
@@ -1,13 +1,17 @@
#!/usr/bin/env node
-// @ts-ignore
+/**
+ * @import {DomStackOpts as DomStackOpts} from './lib/builder.js'
+ * @import { ArgscloptsParseArgsOptionsConfig } from 'argsclopts'
+ */
+
import { readFile } from 'node:fs/promises'
import { resolve, join, relative } from 'node:path'
import { parseArgs } from 'node:util'
import { printHelpText } from 'argsclopts'
import readline from 'node:readline'
import process from 'process'
-// @ts-ignore
+// @ts-expect-error
import tree from 'pretty-tree'
import { inspect } from 'util'
import { packageDirectory } from 'package-directory'
@@ -15,16 +19,11 @@ import { readPackage } from 'read-pkg'
import { addPackageDependencies } from 'write-package'
import { copyFile } from './lib/helpers/copy-file.js'
-import { TopBun } from './index.js'
-import { TopBunAggregateError } from './lib/helpers/top-bun-aggregate-error.js'
+import { DomStack } from './index.js'
+import { DomStackAggregateError } from './lib/helpers/dom-stack-aggregate-error.js'
import { generateTreeData } from './lib/helpers/generate-tree-data.js'
import { askYesNo } from './lib/helpers/cli-prompt.js'
-/**
- * @import {TopBunOpts} from './lib/builder.js'
- * @import { ArgscloptsParseArgsOptionsConfig } from 'argsclopts'
- */
-
const __dirname = import.meta.dirname
async function getPkg () {
@@ -69,7 +68,7 @@ const options = {
eject: {
type: 'boolean',
short: 'e',
- help: 'eject the top bun default layout, style and client into the src flag directory',
+ help: 'eject the DOMStack default layout, style and client into the src flag directory',
},
watch: {
type: 'boolean',
@@ -162,7 +161,7 @@ async function run () {
}
console.log(`
-top-bun eject actions:
+domstack eject actions:
- Write ${join(relativeSrc, targetLayoutPath)}
- Write ${join(relativeSrc, targetGlobalStylePath)}
- Write ${join(relativeSrc, targetGlobalClientPath)}
@@ -200,7 +199,7 @@ top-bun eject actions:
process.exit(0)
}
- /** @type {TopBunOpts} */
+ /** @type {DomStackOpts} */
const opts = {}
if (argv['ignore']) opts.ignore = String(argv['ignore']).split(',')
@@ -213,14 +212,14 @@ top-bun eject actions:
opts.copy = copyPaths.map(p => resolve(cwd, p))
}
- const topBun = new TopBun(src, dest, opts)
+ const domStack = new DomStack(src, dest, opts)
process.once('SIGINT', quit)
process.once('SIGTERM', quit)
async function quit () {
- if (topBun.watching) {
- const results = await topBun.stopWatching()
+ if (domStack.watching) {
+ const results = await domStack.stopWatching()
console.log(results)
console.log('watching stopped')
}
@@ -230,7 +229,7 @@ top-bun eject actions:
if (!argv['watch'] && !argv['watch-only']) {
try {
- const results = await topBun.build()
+ const results = await domStack.build()
console.log(tree(generateTreeData(cwd, src, dest, results)))
if (results?.warnings?.length > 0) {
console.log(
@@ -247,7 +246,7 @@ top-bun eject actions:
console.log('\nBuild Success!\n\n')
} catch (err) {
if (!(err instanceof Error || err instanceof AggregateError)) throw new Error('Non-error thrown', { cause: err })
- if (err instanceof TopBunAggregateError) {
+ if (err instanceof DomStackAggregateError) {
if (err?.results?.siteData?.pages) {
console.log(tree(generateTreeData(cwd, src, dest, err.results)))
}
@@ -259,7 +258,7 @@ top-bun eject actions:
process.exit(1)
}
} else {
- const initialResults = await topBun.watch({
+ const initialResults = await domStack.watch({
serve: !argv['watch-only'],
})
console.log(tree(generateTreeData(cwd, src, dest, initialResults)))
@@ -279,6 +278,6 @@ top-bun eject actions:
}
run().catch(err => {
- console.error(new Error('Unhandled top-bun error', { cause: err }))
+ console.error(new Error('Unhandled domstack error', { cause: err }))
process.exit(1)
})
diff --git a/dependencygraph.svg b/dependencygraph.svg
index cf4f222..7db9b83 100644
--- a/dependencygraph.svg
+++ b/dependencygraph.svg
@@ -1,1306 +1,1685 @@
-
-