diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c158c53d..a42f18e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,11 +21,6 @@ jobs: with: bun-version: 1.3.5 - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 22.12.0 - - name: Cache dependencies uses: actions/cache@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a47a7299..239de008 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,11 +27,6 @@ jobs: with: bun-version: 1.3.5 - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 22.12.0 - - name: Cache dependencies uses: actions/cache@v4 with: @@ -86,11 +81,6 @@ jobs: with: bun-version: 1.3.5 - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 22.12.0 - - name: Cache dependencies uses: actions/cache@v4 with: @@ -148,11 +138,6 @@ jobs: with: bun-version: 1.3.5 - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 22.12.0 - - name: Cache dependencies uses: actions/cache@v4 with: @@ -226,11 +211,6 @@ jobs: with: bun-version: 1.3.5 - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 22.12.0 - - name: Cache dependencies uses: actions/cache@v4 with: diff --git a/README.md b/README.md index c7561e00..5ce59461 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ chmod +x ~/.local/bin/subminer **Windows (Installer/ZIP):** download the latest `SubMiner-.exe` installer or portable `.zip` from [GitHub Releases](https://github.com/ksyasuda/SubMiner/releases/latest). Keep `mpv` installed and available on `PATH`. -**From source** — initialize submodules first (`git submodule update --init --recursive`). Source builds now also require Node.js 22 + npm because bundled Yomitan is built from the `vendor/subminer-yomitan` submodule into `build/yomitan` during `bun run build`. Full install guide: [docs.subminer.moe/installation#from-source](https://docs.subminer.moe/installation#from-source). +**From source** — initialize submodules first (`git submodule update --init --recursive`). Bundled Yomitan is built from the `vendor/subminer-yomitan` submodule into `build/yomitan` during `bun run build`, so source builds only need Bun for the JS toolchain. Packaged macOS and Windows installs do not require Bun. Full install guide: [docs.subminer.moe/installation#from-source](https://docs.subminer.moe/installation#from-source). ### 2. Launch the app once @@ -101,7 +101,7 @@ subminer --start video.mkv # optional explicit overlay start when plugin auto_st | Required | Optional | | ------------------------------------------ | -------------------------------------------------- | -| `bun`, `node` 22, `npm` | | +| `bun` (source builds, Linux `subminer`) | | | `mpv` with IPC socket | `yt-dlp` | | `ffmpeg` | `guessit` (better AniSkip title/episode detection) | | `mecab` + `mecab-ipadic` | `fzf` / `rofi` | @@ -117,13 +117,13 @@ For full guides on configuration, Anki, Jellyfin, and more, see [docs.subminer.m ## Testing - Run `bun run test` or `bun run test:fast` for the default fast lane: config/core coverage plus representative entry/runtime, Anki integration, and main runtime checks. -- Run `bun run test:full` for the maintained test surface: Bun-compatible `src/**` coverage, Bun-compatible launcher unit coverage, and a Node compatibility lane for suites that depend on Electron named exports or `node:sqlite` behavior. -- Run `bun run test:node:compat` directly when you only need the Node-backed compatibility slice: `ipc`, `anki-jimaku-ipc`, `overlay-manager`, `config-validation`, `startup-config`, and runtime registry coverage. +- Run `bun run test:full` for the maintained test surface: Bun-compatible `src/**` coverage, Bun-compatible launcher unit coverage, and the maintained dist compatibility slice for `ipc`, `anki-jimaku-ipc`, `overlay-manager`, `config-validation`, `startup-config`, and runtime registry coverage. +- Run `bun run test:node:compat` directly when you only need that dist compatibility slice. The command name is legacy; it now runs under Bun. - Run `bun run test:env` for environment-specific verification: launcher smoke/plugin checks plus the SQLite-backed immersion tracker lane. -- Run `bun run test:immersion:sqlite` when you specifically need real SQLite persistence coverage under Node with `--experimental-sqlite`. +- Run `bun run test:immersion:sqlite` when you specifically need the dist SQLite persistence coverage. - Run `bun run test:subtitle` for the maintained `alass`/`ffsubsync` subtitle surface. -The Bun-managed discovery lanes intentionally exclude a small set of suites that are currently Node-only because of Bun runtime/tooling gaps rather than product behavior: Electron named-export tests in `src/core/services/ipc.test.ts`, `src/core/services/anki-jimaku-ipc.test.ts`, and `src/core/services/overlay-manager.test.ts`, plus runtime/config tests in `src/main/config-validation.test.ts`, `src/main/runtime/startup-config.test.ts`, and `src/main/runtime/registry.test.ts`. `bun run test:node:compat` keeps those suites in the standard workflow instead of leaving them untracked. +The Bun-managed discovery lanes intentionally exclude a small set of suites from the source-file discovery pass and keep them in the maintained dist compatibility slice instead: Electron-focused tests in `src/core/services/ipc.test.ts`, `src/core/services/anki-jimaku-ipc.test.ts`, and `src/core/services/overlay-manager.test.ts`, plus runtime/config tests in `src/main/config-validation.test.ts`, `src/main/runtime/startup-config.test.ts`, and `src/main/runtime/registry.test.ts`. `bun run test:node:compat` keeps those suites in the standard workflow instead of leaving them untracked. ## Acknowledgments diff --git a/package.json b/package.json index fe6e6dc4..7f0dd813 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "get-frequency:electron": "bun run build:yomitan && bun build scripts/get_frequency.ts --format=cjs --target=node --outfile dist/scripts/get_frequency.js --external electron && electron dist/scripts/get_frequency.js --pretty --color-top-x 10000 --yomitan-user-data ~/.config/SubMiner --colorized-line", "test-yomitan-parser": "bun run scripts/test-yomitan-parser.ts", "test-yomitan-parser:electron": "bun run build:yomitan && bun build scripts/test-yomitan-parser.ts --format=cjs --target=node --outfile dist/scripts/test-yomitan-parser.js --external electron && electron dist/scripts/test-yomitan-parser.js", - "build:yomitan": "node scripts/build-yomitan.mjs", - "build:assets": "node scripts/prepare-build-assets.mjs", + "build:yomitan": "bun scripts/build-yomitan.mjs", + "build:assets": "bun scripts/prepare-build-assets.mjs", "build": "bun run build:yomitan && tsc -p tsconfig.json && bun run build:renderer && bun run build:assets", "build:renderer": "esbuild src/renderer/renderer.ts --bundle --platform=browser --format=esm --target=es2022 --outfile=dist/renderer/renderer.js --sourcemap", "changelog:build": "bun run scripts/build-changelog.ts build", @@ -36,13 +36,13 @@ "test:smoke:dist": "bun run test:config:smoke:dist && bun run test:core:smoke:dist", "test:subtitle:src": "bun test src/core/services/subsync.test.ts src/subsync/utils.test.ts", "test:immersion:sqlite:src": "bun test src/core/services/immersion-tracker-service.test.ts src/core/services/immersion-tracker/storage-session.test.ts", - "test:immersion:sqlite:dist": "node --experimental-sqlite --test dist/core/services/immersion-tracker-service.test.js dist/core/services/immersion-tracker/storage-session.test.js", + "test:immersion:sqlite:dist": "bun test dist/core/services/immersion-tracker-service.test.js dist/core/services/immersion-tracker/storage-session.test.js", "test:immersion:sqlite": "bun run tsc && bun run test:immersion:sqlite:dist", - "test:src": "node scripts/run-test-lane.mjs bun-src-full", - "test:launcher:unit:src": "node scripts/run-test-lane.mjs bun-launcher-unit", + "test:src": "bun scripts/run-test-lane.mjs bun-src-full", + "test:launcher:unit:src": "bun scripts/run-test-lane.mjs bun-launcher-unit", "test:launcher:env:src": "bun run test:launcher:smoke:src && bun run test:plugin:src", "test:env": "bun run test:launcher:env:src && bun run test:immersion:sqlite:src", - "test:runtime:compat": "bun run tsc && node --experimental-sqlite --test dist/core/services/ipc.test.js dist/core/services/anki-jimaku-ipc.test.js dist/core/services/overlay-manager.test.js dist/main/config-validation.test.js dist/main/runtime/registry.test.js dist/main/runtime/startup-config.test.js", + "test:runtime:compat": "bun run tsc && bun test dist/core/services/ipc.test.js dist/core/services/anki-jimaku-ipc.test.js dist/core/services/overlay-manager.test.js dist/main/config-validation.test.js dist/main/runtime/registry.test.js dist/main/runtime/startup-config.test.js", "test:node:compat": "bun run test:runtime:compat", "test:full": "bun run test:src && bun run test:launcher:unit:src && bun run test:node:compat", "test": "bun run test:fast", @@ -50,7 +50,7 @@ "test:launcher": "bun run test:launcher:src", "test:core": "bun run test:core:src", "test:subtitle": "bun run test:subtitle:src", - "test:fast": "bun run test:config:src && bun run test:core:src && bun test src/main-entry-runtime.test.ts src/anki-integration/anki-connect-proxy.test.ts src/release-workflow.test.ts src/ci-workflow.test.ts scripts/build-changelog.test.ts && bun run tsc && node --experimental-sqlite --test dist/main/runtime/registry.test.js", + "test:fast": "bun run test:config:src && bun run test:core:src && bun test src/main-entry-runtime.test.ts src/anki-integration/anki-connect-proxy.test.ts src/release-workflow.test.ts src/ci-workflow.test.ts scripts/build-changelog.test.ts && bun run tsc && bun test dist/main/runtime/registry.test.js", "generate:config-example": "bun run build && bun dist/generate-config-example.js", "start": "bun run build && electron . --start", "dev": "bun run build && electron . --start --dev", diff --git a/scripts/build-yomitan.mjs b/scripts/build-yomitan.mjs index 999021bb..40d0e913 100644 --- a/scripts/build-yomitan.mjs +++ b/scripts/build-yomitan.mjs @@ -13,7 +13,7 @@ const submodulePackageLockPath = path.join(submoduleDir, 'package-lock.json'); const buildOutputDir = path.join(repoRoot, 'build', 'yomitan'); const stampPath = path.join(buildOutputDir, '.subminer-build.json'); const zipPath = path.join(submoduleDir, 'builds', 'yomitan-chrome.zip'); -const npmCommand = process.platform === 'win32' ? process.env.ComSpec ?? 'cmd.exe' : 'npm'; +const bunCommand = process.versions.bun ? process.execPath : 'bun'; const dependencyStampPath = path.join(submoduleDir, 'node_modules', '.subminer-package-lock-hash'); function run(command, args, cwd) { @@ -28,13 +28,6 @@ function readCommand(command, args, cwd) { return execFileSync(command, args, { cwd, encoding: 'utf8' }).trim(); } -function getNpmArgs(args) { - if (process.platform !== 'win32') { - return args; - } - return ['/d', '/s', '/c', 'npm', ...args]; -} - function readStamp() { try { return JSON.parse(fs.readFileSync(stampPath, 'utf8')); @@ -89,7 +82,7 @@ function ensureDependenciesInstalled() { } catch {} if (!fs.existsSync(nodeModulesDir) || installedLockHash !== currentLockHash) { - run(npmCommand, getNpmArgs(['ci']), submoduleDir); + run(bunCommand, ['install', '--no-save'], submoduleDir); fs.mkdirSync(nodeModulesDir, { recursive: true }); fs.writeFileSync(dependencyStampPath, `${currentLockHash}\n`, 'utf8'); } @@ -97,7 +90,7 @@ function ensureDependenciesInstalled() { function installAndBuild() { ensureDependenciesInstalled(); - run(npmCommand, getNpmArgs(['run', 'build', '--', '--target', 'chrome']), submoduleDir); + run(bunCommand, ['./dev/bin/build.js', '--target', 'chrome'], submoduleDir); } function extractBuild() { diff --git a/scripts/run-test-lane.mjs b/scripts/run-test-lane.mjs index 23c7cc2d..d9179bbf 100644 --- a/scripts/run-test-lane.mjs +++ b/scripts/run-test-lane.mjs @@ -1,8 +1,9 @@ import { readdirSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; import { relative, resolve } from 'node:path'; import { spawnSync } from 'node:child_process'; -const repoRoot = resolve(new URL('..', import.meta.url).pathname); +const repoRoot = resolve(fileURLToPath(new URL('..', import.meta.url))); const lanes = { 'bun-src-full': {