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
52 changes: 52 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: CI

on:
push:
branches:
- main
pull_request:

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Typecheck
run: pnpm typecheck

- name: Biome
run: pnpm check

- name: Unit tests
run: pnpm test:unit

- name: Build
run: pnpm build

- name: Validate extension config
run: pnpm validate

- name: Install Playwright browsers
run: |
pnpm exec playwright install --with-deps chromium
pnpm exec playwright install chrome msedge

- name: E2E tests
run: xvfb-run --auto-servernum pnpm test:e2e
36 changes: 19 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ name: Release Chrome Extension
on:
push:
tags:
- 'v*' # 触发条件:推送以 v 开头的tag
- 'v*'

jobs:
build-and-publish:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整的 git 历史用于版本号
- uses: pnpm/action-setup@v4
name: Install pnpm
fetch-depth: 0

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false

Expand All @@ -27,24 +27,26 @@ jobs:
cache: 'pnpm'

- name: Get version from git tag
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_ENV"

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Update version in manifest.json
- name: Install Playwright browsers
run: |
sed -i "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" src/manifest.json
sed -i "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" package.json
pnpm exec playwright install --with-deps chromium
pnpm exec playwright install chrome msedge

- name: Install dependencies
run: pnpm install
- name: Verify release build
run: xvfb-run --auto-servernum pnpm test:ci

- name: Create ZIP file
run: pnpm zip
run: pnpm crx package --version "$VERSION" --out CrxKit.zip

- name: Upload to Chrome Web Store
uses: mnao305/chrome-extension-upload@v5.0.0
with:
file-path: Tiny-helmet.zip
file-path: CrxKit.zip
extension-id: ${{ secrets.CHROME_EXTENSION_ID }}
client-id: ${{ secrets.CHROME_CLIENT_ID }}
client-secret: ${{ secrets.CHROME_CLIENT_SECRET }}
Expand All @@ -54,11 +56,11 @@ jobs:
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: Tiny-helmet.zip
files: CrxKit.zip
name: Release ${{ env.VERSION }}
body: |
Release version ${{ env.VERSION }}

Changes in this version:
- Please check the commit history for detailed changes
draft: false
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
node_modules
dist
playwright-report
test-results
*.zip
.DS_Store
.antigravitycli

46 changes: 46 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# AGENTS.md

This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.

## Project Overview

**CRXKit** is a Chrome Extension Manifest v3 scaffold that ships with React 19, Tailwind CSS v4, shadcn UI primitives, Zustand, TanStack React Query, and Rspack. It exposes React-based popup and side panel surfaces, a configurable background service worker, and a themed, localization-aware content script helper.

## Development Commands

- `pnpm dev` – Incremental build that watches all MV3 entrypoints and writes to `dist/`.
- `pnpm build` – Production build with minification and asset copying.
- `pnpm typecheck` – Run TypeScript in no-emit mode using bundler-style resolution.
- **Package manager**: `pnpm@9` (pinned in `package.json`).

## Architecture

- **Entries** (`src/entries/`)
- `background/` – Service worker orchestrating side panel enablement and host automation.
- `content/` – Content script that syncs theme preferences, renders a floating opener, and reacts to storage updates.
- `popup/` – React UI for managing hosts, theme, and automation flags.
- `side-panel/` – React UI rendered inside Chrome's side panel, reflecting shared state in real time.
- **Shared modules** (`src/shared/`)
- `config/extension.ts` – Central defaults, entry asset paths, host allowlists, and settings shape.
- `platform/` – Chrome wrappers (`storage.ts`, `i18n.ts`) that guard access when APIs are unavailable.
- `state/useExtensionStore.ts` – Persisted Zustand store with hydration helpers and Chrome event subscription.
- `hooks/` – React hooks for hydration (`useExtensionHydration`) and metadata (`useChromeManifest`).
- `providers/AppProviders.tsx` – Singleton React Query client for popup + side panel surfaces.
- `ui/` – shadcn-inspired primitives (`Button`, `Card`, `Input`).
- `lib/utils.ts` – Utility helpers (`cn`, runtime checks, URL parsing).
- **Styles** (`src/styles/tailwind.css`) – Tailwind 4 tokens for light/dark theming.

## Key Behaviours

- Background worker toggles and optionally opens the side panel based on default hosts and user-pinned domains stored in `chrome.storage`.
- Content script applies the persisted theme and exposes a localized floating action button when the active domain is allowed.
- Popup and side panel hydrate shared state via the Zustand store, backed by React Query for extension metadata and ready for future async data.
- Manifest restricts content scripts and host permissions to the default allowlist; update both alongside `extensionConfig` when adding domains.

