~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A guide shows how to deploy a repository's site

Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:guide/sites
docs/design/pages.md+4−2
@@ -124,9 +124,11 @@ for releases.
## Deploying on a push
A site deploys on every push to a branch by a workflow step that runs
`knotless site` on `push` to that branch. A shared step makes
`knotless site` on `push` to that branch. The `site` shared step makes
this one line (see [reusable workflows](reusable-workflows.md)). The
[workflow reference](../reference/workflows.md) lists the keys.
[sites guide](../guide/sites.md#deploy-on-every-push) shows the
workflow, and the [workflow reference](../reference/workflows.md) lists
the keys.
There is no mode that serves a branch's tree directly, so there is one way
to store and serve a site. The reasons are these.
docs/guide/sites.mdnew+148−0
@@ -0,0 +1,148 @@
# Sites
A public repository can have a website. You deploy a directory of files,
such as a build's output, and knotless serves it at
`https://<owner>.knotless.page/<repo>/`. The files are stored as blobs
in your own account, in one record that each deploy replaces.
[Pages](../design/pages.md) explains how sites are stored and served, and
the [command reference](../reference/cli.md) lists every flag of
`knotless site`.
## Deploy a site
As the repository's owner, give `knotless site` the repository and the
directory to deploy:
```sh
knotless site knotless://alice.example.com/blog dist
```
It uploads only the files the live site does not hold already, then
replaces the site's record. It prints how many it uploaded and the
address:
```
uploaded 3 of 41 files
https://alice-example-com.knotless.page/blog/
```
The new site is live within seconds. A visitor sees the old site or the
new one, never a mix of the two.
The subdomain is your handle with each `-` doubled and each `.` turned
into a `-`: `alice.example.com` is `alice-example-com`. It follows your
handle, so it changes when your handle does.
A site holds 1 to 2,000 files. A private repository cannot have a site
yet.
## Build for the path
The site is served under `/<repo>/`, not at the root, so build it with
that as its base path. In Vite, that is `base`:
```js
// vite.config.js
export default { base: '/blog/' }
```
In SvelteKit it is `kit.paths.base`. A build with the wrong base loads
its pages but not their scripts and styles.
## Serve a single-page app
A single-page app routes in the browser, so every page has to load the
app. Name the app's page as the fallback:
```sh
knotless site knotless://alice.example.com/app dist --fallback index.html
```
A request for a page that no file matches then gets `index.html`, with
status 200, and the app's router takes the path from there. A request
counts as one for a page when it accepts `text/html`, or when the last
part of its path has no extension.
A file still comes first: `/app/assets/main.js` serves that file. A
missing script or image gets a 404, not the app's HTML, so a broken build
shows as one.
## Add a 404 page
To answer a missing path with a page of your own, name it:
```sh
knotless site knotless://alice.example.com/blog dist --not-found 404.html
```
A path that no file matches gets that page with status 404. With a
fallback too, pages get the fallback, and other files get the 404 page.
The fallback and the 404 page must each be one of the files you deploy.
## Deploy on every push
The `site` shared step deploys from a workflow. It runs `knotless site` as
the repository's owner, and installs knotless first if the image has
none.
The step logs in with an app password of the owner's account. Make one
at your PDS (on Bluesky, under Settings, Privacy and security, App
passwords). Then give it to the runners as a secret, limited to the
branch you deploy from:
```sh
printf %s "$APP_PASSWORD" | knotless secret knotless://alice.example.com/blog set SITE_PASSWORD --ref refs/heads/main
```
Then add a workflow that builds the site and deploys it, on a push to
that branch only:
```yaml
# .knotless/workflows/site.yml
on:
push: {refs: [refs/heads/main]}
image: node:24
secrets: [SITE_PASSWORD]
steps:
- name: build
run: npm ci && npm run build
- uses: chadtmiller.com/steps/site@1
with: {dir: dist, fallback: index.html}
secrets: [SITE_PASSWORD]
```
The step's inputs are `dir`, the directory to deploy, and optionally
`fallback`, `not-found`, `repo` (this run's repository if not given) and
`appview`. Pin it before you push, and commit the lock file:
```sh
knotless uses update
git add .knotless/uses.lock
```
Each deploy records the commit it was built from. [Shared
steps](../reference/workflows.md#shared-steps) explains how `uses` works,
and [Workflows](workflows.md) how to run a runner and give it secrets.
## See what is live
With no directory, `knotless site` shows the live site: its address, how
many files it holds, the commit it was built from, and when it was
deployed:
```sh
knotless site knotless://alice.example.com/blog
```
There is no history of deploys. To roll back, deploy an older commit's
build again.
## Take a site down
```sh
knotless site knotless://alice.example.com/blog --down
```
This deletes the site's record, and the site stops being served.
docs/README.md+2−0
@@ -15,6 +15,8 @@ How to do things with knotless, a task at a time.
- [Running knotless-serve](guide/server.md): the cache, appview, gateway
and web pages.
- [Workflows](guide/workflows.md): run CI with `knotless-run`.
- [Sites](guide/sites.md): deploy a repository's website, a single-page
app or a 404 page, by hand or on every push.
## Reference
docs-site/astro.config.mjs+1−0
@@ -49,6 +49,7 @@ export default defineConfig({
page('Review agents', 'guide/reviews'),
page('Running knotless-serve', 'guide/server'),
page('Workflows', 'guide/workflows'),
page('Sites', 'guide/sites'),
],
},
{