Traffic Blocker is built on a two-process architecture mandated by Chrome’s Manifest V3 platform. A Vue 3 single-page application runs as the popup and handles all user interaction, while a background service worker handles counting blocked requests and initialising storage on first install. Rule updates reachDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/alexperezortuno/ce-blocker/llms.txt
Use this file to discover all available pages before exploring further.
declarativeNetRequest through two paths: the Dashboard popup calls declarativeNetRequest directly for fast inline edits, while the Settings component routes preset and import operations through chrome.runtime.sendMessage to the background service worker.
Directory Structure
Popup (Vue 3 SPA)
main.ts bootstraps a Vue 3 application and mounts it to #app inside index.html. The app uses vue-router with createWebHistory and three content routes plus a catch-all:
| Path | Name | Component |
|---|---|---|
/ | Dashboard | Dashboard.vue — add, edit, delete, search, reorder rules, and toggle blocking |
/statistics | Statistics | Statistics.vue — blocked traffic counter with reset action |
/settings | Settings | Settings.vue — dark mode toggle, export/import, and preset blocklists |
App.vue is the root component and owns the isDarkMode reactive ref. On mount it reads settings.darkMode from chrome.storage.local and applies (or removes) the dark-mode CSS class on document.body. It exposes isDarkMode to child routes via defineExpose and listens for a toggle-dark-mode event emitted up through the <router-view>:
Background Service Worker
The background script is registered inmanifest.json as:
registerEventListeners() call:
-
chrome.runtime.onInstalled— fires on first install. Reads bothsettingsandblockerkeys fromchrome.storage.local. Ifsettingsis absent it writes{ blocked: 0 }. Ifblockeris absent it writes{ rules: [], isEnabled: false }. -
chrome.webRequest.onErrorOccurred— attached to<all_urls>with theextraHeadersoption. Each time a request fails withres.error === 'net::ERR_BLOCKED_BY_CLIENT'it reads the currentsettings.blockedvalue from storage and increments it by one. -
chrome.runtime.onMessage— handlesupdateRulesmessages from the popup. A module-levelisUpdatingRulesboolean flag prevents concurrent updates from racing. When a valid message arrives the background auto-fixes and re-indexes every rule, fetches the current dynamic-rule IDs, removes them all, then adds the new set (or an empty array when blocking is disabled). Finally it persists the new state tochrome.storage.localand replies to the popup.
Communication Between Popup and Background
When the Settings component applies a preset or imports rules, it delegates to the background viachrome.runtime.sendMessage:
true to keep the message channel open for the asynchronous sendResponse call, which is required by the Chrome runtime when responding after an await or callback boundary.
Data Flow
Dashboard inline rule edits
When a user adds or edits a rule directly in the Dashboard,updateStaticRules() handles everything inside the popup:
User submits a rule
The Dashboard component validates the input and pushes the new rule into the local
rules array.Popup calls updateStaticRules()
The helper builds a cleaned rule list with sequential IDs starting from
1, then calls declarativeNetRequest directly from the popup context.declarativeNetRequest.updateDynamicRules applies the change
All previous dynamic rules are removed by ID, then the new rules are added (or an empty array when
isEnabled is false).Settings-driven rule updates (presets and imports)
When the Settings component applies a preset blocklist or imports rules from a file, it routes the update through the background service worker:Settings sends an updateRules message
chrome.runtime.sendMessage({ updateRules: { data: rules, isEnabled } }) dispatches to the background and awaits the response.Background validates and auto-fixes
The service worker runs each rule through
autoFixRule(), reassigning sequential IDs starting from 1.declarativeNetRequest.updateDynamicRules applies the change
All previous dynamic rules are removed by ID, then the new set is added (or an empty array when
isEnabled is false).