## Notes for Contributors

- Add new React surfaces under `src/entries/<feature>` and register them in both `rspack.config.js` and `src/manifest.json`.
- Extend `extensionConfig` when altering storage shape, asset locations, or Chrome permissions to keep background/content logic aligned.
- Prefer shared utilities/hooks/providers to avoid duplicating storage or Chrome API access patterns.
- Use `getMessage` wrappers for user-facing strings and update `_locales/en` + `_locales/zh_CN` together.
- Tailwind tokens power shadcn components; extend `tailwind.config.ts` for new palettes or animations instead of inlining custom CSS.
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

**Tiny Helmet** is a Chrome Extension Manifest v3 scaffold that ships with React 19, Tailwind CSS v4, shadcn UI primitives, Zustand, TanStack React Query, and Rspack. It exposes React-based popup and side panel surfaces, a configurable background service worker, and a themed, localization-aware content script helper.
**CRXKit** is a Chrome Extension Manifest v3 scaffold that ships with React 19, Tailwind CSS v4, shadcn UI primitives, Zustand, TanStack React Query, and Rspack. It exposes React-based popup and side panel surfaces, a configurable background service worker, and a themed, localization-aware content script helper.

## Development Commands

Expand Down
39 changes: 31 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Tiny Helmet
# CRXKit

A modern Chrome extension scaffold powered by Rspack, React 19, Tailwind CSS v4, shadcn UI primitives, and Zustand state management. Configure hosts, theme, and side panel behaviour with minimal setup and ship production-ready MV3 bundles quickly.
A lightweight Chrome MV3 extension framework powered by Rspack, React 19, Tailwind CSS v4, shadcn UI primitives, Zustand, and a small project-local CLI. Configure entrypoints, manifest metadata, permissions, hosts, and defaults from `extension.config.json`, then ship production-ready bundles from `dist/`.

## Quick start

Expand All @@ -11,40 +11,63 @@ A modern Chrome extension scaffold powered by Rspack, React 19, Tailwind CSS v4,

## Project layout

- `src/entries/` — MV3 entrypoints for background, content script, popup, and side panel UIs.
- `extension.config.json` — Single source of truth for MV3 entries, permissions, hosts, defaults, and manifest metadata.
- `src/entries/` — MV3 entrypoints for background, content script, popup, side panel, options, and new tab UIs.
- `src/entries/content/` — React-powered content script that mounts inside a Shadow DOM with Tailwind styling.
- `src/shared/` — Reusable configuration, hooks, providers, state, and shadcn-style UI primitives.
- `src/styles/` — Tailwind 4 design tokens and layer definitions.
- `scripts/lib/` & `bin/crxkit.mjs` — Manifest, Rspack, validation, scaffold, and packaging helpers.
- `_locales/` & `public/` — i18n resources and static assets copied to the build.

## Tech stack highlights

- **Rspack** for fast, multi-entry bundling tailored to Chrome extensions.
- **Config-driven Rspack** for fast, multi-entry bundling tailored to Chrome extensions.
- **React 19 + Tailwind 4** for ergonomics and theming inside popup and side panel surfaces.
- **shadcn UI primitives** (`Button`, `Card`, `Input`) with `class-variance-authority` and `tailwind-merge`.
- **Zustand + chrome.storage** store shared across background, popup, and side panel.
- **React Query** provider ready for async data caching and cross-surface reuse.
- **Localization ready** via `_locales`, with theme-aware content script helpers.
- **CRXKit CLI** for validation, entry generation, manifest inspection, project creation, and zip packaging.

## Useful commands

- `pnpm dev` — Watch mode build; rebuilds extension outputs on file change.
- `pnpm build` — Production bundle with minified assets.
- `pnpm typecheck` — Run TypeScript in no-emit mode to validate types.
- `pnpm test` — Execute the Vitest suite once (CI-friendly).
- `pnpm test:unit` — Execute unit and component tests with Vitest.
- `pnpm test:e2e` — Execute Playwright E2E and browser smoke tests after `pnpm build`.
- `pnpm test:ci` — Run typecheck, Biome, unit tests, build, validation, and E2E.
- `pnpm test:watch` — Re-run tests on file change during local development.
- `pnpm test:coverage` — Generate HTML/LCOV coverage output under `coverage/`.
- `pnpm lint` — Run Biome lint rules without mutating files.
- `pnpm format` — Apply Biome formatting fixes in-place.
- `pnpm check` — Run Biome’s combined lint/format/import organization checks in read-only mode.
- `pnpm validate` — Validate `extension.config.json`, entries, locales, and manifest derivation.
- `pnpm crx manifest --print` — Print the generated MV3 manifest.
- `pnpm crx entry add demo --kind page` — Add a React page entry and update `extension.config.json`.
- `pnpm crx package --out CrxKit.zip` — Build and package `dist/` for Chrome Web Store upload.

