refactor: feature-first architecture, tests, CI hardening, bugfixes#2
Merged
Conversation
Replace technical-layer folders (components/, hooks/, preferences/, steam-ui/) with feature modules that reflect what the extension does: - src/trackers/ tracker catalog, URL building, preferences + hook - src/tracker-menu/ menu injected into Steam profile sidebars - src/popup/ toolbar popup app and components - src/steam/ Steam profile URL parsing and match patterns - src/i18n/ locales, stored preference, runtime + hook Entrypoints are now thin wiring only. Storage keys live with their domains (TRACKER_PREFERENCES_KEY, LOCALE_KEY), install/update lifecycle branching moved to the background entrypoint, pure message helpers extracted to i18n/messages.ts, and all filenames are kebab-case so the useFilenamingConvention override is no longer needed.
setTrackerPreference does a read-modify-write of the whole preferences record. Two rapid toggles in the popup could both read the same snapshot and the second write would silently revert the first one. All writes now go through a queue so each read sees the previous write's result.
browser.storage.onChanged listeners are not cleaned up by WXT's content script context. After an extension update or reload the orphaned listener kept firing against an invalidated context. Register a named handler and remove it via ctx.onInvalidated.
Construct trigger, direct link, and empty state with createElement and textContent instead of interpolating translated strings into innerHTML. Hardens against markup injection from locale files and deduplicates the count_link_label markup.
- resolveLocale was never called; locale resolution is handled by initI18n falling back to browser.i18n for the system setting - GITHUB_ISSUES_URL constant was unreferenced - popupSubtitle message key was unused in all seven locales - wxt.svg shipped in the extension bundle and react.svg were template leftovers
Vitest with WXT's testing plugin (fakeBrowser for storage-backed code) and happy-dom for DOM assertions. Covers Steam profile URL parsing, tracker URL transforms, catalog invariants, preference storage (including a regression test for the concurrent-write race), locale storage normalization, i18n substitutions, and the injected menu's rendering, a11y attributes, and keyboard navigation. Run with bun run test / bun run test:watch.
Split CI into a quality job (lint, locale check, typecheck, test) and a build matrix (chrome, firefox). Cancel superseded runs on PR branches. Release workflow now lints and tests before zipping.
json-sort carried monorepo package discovery (packages/*, apps/*) from a template; this repo has a single package.json. check-locales now also verifies $n substitution tokens match the base locale per key.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Reorganizes the source into feature-first ("screaming") modules, adds a Vitest test suite, hardens CI, and fixes two real bugs found during the audit.
Architecture
Technical-layer folders (
components/,hooks/,preferences/,steam-ui/) are dissolved into feature modules:src/trackers/src/tracker-menu/src/popup/src/steam/src/i18n/src/entrypoints/Storage keys now live with their domains, install/update lifecycle branching moved into the background entrypoint, pure i18n helpers extracted to
i18n/messages.ts, and all filenames are kebab-case (theuseFilenamingConventionlint override is removed).Bugfixes
setTrackerPreferenceis a read-modify-write of the whole record; two rapid popup toggles could clobber each other. Writes are now serialized through a queue. Regression test included (verified failing without the fix).browser.storage.onChangedlistener was never removed when the script context was invalidated (extension update/reload). Now cleaned up viactx.onInvalidated.createElement/textContentinstead of interpolating translated strings intoinnerHTML.Tests (new)
Vitest + WXT testing plugin (
fakeBrowser) + happy-dom — 55 tests across 8 files: profile URL parsing, tracker URL transforms, catalog invariants, preference storage (incl. concurrency regression), locale normalization, i18n substitutions, and the injected menu's rendering/a11y/keyboard navigation.bun run test.CI
check-localesnow also validates$nplaceholder consistency per keyCleanup
resolveLocale,GITHUB_ISSUES_URL, unusedpopupSubtitlekey in all 7 localeswxt.svg(was shipping inside the extension bundle) andreact.svgtemplate leftovers removedjson-sortscript dropped its monorepo (packages/*,apps/*) discovery leftoverVerification
ultracite check,tsc --noEmit,check:locales,vitest run(55/55), chrome + firefox builds all pass