Add the clone engine, CLI, tests, CI, and docs
kage renders every page in headless Chrome, snapshots the final DOM, strips all JavaScript, and localises CSS, images, and fonts so a site can be browsed offline as a plain folder of files. The engine is split into small packages: urlx deterministic URL to local-path mapping and scope rules sanitize remove scripts, on* handlers, and javascript: URLs asset rewrite HTML and CSS references, download assets browser headless Chrome pool over the DevTools protocol robots robots.txt matcher clone the orchestrator: a polite resumable breadth-first crawl The cli package wires a cobra and fang command surface with two commands, clone and serve. Every pure package has table tests; the browser and clone packages add Chrome-driven end-to-end tests that skip when no browser is present or under -short. CI runs gofmt, vet, build, race tests, golangci-lint, govulncheck, and a tidy check on Linux and macOS. A goreleaser config fans one tag out to archives, deb/rpm/apk, a Chromium-bundled GHCR image, and the package managers. A tago docs site builds to Pages and Cloudflare.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: "kage"
|
||||
description: "kage (影, shadow) clones any website into a self-contained folder you can browse offline, with all the JavaScript stripped out. Render in headless Chrome, remove every script, localise the CSS, images, and fonts, from one pure-Go binary."
|
||||
heroTitle: "A website, frozen as a shadow"
|
||||
heroLead: "kage renders every page in headless Chrome, snapshots the final DOM, removes every script and event handler, and downloads and rewrites the CSS, images, and fonts. The result looks like the live site but runs no code: a plain folder of .html files you can open straight from disk."
|
||||
heroPrimaryURL: "/getting-started/quick-start/"
|
||||
heroPrimaryText: "Get started"
|
||||
---
|
||||
|
||||
Saving a page with "Save As" gives you a copy that still phones home, still runs
|
||||
analytics, and often renders blank because the markup is built by JavaScript at
|
||||
runtime. kage (影, "shadow") takes the opposite approach: it drives a real
|
||||
browser, captures the page the way a human would have seen it, then makes it
|
||||
inert.
|
||||
|
||||
```bash
|
||||
kage clone example.com
|
||||
kage serve kage-out/example.com
|
||||
```
|
||||
|
||||
## What it does
|
||||
|
||||
- **Renders first, saves second.** Each page goes through real headless Chrome,
|
||||
so a page whose content is assembled by JavaScript is captured fully, not as
|
||||
an empty shell.
|
||||
- **Strips every script.** Once the DOM is captured, kage removes all `<script>`
|
||||
tags, every `on*` event handler, and any `javascript:` URL. The saved page
|
||||
makes no network calls and runs no code.
|
||||
- **Keeps the layout.** Stylesheets, images, fonts, and media are downloaded and
|
||||
rewritten to relative local paths, so the offline copy looks like the original.
|
||||
- **Stays browsable.** In-scope links are rewritten to point at the other saved
|
||||
pages, so you can click around the mirror exactly as you would the live site.
|
||||
|
||||
## Where to go next
|
||||
|
||||
- New here? Start with the [introduction](/getting-started/introduction/), then
|
||||
the [quick start](/getting-started/quick-start/).
|
||||
- Want to install it? See [installation](/getting-started/installation/).
|
||||
- Looking for a specific task? The [guides](/guides/) cover scoping a crawl,
|
||||
serving a mirror, and resuming an interrupted run.
|
||||
- Need every flag? The [CLI reference](/reference/cli/) is the full surface.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: "Getting started"
|
||||
linkTitle: "Getting started"
|
||||
description: "Install kage and clone your first site into a browsable offline folder in under a minute."
|
||||
weight: 10
|
||||
featured: true
|
||||
---
|
||||
|
||||
Three short pages: how kage thinks about cloning a site (render, strip, localise),
|
||||
how to install the binary and point it at a browser, and a guided first run that
|
||||
ends with a real offline mirror you can click through.
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
title: "Installation"
|
||||
description: "Install kage from Go, Homebrew, a release archive, a Linux package, or the container image, and point it at a browser."
|
||||
weight: 20
|
||||
---
|
||||
|
||||
kage is a single binary. Pick whichever channel suits you.
|
||||
|
||||
## Go
|
||||
|
||||
```bash
|
||||
go install github.com/tamnd/kage/cmd/kage@latest
|
||||
```
|
||||
|
||||
## Homebrew
|
||||
|
||||
```bash
|
||||
brew install tamnd/tap/kage
|
||||
```
|
||||
|
||||
## Release archives and Linux packages
|
||||
|
||||
Every [release](https://github.com/tamnd/kage/releases) attaches `tar.gz`
|
||||
archives (and a `.zip` for Windows) for Linux, macOS, Windows, and FreeBSD, plus
|
||||
`.deb`, `.rpm`, and `.apk` packages and a `checksums.txt` with a cosign
|
||||
signature. Download the one for your platform, extract `kage`, and put it on your
|
||||
`PATH`.
|
||||
|
||||
```bash
|
||||
# Debian/Ubuntu
|
||||
sudo dpkg -i kage_*_linux_amd64.deb
|
||||
|
||||
# Fedora/RHEL
|
||||
sudo rpm -i kage_*_linux_amd64.rpm
|
||||
```
|
||||
|
||||
## Container
|
||||
|
||||
The image bundles Chromium, so it needs nothing else:
|
||||
|
||||
```bash
|
||||
docker run -v "$PWD/out:/out" ghcr.io/tamnd/kage clone example.com
|
||||
```
|
||||
|
||||
The mirror lands in `./out/example.com/` on your host.
|
||||
|
||||
## You need a browser
|
||||
|
||||
kage drives a real Chrome to render pages. Outside the container image, it needs
|
||||
Chrome or Chromium available on the machine. It looks for a system install
|
||||
automatically (Google Chrome on macOS and Windows, `google-chrome`/`chromium` on
|
||||
Linux). To use a specific binary:
|
||||
|
||||
```bash
|
||||
kage clone example.com --chrome /path/to/chromium
|
||||
# or
|
||||
export KAGE_CHROME=/path/to/chromium
|
||||
```
|
||||
|
||||
If no browser is found, kage's launcher can download a private copy of Chromium
|
||||
on first use.
|
||||
|
||||
Next: [the quick start](/getting-started/quick-start/).
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: "Introduction"
|
||||
description: "Why kage renders before it saves, and what it means to strip the JavaScript out of a clone."
|
||||
weight: 10
|
||||
---
|
||||
|
||||
A normal website is not a document; it is a program. The HTML the server sends
|
||||
is often a near-empty shell, and the page you actually see is assembled in your
|
||||
browser by JavaScript: fetching data, building the DOM, wiring up handlers. That
|
||||
is why "Save As" so often fails. You get the shell, not the page, and whatever
|
||||
you do get still runs trackers and phones home when you open it.
|
||||
|
||||
kage treats a clone as three steps in order.
|
||||
|
||||
## 1. Render
|
||||
|
||||
Every page is loaded in a real headless Chrome through the DevTools protocol.
|
||||
kage navigates to the URL, waits for the network to go quiet, optionally scrolls
|
||||
to trigger lazy-loaded images, and then serialises the **final** DOM, the markup
|
||||
that exists after the page's JavaScript has finished building it. This is the
|
||||
same thing you would see if you opened the page and chose "Inspect".
|
||||
|
||||
## 2. Strip
|
||||
|
||||
From that captured DOM, kage removes everything executable:
|
||||
|
||||
- every `<script>` tag, inline or external;
|
||||
- every `on*` event handler attribute (`onclick`, `onload`, and the rest);
|
||||
- every `javascript:` URL;
|
||||
- `<meta http-equiv="refresh">` redirects and dead resource hints like
|
||||
`<link rel="preload" as="script">`.
|
||||
|
||||
What remains is inert. The saved page makes no network calls, runs no code, and
|
||||
tracks nothing.
|
||||
|
||||
## 3. Localise
|
||||
|
||||
A page with no working CSS or images is not much of a clone, so kage keeps the
|
||||
parts that define how it looks. It downloads every stylesheet, image, font, and
|
||||
media file, rewrites the references in the HTML and inside the CSS (`url()` and
|
||||
`@import`) to relative local paths, and rewrites in-scope page links to point at
|
||||
the other saved pages. The mirror is fully self-contained: you can move the
|
||||
folder anywhere, open it with no network, and click around.
|
||||
|
||||
## The shape of a clone
|
||||
|
||||
kage crawls breadth-first from a seed URL, staying within the seed's host (and
|
||||
optionally its subdomains). It is polite by default: it honours `robots.txt` and
|
||||
seeds itself from `sitemap.xml`. Output lands in `kage-out/<host>/`, with pages
|
||||
as `<path>/index.html` and assets under a reserved `_kage/` directory alongside
|
||||
the crawl state that powers `--resume`.
|
||||
|
||||
Next: [install kage](/getting-started/installation/).
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Quick start"
|
||||
description: "From an empty terminal to a self-contained offline mirror you can click through."
|
||||
weight: 30
|
||||
---
|
||||
|
||||
This walks the core loop: clone a small site, look at what landed on disk, and
|
||||
serve it back so links and assets resolve the way they would on a real host.
|
||||
|
||||
## 1. Clone a site
|
||||
|
||||
```bash
|
||||
kage clone example.com
|
||||
```
|
||||
|
||||
kage launches headless Chrome, renders the home page, strips its scripts, and
|
||||
follows in-scope links breadth-first. A live counter shows pages, assets, and
|
||||
errors as it goes; the final summary tells you where the mirror landed.
|
||||
|
||||
```
|
||||
kage cloning https://example.com
|
||||
done kage-out/example.com
|
||||
pages 12 assets 38
|
||||
open kage serve kage-out/example.com
|
||||
```
|
||||
|
||||
## 2. Look at what landed
|
||||
|
||||
```bash
|
||||
ls kage-out/example.com
|
||||
```
|
||||
|
||||
```
|
||||
index.html # the home page, scripts stripped
|
||||
about/index.html # /about
|
||||
_kage/ # localised assets and crawl state
|
||||
```
|
||||
|
||||
Open `index.html` directly in a browser and it renders offline, with no network.
|
||||
Grep it and you will find no `<script>`, no `onclick`, no `javascript:`.
|
||||
|
||||
## 3. Serve it back
|
||||
|
||||
Opening files directly works, but some sites use root-relative links. `kage
|
||||
serve` runs a local static server so everything resolves exactly as it would
|
||||
live:
|
||||
|
||||
```bash
|
||||
kage serve kage-out/example.com
|
||||
# open http://127.0.0.1:8800
|
||||
```
|
||||
|
||||
## 4. Scope a bigger crawl
|
||||
|
||||
For a large site, bound the crawl so it does not run away:
|
||||
|
||||
```bash
|
||||
# Just the docs section, three levels deep, at most 200 pages
|
||||
kage clone example.com --scope-prefix /docs --max-depth 3 --max-pages 200
|
||||
```
|
||||
|
||||
If you stop a run with Ctrl-C, kage saves its state. Run the same command again
|
||||
and it resumes, skipping the pages it already wrote.
|
||||
|
||||
## Where to go next
|
||||
|
||||
- The [guides](/guides/) cover scoping, serving, and resuming in depth.
|
||||
- The [CLI reference](/reference/cli/) lists every flag.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: "Guides"
|
||||
linkTitle: "Guides"
|
||||
description: "Task-oriented walkthroughs for the things people actually do with kage: scoping a crawl, serving a mirror, and resuming a run."
|
||||
weight: 20
|
||||
featured: true
|
||||
---
|
||||
|
||||
Each guide is built around a job rather than a flag: keeping a crawl inside the
|
||||
lines, viewing what you cloned, and picking up an interrupted run. They assume
|
||||
you have worked through the [quick start](/getting-started/quick-start/).
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: "Resuming a run"
|
||||
description: "Pick up an interrupted clone where it left off, and start fresh when you want to."
|
||||
weight: 30
|
||||
---
|
||||
|
||||
Cloning a large site can take a while, and runs get interrupted: you press
|
||||
Ctrl-C, your laptop sleeps, the network drops. kage is built to pick up where it
|
||||
left off.
|
||||
|
||||
## How resume works
|
||||
|
||||
As it writes each page, kage records it in a small state file inside the mirror,
|
||||
at `<host>/_kage/state.json`. When a run ends, for any reason, that file holds
|
||||
the set of pages already written. Resume is **on by default**: the next time you
|
||||
run the same clone, kage loads the state and skips every page it already wrote,
|
||||
re-crawling only what is left.
|
||||
|
||||
```bash
|
||||
kage clone example.com
|
||||
# ... press Ctrl-C partway through ...
|
||||
# interrupted; resume state saved (rerun to continue)
|
||||
|
||||
kage clone example.com
|
||||
# resume: 137 pages already done
|
||||
```
|
||||
|
||||
Ctrl-C is a clean stop: kage cancels in-flight renders, flushes the state file,
|
||||
and exits. You will not lose the pages already written.
|
||||
|
||||
## Start fresh
|
||||
|
||||
To ignore any previous run and rebuild the mirror from scratch, delete the
|
||||
existing host folder first with `--force`:
|
||||
|
||||
```bash
|
||||
kage clone example.com --force
|
||||
```
|
||||
|
||||
This removes `kage-out/example.com/` before crawling, so nothing from a prior run
|
||||
carries over.
|
||||
|
||||
To run without reading or writing any resume state at all, for a strictly
|
||||
one-shot clone, use `--no-resume`:
|
||||
|
||||
```bash
|
||||
kage clone example.com --no-resume
|
||||
```
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
title: "Scoping a crawl"
|
||||
description: "Keep a clone inside the lines with depth, page, prefix, subdomain, and exclude controls."
|
||||
weight: 10
|
||||
---
|
||||
|
||||
By default kage crawls every in-scope page it can reach from the seed, staying on
|
||||
the seed's host. On a large site that can be a lot of pages. These flags bound
|
||||
the crawl.
|
||||
|
||||
## Limit by count and depth
|
||||
|
||||
```bash
|
||||
# Stop after 200 pages
|
||||
kage clone example.com --max-pages 200
|
||||
|
||||
# Only follow links three hops from the seed
|
||||
kage clone example.com --max-depth 3
|
||||
```
|
||||
|
||||
`--max-depth 0` (the default) means unlimited depth; `--max-pages 0` means
|
||||
unlimited pages. Combine them to put a hard ceiling on a run.
|
||||
|
||||
## Limit by path
|
||||
|
||||
To clone just one section of a site, restrict the crawl to a path prefix:
|
||||
|
||||
```bash
|
||||
kage clone example.com --scope-prefix /docs
|
||||
```
|
||||
|
||||
Only pages whose path starts with `/docs` are followed. Assets are still fetched
|
||||
from wherever the page references them, so the section renders correctly.
|
||||
|
||||
To skip parts of a site, exclude path prefixes (repeatable):
|
||||
|
||||
```bash
|
||||
kage clone example.com --exclude /archive --exclude /tags
|
||||
```
|
||||
|
||||
## Subdomains
|
||||
|
||||
By default a clone stays on the exact seed host. To treat subdomains of the seed
|
||||
as in scope, add `--subdomains`:
|
||||
|
||||
```bash
|
||||
kage clone example.com --subdomains
|
||||
```
|
||||
|
||||
Now `blog.example.com` and `docs.example.com` are crawled too, each landing
|
||||
under its own host directory inside the mirror.
|
||||
|
||||
## Politeness
|
||||
|
||||
kage honours `robots.txt` by default and seeds itself from `sitemap.xml`. If you
|
||||
are cloning a site you control, or you have a reason to ignore the robots rules,
|
||||
you can turn them off, but do so responsibly:
|
||||
|
||||
```bash
|
||||
kage clone example.com --no-robots --no-sitemap
|
||||
```
|
||||
|
||||
## Lazy-loaded media
|
||||
|
||||
Sites that load images as you scroll will only have their above-the-fold images
|
||||
captured unless you tell kage to scroll each page:
|
||||
|
||||
```bash
|
||||
kage clone example.com --scroll
|
||||
```
|
||||
|
||||
This makes each render a little slower but captures media that only loads on
|
||||
view.
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: "Serving a mirror"
|
||||
description: "View a cloned folder the way it would render on a real host, with kage serve."
|
||||
weight: 20
|
||||
---
|
||||
|
||||
A clone is a plain folder of files, so the simplest way to view it is to open an
|
||||
`.html` file in your browser. That works for many sites. But some pages use
|
||||
root-relative URLs (`/style.css`, `/img/logo.png`), which only resolve correctly
|
||||
when served from the root of a host. `kage serve` gives you that root.
|
||||
|
||||
## Serve a clone
|
||||
|
||||
```bash
|
||||
kage serve kage-out/example.com
|
||||
```
|
||||
|
||||
```
|
||||
kage serve /…/kage-out/example.com
|
||||
open http://127.0.0.1:8800
|
||||
press Ctrl-C to stop
|
||||
```
|
||||
|
||||
Open the printed URL and click around the mirror exactly as you would the live
|
||||
site. Every in-scope link kage rewrote points at another saved page; every asset
|
||||
resolves to its localised copy.
|
||||
|
||||
## Choose an address
|
||||
|
||||
By default kage serves on `127.0.0.1:8800`. Change it with `--addr`:
|
||||
|
||||
```bash
|
||||
# A different port
|
||||
kage serve kage-out/example.com --addr 127.0.0.1:9000
|
||||
|
||||
# Reachable from other machines on your network (be deliberate about this)
|
||||
kage serve kage-out/example.com --addr 0.0.0.0:8800
|
||||
```
|
||||
|
||||
## Serve the current directory
|
||||
|
||||
With no argument, `kage serve` serves the current directory, which is handy from
|
||||
inside an output folder:
|
||||
|
||||
```bash
|
||||
cd kage-out/example.com
|
||||
kage serve
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: "Reference"
|
||||
linkTitle: "Reference"
|
||||
description: "The complete kage surface: every command, every flag, and every environment variable."
|
||||
weight: 30
|
||||
featured: true
|
||||
---
|
||||
|
||||
The exhaustive reference. The [CLI](/reference/cli/) page lists every command and
|
||||
flag; the [configuration](/reference/configuration/) page covers environment
|
||||
variables and the output layout on disk.
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
title: "CLI reference"
|
||||
description: "Every kage command and flag."
|
||||
weight: 10
|
||||
---
|
||||
|
||||
```
|
||||
kage [command] [flags]
|
||||
```
|
||||
|
||||
Two commands: `clone` fetches a site into an offline folder, `serve` previews
|
||||
one. Run `kage <command> --help` for the canonical, up-to-date list.
|
||||
|
||||
## kage clone
|
||||
|
||||
```
|
||||
kage clone <url> [flags]
|
||||
```
|
||||
|
||||
Renders each page in headless Chrome, strips all JavaScript, localises CSS,
|
||||
images, and fonts, and writes a browsable mirror to `<out>/<host>/`.
|
||||
|
||||
### Output
|
||||
|
||||
| Flag | Default | Meaning |
|
||||
|------|---------|---------|
|
||||
| `-o, --out` | `kage-out` | Output root; the mirror lands in `<out>/<host>/` |
|
||||
| `--reserved` | `_kage` | Reserved directory name for assets and crawl state |
|
||||
| `-f, --force` | `false` | Delete any existing mirror for the host before crawling |
|
||||
| `--no-resume` | `false` | Do not read or write resume state |
|
||||
|
||||
### Scope
|
||||
|
||||
| Flag | Default | Meaning |
|
||||
|------|---------|---------|
|
||||
| `-p, --max-pages` | `0` | Stop after N pages (0 = unlimited) |
|
||||
| `-d, --max-depth` | `0` | Link-follow depth cap (0 = unlimited) |
|
||||
| `--scope-prefix` | | Only crawl pages whose path starts with this prefix |
|
||||
| `--subdomains` | `false` | Treat subdomains of the seed host as in scope |
|
||||
| `--exclude` | | Path prefixes to skip (repeatable) |
|
||||
| `--traversal` | `bfs` | Frontier order: `bfs` or `dfs` |
|
||||
|
||||
### Politeness
|
||||
|
||||
| Flag | Default | Meaning |
|
||||
|------|---------|---------|
|
||||
| `--no-robots` | `false` | Ignore `robots.txt` |
|
||||
| `--no-sitemap` | `false` | Do not seed URLs from `sitemap.xml` |
|
||||
| `--user-agent` | Chrome UA | User-Agent for asset and robots fetches |
|
||||
|
||||
### Rendering
|
||||
|
||||
| Flag | Default | Meaning |
|
||||
|------|---------|---------|
|
||||
| `--scroll` | `false` | Auto-scroll each page to trigger lazy loading |
|
||||
| `--settle` | `1.5s` | Network-idle quiet period before snapshotting the DOM |
|
||||
| `--render-timeout` | `30s` | Hard cap per page render |
|
||||
| `--headful` | `false` | Run Chrome with a visible window (debugging) |
|
||||
| `--chrome` | | Path to the Chrome/Chromium binary |
|
||||
| `--control-url` | | Attach to an existing Chrome DevTools endpoint |
|
||||
| `--keep-noscript` | `false` | Unwrap `<noscript>` content instead of dropping it |
|
||||
|
||||
### Concurrency and limits
|
||||
|
||||
| Flag | Default | Meaning |
|
||||
|------|---------|---------|
|
||||
| `--workers` | `4` | Concurrent page render workers |
|
||||
| `--asset-workers` | `8` | Concurrent asset download workers |
|
||||
| `--browser-pages` | `4` | Chrome page-pool size |
|
||||
| `--max-asset-mb` | `25` | Skip assets larger than N MB |
|
||||
| `--timeout` | `30s` | Per-request timeout |
|
||||
| `-q, --quiet` | `false` | Suppress per-page progress lines |
|
||||
|
||||
## kage serve
|
||||
|
||||
```
|
||||
kage serve [dir] [flags]
|
||||
```
|
||||
|
||||
Runs a local static file server over a cloned folder. With no `dir`, serves the
|
||||
current directory.
|
||||
|
||||
| Flag | Default | Meaning |
|
||||
|------|---------|---------|
|
||||
| `-a, --addr` | `127.0.0.1:8800` | Address to listen on |
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: "Configuration"
|
||||
description: "Environment variables kage reads, and the layout of a cloned mirror on disk."
|
||||
weight: 20
|
||||
---
|
||||
|
||||
kage is configured almost entirely through command-line flags (see the
|
||||
[CLI reference](/reference/cli/)). It reads a couple of environment variables for
|
||||
locating the browser.
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variable | Meaning |
|
||||
|----------|---------|
|
||||
| `KAGE_CHROME` | Path to the Chrome/Chromium binary. Takes precedence over autodetection. Equivalent to `--chrome`. |
|
||||
| `CHROME_BIN` | Fallback Chrome path, read if `KAGE_CHROME` is unset. |
|
||||
|
||||
If neither is set and no system Chrome is found in the usual install locations,
|
||||
kage's launcher can download a private copy of Chromium on first use.
|
||||
|
||||
## Output layout
|
||||
|
||||
A clone of `example.com` lands under `kage-out/example.com/`:
|
||||
|
||||
```
|
||||
kage-out/example.com/
|
||||
├── index.html # the home page (/), scripts stripped
|
||||
├── about/index.html # /about
|
||||
├── blog/
|
||||
│ ├── index.html # /blog
|
||||
│ └── a-post/index.html # /blog/a-post
|
||||
├── _kage/ # reserved directory
|
||||
│ ├── example.com/
|
||||
│ │ ├── site.css # localised stylesheet, url() rewritten
|
||||
│ │ ├── logo.png
|
||||
│ │ └── fonts/body.woff2
|
||||
│ ├── cdn.example.com/ # assets from other hosts, by host
|
||||
│ └── state.json # visited set, for --resume
|
||||
└── ...
|
||||
```
|
||||
|
||||
Key points:
|
||||
|
||||
- **Pages become directories.** A page at `/about` is written as
|
||||
`about/index.html`, so a link to `/about` resolves to a real file when served.
|
||||
- **Assets live under the reserved directory.** Everything kage downloads, CSS,
|
||||
images, fonts, media, goes under `_kage/<asset-host>/`, mirroring the path it
|
||||
had on its origin. Cross-origin assets are grouped by their own host.
|
||||
- **Query strings are folded into the filename.** An asset like
|
||||
`style.css?v=3` is saved with a short hash suffix so two versions never
|
||||
collide.
|
||||
- **State lives in the mirror.** `_kage/state.json` records every page written,
|
||||
which is what makes `--resume` able to skip completed work. Rename the reserved
|
||||
directory with `--reserved` if `_kage` would clash with a real path on the site.
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><rect width="16" height="16" rx="3" fill="#0b6e4f"/><path fill="#f6f8fa" d="M7 2.5a4.5 4.5 0 1 0 2.62 8.15l2.36 2.37a.75.75 0 1 0 1.06-1.06l-2.37-2.36A4.5 4.5 0 0 0 7 2.5Zm-3 4.5a3 3 0 1 1 6 0 3 3 0 0 1-6 0Z"/></svg>
|
||||
|
After Width: | Height: | Size: 300 B |
@@ -0,0 +1,10 @@
|
||||
title = "kage"
|
||||
baseURL = "https://kage.tamnd.com/"
|
||||
description = "kage (影, shadow) clones any website into a self-contained folder you can browse offline, with all the JavaScript stripped out. It renders every page in headless Chrome, removes every script, and localises the CSS, images, and fonts."
|
||||
contentDir = "content"
|
||||
outputDir = "public"
|
||||
theme = "tago-doks"
|
||||
syntaxHighlight = "true"
|
||||
|
||||
[params]
|
||||
github = "https://github.com/tamnd/kage"
|
||||
Reference in New Issue
Block a user