## Framework configuration

`extension.config.json` drives both runtime code and build output:

- `entries` are converted into Rspack inputs, HTML outputs, service worker registration, content scripts, side panel, options, and new tab manifest fields.
- `permissions`, `hostPermissions`, `webAccessibleResources`, `minimumChromeVersion`, and localized manifest message keys are emitted into `dist/manifest.json`.
- `settings` and `sidePanel.allowedHosts` are imported by `src/shared/config/extension.ts`, so runtime defaults and manifest/build output stay aligned.

Do not edit `dist/manifest.json` by hand. The source manifest is generated from config during `pnpm build`.

## Testing workflow

- Unit and component tests live under `src/__tests__/` and use Vitest with Testing Library.
- The `vitest.config.ts` file mirrors extension aliases (e.g. `@/`) and bootstraps a happy-path Chrome API stub via `src/__tests__/setup/test-setup.ts`.
- CLI and config tests live under `src/__tests__/unit/scripts/`.
- Extension E2E tests live under `tests/e2e/` and use Playwright.
- The `vitest.config.mjs` file mirrors extension aliases (e.g. `@/`) and bootstraps a happy-path Chrome API stub via `src/__tests__/setup/test-setup.ts`.
- Prefer co-locating tests near shared logic (`@/shared`) to validate hooks, stores, and shadcn primitives.
- Before opening a PR, run `pnpm typecheck`, `pnpm check`, and `pnpm test` (or `pnpm test:coverage` when you need a report for reviewers).
- Before opening a PR, run `pnpm test:ci` when browser dependencies are installed, or at minimum `pnpm typecheck`, `pnpm check`, `pnpm test:unit`, `pnpm build`, and `pnpm validate`.
- When tests require additional Chrome APIs, extend the shared stub instead of mocking per file to keep behaviour consistent.
- Core extension sideload tests use Playwright bundled Chromium. Chrome and Edge projects are smoke tests for built HTML pages because current browser policies do not reliably support sideloaded extension flags there.

## Content script UI

Expand All @@ -55,6 +78,6 @@ A modern Chrome extension scaffold powered by Rspack, React 19, Tailwind CSS v4,

## Next steps

- Tweak `extensionConfig` + `manifest.json` to add new hosts, permissions, or surfaces.
- Drop additional React entrypoints under `src/entries` and register them inside `rspack.config.js`.
- Tweak `extension.config.json` to add new hosts, permissions, or surfaces.
- Run `pnpm crx entry add <name> --kind page` to generate additional React entrypoints.
- Expand `_locales/` alongside UI updates so popup, side panel, and content script stay translated.
4 changes: 2 additions & 2 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extension_name": {
"message": "Tiny Helmet",
"message": "CRXKit",
"description": "The display name of the extension"
},
"extension_description": {
Expand Down Expand Up @@ -92,7 +92,7 @@
"description": "Content script button label when auto-open is enabled"
},
"content_open_side_panel_aria": {
"message": "Open Tiny Helmet side panel",
"message": "Open CRXKit side panel",
"description": "ARIA label for the floating button"
},
"sidepanel_status_ready": {
Expand Down
4 changes: 2 additions & 2 deletions _locales/zh_CN/messages.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extension_name": {
"message": "Tiny Helmet",
"message": "CRXKit",
"description": "扩展显示名称"
},
"extension_description": {
Expand Down Expand Up @@ -92,7 +92,7 @@
"description": "内容脚本在自动模式下的按钮文案"
},
"content_open_side_panel_aria": {
"message": "打开 Tiny Helmet 侧边栏",
"message": "打开 CRXKit 侧边栏",
"description": "浮动按钮的 ARIA 标签"
},
"sidepanel_status_ready": {
Expand Down
11 changes: 11 additions & 0 deletions bin/crxkit.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env node

import { runCli } from '../scripts/lib/cli.mjs';

const exitCode = await runCli(process.argv.slice(2), {
cwd: process.cwd(),
stdout: (line) => console.log(line),
stderr: (line) => console.error(line),
});

process.exitCode = exitCode;
10 changes: 9 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
"$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
"root": true,
"files": {
"includes": ["**", "!**/dist", "!**/node_modules", "!**/coverage"]
"includes": [
"**",
"!**/dist",
"!**/node_modules",
"!**/coverage",
"!**/playwright-report",
"!**/test-results",
"!**/*.zip"
]
},
"formatter": {
"enabled": true,
Expand Down
Loading
Loading