12 KiB
Building & Testing
For internal architecture/workflow guidance, use docs/README.md at the repo root. This page stays focused on contributor-facing build and test commands.
Prerequisites
- Required for all contributor workflows:
- Bun
gitwith submodule support
- Required by commands used on this page:
bashfor helper scripts such asmake dev-watch,bun run format:check:src, andbash scripts/verify-generated-launcher.shunzipon macOS/Linux for the bundled Yomitan build step insidebun run buildluafor plugin/environment test lanes such asbun run test:envandbun run test:launcher
- Platform-specific / conditional:
swiftcon macOS is optional. If absent, the build falls back to staging the Swift helper source instead of compiling the helper binary.- Windows uses
powershell.exeduring the bundled Yomitan extraction step. A normal Windows install already provides it.
Setup
git clone --recurse-submodules https://github.com/ksyasuda/SubMiner.git
cd SubMiner
# if you cloned without --recurse-submodules:
git submodule update --init --recursive
bun install
(cd stats && bun install --frozen-lockfile)
(cd vendor/texthooker-ui && bun install --frozen-lockfile)
make deps is still available as a convenience wrapper around the same dependency install flow.
If you only need the default TypeScript/unit lanes, Bun plus the checked-in dependencies is enough after install. The extra tools above are only needed when you run the commands that invoke them.
Building
# Main app build
bun run build
# Platform packages
bun run build:appimage # Linux AppImage
bun run build:mac # macOS DMG + ZIP (signed)
bun run build:mac:unsigned # macOS DMG + ZIP (unsigned)
bun run build:win # Windows NSIS installer + ZIP
# Optional launcher artifact only
make build-launcher
# output: dist/launcher/subminer
bun run build includes the Yomitan build step. It builds the bundled Chrome extension directly from the vendor/subminer-yomitan submodule into build/yomitan using Bun.
On macOS/Linux, that build also shells out to unzip while extracting the Yomitan artifact. On macOS, the asset staging step will compile the helper with swiftc when available, then fall back to copying the .swift source if not.
Launcher Artifact Workflow
- Source of truth:
launcher/*.ts - Generated output:
dist/launcher/subminer - Do not hand-edit generated launcher output.
- Repo-root
./submineris a stale artifact path and is rejected by verification checks. - Install targets (
make install-linux,make install-macos) copy fromdist/launcher/subminer.
Verify the workflow:
make build-launcher
dist/launcher/subminer --help >/dev/null
bash scripts/verify-generated-launcher.sh
Running Locally
bun run dev # builds + launches with --start --dev
bun run electron . --start --dev --log-level debug # equivalent Electron launch with verbose logging
bun run electron . --background # tray/background mode, minimal default logging
make dev-start # build + launch via Makefile
make dev-watch # watch TS + renderer and launch Electron (faster edit loop)
make dev-watch-macos # same as dev-watch, forcing --backend macos
For mpv-plugin-driven testing without exporting SUBMINER_BINARY_PATH each run, set a one-time
dev binary path in ~/.config/mpv/script-opts/subminer.conf:
binary_path=/absolute/path/to/SubMiner/scripts/subminer-dev.sh
Testing
Default lanes:
bun run test # alias for test:fast
bun run test:fast # default fast lane
bun run test:full # maintained source + launcher-unit + runtime compat surface
bun run test:runtime:compat # compiled/runtime compatibility slice only
bun run test:env # launcher/plugin + env-sensitive verification
bun run test:immersion:sqlite # SQLite persistence lane
bun run test:subtitle # maintained alass/ffsubsync subtitle surface
bun run testandbun run test:fastcover config/core suites plus representative entry/runtime, Anki integration, release-workflow coverage, typecheck, and runtime-registry checks.bun run test:fullis the maintained full surface: Bun-compatiblesrc/**discovery, Bun-compatible launcher unit discovery, and the compiled/runtime compatibility lane for suites routed throughdist/**.bun run test:runtime:compatcovers the compiled/runtime slice directly:ipc,anki-jimaku-ipc,overlay-manager,config-validation,startup-config, andregistry.bun run test:envcovers environment-sensitive checks: launcher smoke/plugin verification plus the Bun source SQLite lane.bun run test:immersion:sqliteis the reproducible persistence lane when you need real DB-backed SQLite coverage under Bun.
Command-specific test deps:
bun run test:envandbun run test:launcherinvoke Lua-based plugin checks, soluamust be installed.bun run format:srcandbun run format:check:srcinvokebash scripts/prettier-scope.sh.
The Bun-managed discovery lanes intentionally exclude a small compiled/runtime-focused set: src/core/services/ipc.test.ts, src/core/services/anki-jimaku-ipc.test.ts, src/core/services/overlay-manager.test.ts, src/main/config-validation.test.ts, src/main/runtime/startup-config.test.ts, and src/main/runtime/registry.test.ts. bun run test:runtime:compat keeps them in the standard workflow via dist/**.
Suggested local gate before handoff:
bun run typecheck
bun run test:fast
bun run test:env
bun run build
bun run test:smoke:dist
If you changed docs in docs-site/, also run:
bun run docs:test
bun run docs:build
Focused commands:
bun run test:config # Source-level config schema/validation tests
bun run test:launcher # Launcher regression tests (config discovery + command routing)
bun run test:core # Source-level core regression tests (default lane)
bun run test:launcher:smoke:src # Launcher e2e smoke: launcher -> mpv IPC -> overlay start/stop wiring
bun run test:launcher:env:src # Launcher smoke + Lua plugin gate
bun run test:src # Bun-managed maintained src/** discovery lane
bun run test:launcher:unit:src # Bun-managed maintained launcher unit lane
bun run test:immersion:sqlite:src # Bun source lane
Dist-level tests are now an explicit smoke lane used to validate compiled/runtime assumptions.
Launcher smoke artifacts are written to .tmp/launcher-smoke locally and uploaded by CI/release workflows when the smoke step fails.
Smoke and optional deep dist commands:
bun run build # compile dist artifacts
bun run test:immersion:sqlite # compile + run SQLite-backed immersion tests under Bun
bun run test:smoke:dist # explicit smoke scope for compiled runtime
bun run test:config:dist # optional full dist config suite
bun run test:core:dist # optional full dist core suite
Use bun run test:immersion:sqlite when you need real DB-backed coverage for the immersion tracker.
Formatting
Use the scoped formatter for normal app-repo work:
make pretty
bun run format:check:src
make prettyruns the maintained Prettier allowlist only (format:src).bun run format:check:srcchecks the same scoped set without writing changes.bun run formatremains the broad repo-wide Prettier command; use it intentionally.
Config Generation
# Generate default config to ~/.config/SubMiner/config.jsonc (or %APPDATA%\SubMiner\config.jsonc on Windows)
bun run electron . --generate-config
# Regenerate the repo's config.example.jsonc from centralized defaults
bun run generate:config-example
Convenience wrappers still exist:
make generate-configmake generate-example-config
Documentation Site
The docs site now lives in docs-site/ inside the main repo.
From the SubMiner app repo:
bun --cwd docs-site install
bun run docs:dev # Dev server at http://localhost:5173
bun run docs:build # Production build into docs-site/.vitepress/dist
bun run docs:preview # Preview built site at http://localhost:4173
bun run docs:test # Docs regression tests
Cloudflare Pages deploy settings:
- Git repo:
ksyasuda/SubMiner - Root directory:
docs-site - Build command:
bun run docs:build - Build output directory:
.vitepress/dist - Build watch paths:
docs-site/*
Use Cloudflare's single * wildcard syntax for watch paths. docs-site/* covers nested docs-site changes in the repo; docs-site/** is not the correct Pages pattern and may skip docs-only pushes.
Makefile Reference
Run make help for a full list of targets. Key ones:
| Target | Description |
|---|---|
make build |
Build platform package for detected OS |
make build-launcher |
Generate Bun launcher wrapper at dist/launcher/subminer |
make install |
Install platform artifacts (wrapper, theme, AppImage/app bundle) |
make install-plugin |
Install mpv Lua plugin and config |
make deps |
Install JS dependencies (root + stats + texthooker-ui) |
make pretty |
Run scoped Prettier formatting for maintained source/config files |
make generate-config |
Generate default config from centralized registry |
make build-linux |
Convenience wrapper for Linux packaging |
make build-macos |
Convenience wrapper for signed macOS packaging |
make build-macos-unsigned |
Convenience wrapper for unsigned macOS packaging |
Contributor Notes
- To add/change a config default, edit the matching domain file in
src/config/definitions/defaults-*.ts. - To add/change config option metadata, edit the matching domain file in
src/config/definitions/options-*.ts. - To add/change generated config template blocks/comments, update
src/config/definitions/template-sections.ts. - Keep
src/config/definitions.tsas the composed public API (DEFAULT_CONFIG, registries, template export) that wires domain modules together. - Overlay window/visibility state is owned by
src/core/services/overlay-manager.ts. - Runtime architecture/module-boundary conventions are summarized in Architecture, with canonical internal guidance in
docs/architecture/README.mdat the repo root. - Linux packaged desktop launches pass
--backgroundusing electron-builderbuild.linux.executableArgsinpackage.json. - Prefer direct inline deps objects in
src/main/modules for simple pass-through wiring. - Add a helper/adapter service only when it performs meaningful adaptation, validation, or reuse (not identity mapping).
Environment Variables
| Variable | Description |
|---|---|
SUBMINER_APPIMAGE_PATH |
Override SubMiner app binary path for launcher playback commands |
SUBMINER_BINARY_PATH |
Alias for SUBMINER_APPIMAGE_PATH |
SUBMINER_ROFI_THEME |
Override rofi theme path for launcher picker |
SUBMINER_LOG_LEVEL |
Override app logger level (debug, info, warn, error) |
SUBMINER_MPV_LOG |
Override mpv/app shared log file path |
SUBMINER_JIMAKU_API_KEY |
Override Jimaku API key for launcher subtitle downloads |
SUBMINER_JIMAKU_API_KEY_COMMAND |
Command used to resolve Jimaku API key at runtime |
SUBMINER_JIMAKU_API_BASE_URL |
Override Jimaku API base URL |
SUBMINER_JELLYFIN_ACCESS_TOKEN |
Override Jellyfin access token (used before stored encrypted session fallback) |
SUBMINER_JELLYFIN_USER_ID |
Optional Jellyfin user ID override |
SUBMINER_SKIP_MACOS_HELPER_BUILD |
Set to 1 to skip building the macOS helper binary during bun run build |