Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,23 @@ If you consider to contribute to this project, please have a look on [CONTRIBUTI
The site is built with [Zensical](https://zensical.org), the successor to Material for
MkDocs. Run `task build` to build into `site/` and `task check` for the full check suite.

For previewing there are two tasks, and the difference matters:
For previewing there are two tasks:

| Task | Live reload | Shows the site as it ships |
| :--- | :---------- | :------------------------- |
| `task serve` | yes | **no** |
| `task preview` | no | yes |
| Task | Live reload | Shows |
| :--- | :---------- | :---- |
| `task serve` | yes | the pages as you write them |
| `task public:preview` | no | the site as it will be published |

`zensical serve` rebuilds into `site/` on every change, which would overwrite whatever the
post-build steps produce - so its preview has no tag listings and still loads `glightbox`
from a CDN. `task preview` builds once with every post-build step and serves the result on
port 8001 (override with `PORT=…`). Use `serve` while writing prose, `preview` before you
trust what you see.
Use `serve` while writing prose. It rebuilds into `site/` on every change, which overwrites
what the post-build steps produced, so it loads `glightbox` and the ResizeObserver polyfill
from a CDN instead of from the vendored copies - invisible on screen, and nothing
downstream trusts a `site/` left behind that way.

`task public:preview` is the one to run before publishing: it deploys into a throwaway copy
of the `published` branch, serves that on port 8002 (override with `PORT=…`), and deletes
the branch again when you stop it. Because it is `public:deploy` pointed at a scratch
branch, what it serves is what publishing produces - versioned URLs, the version selector,
the outdated-version banner and the root redirect included.

Two Material for MkDocs features are **not yet implemented by Zensical** and are
therefore missing from the output. They are tracked in `tools/check_zensical_output.py`,
Expand All @@ -45,10 +50,29 @@ check** - the build fails if any of it regresses:
| Feature | Replaced by |
| :------ | :---------- |
| Self-hosted fonts | `docs/assets/fonts.css` plus `theme.font: false` |
| `tablesort`, `glightbox` | vendored under `docs/assets/`; `tools/localize_bundle_assets.py` rewrites the CDN URLs Zensical bakes into its JS bundle |
| `tablesort`, `glightbox`, `resize-observer-polyfill` | vendored under `docs/assets/`; `tools/localize_bundle_assets.py` rewrites the CDN URLs Zensical bakes into its JS bundle |
| Redirects | static stubs under `docs/` |
| Comment opt-out | `overrides/partials/comments.html` |

### Vendored third-party assets

Serving these from our own origin is what keeps visitor IP addresses away from third
parties - but it also makes us their redistributor, so each copy carries its licence:

| Asset | Version | Licence | Upstream |
| :---- | :------ | :------ | :------- |
| `assets/glightbox/glightbox.min.{js,css}` | 3.3.1 | MIT, © 2018 Biati Digital | [glightbox](https://github.com/biati-digital/glightbox) |
| `assets/resize-observer-polyfill/ResizeObserver.global.js` | 1.5.1 | MIT, © 2016 Denis Rul | [resize-observer-polyfill](https://github.com/que-etc/resize-observer-polyfill) |
| `assets/tablesort.min.js` | 5.2.1 | MIT, © 2021 Tristen Brown | [tablesort](http://tristen.ca/tablesort/demo/) |
| `assets/fonts/*.woff2` | - | Apache-2.0 | Roboto and Roboto Mono via Google Fonts |

The files are byte-identical to their upstream builds except for a prepended `/*! … */`
licence banner, which is the notice MIT asks to travel with a copy; the full licence text
sits next to each one where upstream ships it. Three of the URLs Zensical bakes into its
bundle are deliberately **not** vendored - mermaid, Ace and Pyodide are unreachable for
this corpus, and `localize_bundle_assets.py` fails the build if a page ever starts using
one.

Tag listings and the links from each page's tag chips to them are **native** as of
Zensical 0.0.58. The local stand-ins for both - a post-build renderer and a `tags.html`
partial override - are gone; the Markdown sources still carry Material's own
Expand Down
84 changes: 68 additions & 16 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ dotenv: ['.env']

vars:
PUBLIC_BRANCH: published
# Throwaway branch used by public:preview. Never pushed, recreated on every
# run and deleted again when the preview server stops.
PREVIEW_BRANCH: publish-preview
CURRENT_VERSION: 26.2
# the markdown linter command, used by format:fix:path and check:rumdl
RUMDL_CHECK: poetry run rumdl --config .markdownlint.jsonc check
Expand Down Expand Up @@ -42,6 +45,9 @@ tasks:
run: once
cmds:
- rm -rf site
# Only ever the throwaway branch of public:preview, which normally deletes
# itself; this catches the run that was killed before it could.
- git branch -D {{.PREVIEW_BRANCH}} >/dev/null 2>&1 || true

install:
desc: Install needed dependencies
Expand Down Expand Up @@ -123,25 +129,19 @@ tasks:

serve:
desc: Serve the page on localhost with live reload (no post-build steps)
# `zensical serve` rebuilds into site/ on every change, which would overwrite
# anything the post-build steps in `build` produce. So this preview still
# loads glightbox from unpkg. Use `task preview` when you need to see the
# site exactly as it ships.
# `zensical serve` rebuilds into site/ on every change, which overwrites what
# the post-build steps in `build` produced - so this preview loads glightbox
# and the ResizeObserver polyfill from unpkg rather than from our vendored
# copies. Nothing downstream consumes a site/ left behind this way: `build`
# and `check:output` rebuild, and `public:deploy` refuses a site/ whose
# canonical URL is unversioned, which such a rebuild always is.
#
# Use `task public:preview` to see the site as it will actually be published.
deps:
- task: install
cmds:
- poetry run zensical serve

preview:
desc: Build with all post-build steps and serve the result (no live reload)
deps:
- task: build
vars:
PORT: '{{.PORT | default "8001"}}'
cmds:
- echo "Serving the fully built site on http://localhost:{{.PORT}} - Ctrl-C to stop"
- python3 -m http.server {{.PORT}} --directory site

update:icons:
desc: update the used eccenca icons from carbon
cmds:
Expand Down Expand Up @@ -264,12 +264,28 @@ tasks:

public:deploy:
desc: Publish the working directory as version {{.CURRENT_VERSION}}
summary: |
Builds the site and commits it as version {{.CURRENT_VERSION}} on the
{{.PUBLIC_BRANCH}} branch. Nothing is pushed - that stays a deliberate
`git push` afterwards.

Deliberately not `mike deploy`: that builds the site itself, without
`--strict` and without the post-build steps below, and its rebuild would
overwrite them anyway. So the build happens here and `dec-tool publish`
hands the result to mike, which still owns versions.json, the aliases and
the root redirect.

MIKE_DOCS_VERSION is what makes the pages carry a versioned canonical URL;
`dec-tool publish` refuses to commit a site/ built without it.
deps:
- task: install
cmds:
- MIKE_DOCS_VERSION={{.CURRENT_VERSION}} task build
- >
poetry run mike deploy -b {{.PUBLIC_BRANCH}}
--update-aliases {{.CURRENT_VERSION}} latest
poetry run dec-tool publish
--branch {{.PUBLIC_BRANCH}}
--version {{.CURRENT_VERSION}}
--alias latest

public:serve:
desc: Start a webserver to manually validate the public branch
Expand All @@ -278,6 +294,42 @@ tasks:
cmds:
- poetry run mike serve -b {{.PUBLIC_BRANCH}}

public:preview:
desc: Rehearse a deployment on a throwaway branch and serve it
summary: |
Deploys the working directory into a throwaway copy of the public branch,
serves it on localhost, and deletes that branch again when the server
stops. Nothing is pushed and {{.PUBLIC_BRANCH}} is never touched.

The rehearsal is public:deploy itself, pointed at the throwaway branch, so
what it serves is exactly what publishing would produce.

Ctrl-C removes the branch. Should the process be killed harder than that,
`task clean` removes it, as does the next run.

task public:preview PORT=9000
deps:
- task: install
vars:
PORT: '{{.PORT | default "8002"}}'
cmds:
# Deleted when the server stops: `defer` runs on Ctrl-C too, since that
# reaches mike and Task alike.
- defer: git branch -D {{.PREVIEW_BRANCH}} >/dev/null 2>&1 || true
# Start from the branch as it stands - locally if it exists, otherwise as
# last fetched - so the rehearsal shows the new version among the existing
# ones: version selector, outdated banner and root redirect included.
- |
base={{.PUBLIC_BRANCH}}
git show-ref --verify --quiet refs/heads/{{.PUBLIC_BRANCH}} \
|| base=origin/{{.PUBLIC_BRANCH}}
git branch -f --no-track {{.PREVIEW_BRANCH}} "$base"
- task: public:deploy
vars:
PUBLIC_BRANCH: "{{.PREVIEW_BRANCH}}"
- echo "Serving the deployment rehearsal on http://localhost:{{.PORT}} - Ctrl-C to stop and discard it"
- poetry run mike serve -b {{.PREVIEW_BRANCH}} --dev-addr localhost:{{.PORT}}

format:fix:path:
internal: true
summary: |
Expand Down
21 changes: 21 additions & 0 deletions docs/assets/glightbox/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Biati Digital https://www.biati.digital

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading