A modern Chrome extension for controlling your Clash proxy — right from the toolbar.
你的 Clash (mihomo) 跑在旁路由、主路由或远程服务器上?或者你只是在本地用 mihomo 内核,不想装 Electron 客户端或其他图形界面浪费内存和磁盘?
Switchy Clash 让你直接在 Chrome 工具栏完成一切 — 切换节点、测延迟、查看当前页面命中了哪条规则 — 两次点击,不需要打开任何 Dashboard 页面,不需要安装任何桌面客户端。
OffscreenCanvasgit clone https://github.com/user/switchy-clash.git
cd switchy-clash
npm install
npm run build
chrome://extensionsdist/ folder| Area | Description |
|---|---|
| Header | Active config (emoji + name), host:port, Clash version, proxy toggle |
| Rule Match | Current tab's domain, matched rule + payload, proxy chain, latency |
| Proxy Groups | 2-column compact cards — group name, type, node count, active node + latency, speed test |
Click a Selector group card to open a modal where you can browse nodes, test individual latency, or switch the active node. Nodes are sorted: selected first, then by latency ascending.
| Layer | Tech |
|---|---|
| UI | Svelte 5 (runes mode) |
| Styling | Tailwind CSS 4 |
| Language | TypeScript 5 |
| Build | Vite 6 |
| Testing | Playwright |
| Runtime deps | 0 |
src/
├── background/index.ts # MV3 service worker — proxy toggle, auto-switch, emoji icons
├── popup/ # Toolbar popup UI
│ ├── App.svelte # Main popup (groups, rule match, config selector)
│ └── main.ts
├── options/ # Full-tab settings page
│ ├── App.svelte # Config management, fonts, bypass list
│ └── main.ts
└── lib/
├── components/ # Button, Toggle, Select, Badge, StatusDot
├── services/
│ ├── clash-api.ts # Clash REST API client (12 endpoints)
│ ├── proxy.ts # chrome.proxy.settings wrapper
│ ├── storage.ts # chrome.storage.local wrapper (singleton)
│ └── permissions.ts # Dynamic host permission requests
├── types/ # TypeScript interfaces + defaults
└── utils.ts # Theme, font, delay formatting helpers
| Command | Description |
|---|---|
npm run build |
Build extension to dist/ |
npm run check |
TypeScript + Svelte type check |
npm run test |
Build + Playwright E2E tests |
npm run dev |
Vite dev server (limited use for extensions) |
proxy, storage, activeTab127.0.0.1 and localhost built-in; remote hosts requested dynamically at runtimeThe popup and options pages communicate with the background worker via chrome.runtime.sendMessage:
| Message | Action |
|---|---|
ENABLE_PROXY |
Set Chrome proxy to Clash |
DISABLE_PROXY |
Revert to system proxy |
TOGGLE_PROXY |
Toggle current state |
CHECK_ALL_CONFIGS |
Health check all configs |
GET_STATE |
Return full extension state |
SWITCH_CONFIG |
Change active config |
GET /version, 3s timeout)lastUsedAll UI state uses Svelte 5 runes ($state, $derived, $effect). No stores or external state libraries. Persistent state lives in chrome.storage.local with cross-page sync via chrome.storage.onChanged.
Implementation note:
chrome.storageuses structured clone which cannot serialize Svelte 5's$stateProxy objects. The storage service strips proxies viaJSON.parse(JSON.stringify())on every write.
12 CSS custom properties per mode, toggled via .dark class on <html>:
--color-bg, --color-bg-secondary, --color-bg-tertiary
--color-text, --color-text-secondary, --color-text-muted
--color-border, --color-primary
--color-success, --color-warning, --color-danger
System mode follows prefers-color-scheme and updates in real-time.
The extension targets mihomo (Clash.Meta) and covers these endpoints:
| Method | Endpoint | Usage |
|---|---|---|
GET |
/version |
Health check |
GET |
/configs |
Read ports & mode |
PATCH |
/configs |
Update config |
GET |
/proxies |
List all groups & nodes |
PUT |
/proxies/{name} |
Switch node |
GET |
/proxies/{name}/delay |
Test node latency |
GET |
/group/{name}/delay |
Test group latency |
GET |
/rules |
Routing rules |
GET |
/connections |
Active connections |
DELETE |
/connections |
Close all |
DELETE |
/connections/{id} |
Close specific |
Port detection priority: mixed-port > port > socks-port > 7890.
git checkout -b feat/my-feature)npm run check passesnpm run testThis project is provided as-is. See the repository for license details.