From ca1a4a31706d0c03673fe4c414c645ed826b21c6 Mon Sep 17 00:00:00 2001 From: shu Date: Wed, 19 Aug 2026 15:56:06 +0800 Subject: 精简 Wiki 构建与运行方式 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将浏览器端工具整理为 utilities 插件,移除 Docker、Org GTD 和 files API,并补充单文件构建及 Node.js 运行入口。 --- scripts/build.sh | 66 +++++++++++++++++++++ scripts/dev.sh | 3 - scripts/init-docker.sh | 157 ------------------------------------------------- scripts/run.sh | 16 ++++- 4 files changed, 80 insertions(+), 162 deletions(-) create mode 100755 scripts/build.sh delete mode 100755 scripts/dev.sh delete mode 100755 scripts/init-docker.sh (limited to 'scripts') diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..ac7651f --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +set -eu + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +PROJECT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd) +OUTPUT_DIR="$PROJECT_DIR/dist" +OUTPUT_FILE="$OUTPUT_DIR/tdwiki.html" +TIDDLYWIKI_BIN=${TIDDLYWIKI_BIN:-tiddlywiki} +BUILD_TMP_DIR= +BUILD_WIKI_DIR= + +cleanup() { + if [ -n "$BUILD_TMP_DIR" ] && [ -d "$BUILD_TMP_DIR" ]; then + rm -rf -- "$BUILD_TMP_DIR" + fi +} + +prepare_build_wiki() { + BUILD_TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/tdwiki-build.XXXXXX") + BUILD_WIKI_DIR="$BUILD_TMP_DIR/wiki" + mkdir -p "$BUILD_WIKI_DIR" + cp -R "$PROJECT_DIR/tiddlers" "$BUILD_WIKI_DIR/tiddlers" + cp -R "$PROJECT_DIR/plugins" "$BUILD_WIKI_DIR/plugins" + + node -e ' +const fs = require("fs"); +const source = process.argv[1]; +const destination = process.argv[2]; +const info = JSON.parse(fs.readFileSync(source,"utf8")); +const serverPlugins = new Set([ + "tiddlywiki/filesystem", + "tiddlywiki/tiddlyweb" +]); +info.plugins = (info.plugins || []).filter(name => !serverPlugins.has(name)); +fs.writeFileSync(destination,JSON.stringify(info,null,4) + "\n"); +' "$PROJECT_DIR/tiddlywiki.info" "$BUILD_WIKI_DIR/tiddlywiki.info" +} + +verify_output() { + node -e ' +const fs = require("fs"); +const filename = process.argv[1]; +const html = fs.readFileSync(filename,"utf8"); + +for(const title of ["$:/plugins/local/utilities"]) { + if(!html.includes(`"title":"${title}"`)) { + throw new Error(`single-file wiki is missing ${title}`); + } +} + +' "$OUTPUT_FILE" +} + +trap cleanup EXIT HUP INT TERM + +prepare_build_wiki +mkdir -p "$OUTPUT_DIR" + +"$TIDDLYWIKI_BIN" "$BUILD_WIKI_DIR" \ + --output "$OUTPUT_DIR" \ + --rendertiddler '$:/core/save/all' \ + tdwiki.html text/plain + +verify_output +printf 'Built %s\n' "$OUTPUT_FILE" diff --git a/scripts/dev.sh b/scripts/dev.sh deleted file mode 100755 index 7d43567..0000000 --- a/scripts/dev.sh +++ /dev/null @@ -1,3 +0,0 @@ -#/usr/bin/bash - -tiddlywiki . --listen port=10000 gzip=yes use-browser-cache=yes \ No newline at end of file diff --git a/scripts/init-docker.sh b/scripts/init-docker.sh deleted file mode 100755 index 4bae29b..0000000 --- a/scripts/init-docker.sh +++ /dev/null @@ -1,157 +0,0 @@ -#!/bin/sh - -set -eu - -SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) -PROJECT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd) -FORCE_USER=no - -if [ "${1:-}" = "--force-user" ]; then - FORCE_USER=yes -elif [ "$#" -gt 0 ]; then - printf 'Usage: %s [--force-user]\n' "$0" >&2 - exit 1 -fi - -if [ ! -f "$PROJECT_DIR/.env" ]; then - cp "$PROJECT_DIR/.env.example" "$PROJECT_DIR/.env" - printf 'Created .env from .env.example\n' -fi - -set -a -. "$PROJECT_DIR/.env" -set +a - -BASE_DOMAIN=${BASE_DOMAIN:-tdwiki.home.arpa} - -case "$BASE_DOMAIN" in - *[!a-zA-Z0-9.-]*|.*|*.) - printf 'Invalid BASE_DOMAIN: %s\n' "$BASE_DOMAIN" >&2 - exit 1 - ;; -esac - -mkdir -p \ - "$PROJECT_DIR/data/authelia" \ - "$PROJECT_DIR/data/caddy/data" \ - "$PROJECT_DIR/data/caddy/config" \ - "$PROJECT_DIR/secrets" - -chmod 700 "$PROJECT_DIR/secrets" - -generate_secret() { - file=$1 - bytes=$2 - if [ ! -s "$file" ]; then - umask 077 - openssl rand -hex "$bytes" > "$file" - printf 'Generated %s\n' "${file#"$PROJECT_DIR/"}" - fi -} - -generate_secret "$PROJECT_DIR/secrets/authelia_jwt_secret" 32 -generate_secret "$PROJECT_DIR/secrets/authelia_session_secret" 32 -generate_secret "$PROJECT_DIR/secrets/authelia_storage_encryption_key" 32 - -sed "s/__BASE_DOMAIN__/$BASE_DOMAIN/g" \ - "$PROJECT_DIR/docker/authelia/configuration.template.yml" \ - > "$PROJECT_DIR/docker/authelia/configuration.yml" - -USERS_FILE="$PROJECT_DIR/docker/authelia/users_database.yml" - -if [ ! -f "$USERS_FILE" ] || [ "$FORCE_USER" = yes ]; then - USERNAME=${AUTHELIA_USERNAME:-} - DISPLAY_NAME=${AUTHELIA_DISPLAY_NAME:-} - EMAIL=${AUTHELIA_EMAIL:-} - PASSWORD=${AUTHELIA_PASSWORD:-} - - if [ -z "$USERNAME" ]; then - printf 'Authelia username [admin]: ' - read -r USERNAME - USERNAME=${USERNAME:-admin} - fi - - case "$USERNAME" in - *[!a-zA-Z0-9_.-]*) - printf 'Username may only contain letters, digits, dot, underscore, and hyphen.\n' >&2 - exit 1 - ;; - esac - - if [ -z "$DISPLAY_NAME" ]; then - printf 'Display name [%s]: ' "$USERNAME" - read -r DISPLAY_NAME - DISPLAY_NAME=${DISPLAY_NAME:-$USERNAME} - fi - - if [ -z "$EMAIL" ]; then - printf 'Email [%s@%s]: ' "$USERNAME" "$BASE_DOMAIN" - read -r EMAIL - EMAIL=${EMAIL:-$USERNAME@$BASE_DOMAIN} - fi - - case "$DISPLAY_NAME$EMAIL" in - *'"'*|*'\'*) - printf 'Display name and email cannot contain quote or backslash characters.\n' >&2 - exit 1 - ;; - esac - - if [ -z "$PASSWORD" ]; then - if [ ! -t 0 ]; then - printf 'Set AUTHELIA_PASSWORD for non-interactive initialization.\n' >&2 - exit 1 - fi - printf 'Password: ' - stty -echo - read -r PASSWORD - stty echo - printf '\nConfirm password: ' - stty -echo - read -r PASSWORD_CONFIRM - stty echo - printf '\n' - if [ "$PASSWORD" != "$PASSWORD_CONFIRM" ]; then - printf 'Passwords do not match.\n' >&2 - exit 1 - fi - fi - - if [ "${#PASSWORD}" -lt 12 ]; then - printf 'Password must contain at least 12 characters.\n' >&2 - exit 1 - fi - - HASH_OUTPUT=$(docker run --rm authelia/authelia:4.39.20 \ - authelia crypto hash generate argon2 \ - --password "$PASSWORD" \ - --no-confirm) - PASSWORD_HASH=${HASH_OUTPUT#Digest: } - unset PASSWORD PASSWORD_CONFIRM HASH_OUTPUT - - escape_sed() { - printf '%s' "$1" | sed 's/[|&]/\\&/g' - } - - USERNAME_ESCAPED=$(escape_sed "$USERNAME") - DISPLAY_NAME_ESCAPED=$(escape_sed "$DISPLAY_NAME") - EMAIL_ESCAPED=$(escape_sed "$EMAIL") - PASSWORD_HASH_ESCAPED=$(escape_sed "$PASSWORD_HASH") - - sed \ - -e "s|__USERNAME__|$USERNAME_ESCAPED|g" \ - -e "s|__DISPLAY_NAME__|$DISPLAY_NAME_ESCAPED|g" \ - -e "s|__EMAIL__|$EMAIL_ESCAPED|g" \ - -e "s|__PASSWORD_HASH__|$PASSWORD_HASH_ESCAPED|g" \ - "$PROJECT_DIR/docker/authelia/users_database.template.yml" \ - > "$USERS_FILE" - chmod 600 "$USERS_FILE" - printf 'Created Authelia user %s\n' "$USERNAME" -fi - -docker compose --project-directory "$PROJECT_DIR" config --quiet - -printf '\nInitialization complete.\n' -printf 'Add wiki.%s, dav.%s, and auth.%s to local DNS, then run:\n' \ - "$BASE_DOMAIN" "$BASE_DOMAIN" "$BASE_DOMAIN" -printf ' docker compose up -d --build\n' diff --git a/scripts/run.sh b/scripts/run.sh index 9164aa6..8843f9f 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -1,3 +1,15 @@ -#/usr/bin/bash +#!/bin/sh -tiddlywiki . --listen port=10000 use-browser-cache=yes \ No newline at end of file +set -eu + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +PROJECT_DIR=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd) +TIDDLYWIKI_BIN=${TIDDLYWIKI_BIN:-tiddlywiki} +TDWIKI_LISTEN_HOST=${TDWIKI_LISTEN_HOST:-127.0.0.1} +TDWIKI_LISTEN_PORT=${TDWIKI_LISTEN_PORT:-10000} + +exec "$TIDDLYWIKI_BIN" "$PROJECT_DIR" --listen \ + host="$TDWIKI_LISTEN_HOST" \ + port="$TDWIKI_LISTEN_PORT" \ + gzip=yes \ + use-browser-cache=yes -- cgit v1.2.3