Scope
This Skill is used to create or modify Chrome extensions (Manifest V3) in Cursor. Follow this when dealing with manifest structure, content script, background, popup, permissions, and message communication.
Extension Structure (Manifest V3)
Manifest V3 must be used; V2 is deprecated.
Minimal manifest.json example:
{
"manifest_version": 3,
"name": "扩展名称",
"version": "1.0.0",
"description": "扩展描述",
"permissions": [],
"optional_permissions": [],
"host_permissions": []
}
Common entry points and fields:
| Entry | Purpose |
|---|---|
background.service_worker |
Persistent logic (events, timers, cross-tab coordination) |
action.default_popup |
Popup HTML when the extension icon is clicked |
content_scripts |
JS/CSS injected into matching web pages |
options_page |
Options page |
Permissions
- permissions: Requested at install time when declared (e.g.,
storage、tabs、scripting)。 - host_permissions: Accessible URLs (e.g.,
https://*/*、<all_urls>)。 - optional_permissions: At runtime via
chrome.permissions.request()to request again.
Only declare permissions actually needed; sensitive permissions (e.g., <all_urls>) must have their purpose explainable to users.
Background(Service Worker)
- Files are specified in the manifest via
background.service_worker, single file, ES modules require setting"type": "module"。 - No DOM, no
window; usechrome.*API andchrome.runtimemessages. - It will be terminated after being idle for a while; you cannot rely on global variables to persist state long-term; use
chrome.storage。
Commonly: listen to chrome.runtime.onInstalled、chrome.tabs.onUpdated、chrome.alarms, and use chrome.runtime.sendMessage / chrome.tabs.sendMessage to communicate with popup/content script.
Content Script
- In
content_scriptsspecifymatches(URL patterns),js、css。 - Runs in an isolated JS environment, does not share globals with page scripts; can access the DOM, but cannot directly access the page's
windowvariables. - Communicating with background:
chrome.runtime.sendMessage; receiving:chrome.runtime.onMessage。 - When you need to operate in the page script context, inject
<script>into the page and then usewindow.postMessageto exchange data with the content script.
Popup
- A normal HTML + JS page; its lifecycle is short, destroyed when closed.
- When data is needed, read from
chrome.storage, or obtain it by sending a message to background. - Do not do long asynchronous initialization here; it is more reliable to prepare data in background before opening.
Message Communication
- popup/content → background:
chrome.runtime.sendMessage(message, response => {...})。 - background → content:
chrome.tabs.sendMessage(tabId, message, response => {...}); a content script must first be injected into that tab. - Receiver:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { ...; return true; }). For asynchronous replies, you mustreturn trueand callsendResponse。
Storage
- chrome.storage.local: Local, relatively large capacity, suitable for extension-private data.
- chrome.storage.sync: Synced across devices, has quota limits.
- chrome.storage.session(MV3): Only for the current session, cleared when the browser is closed.
Both reads and writes are asynchronous:chrome.storage.local.get/set(...)。
Common manifest snippets
With background + popup + content script:
{
"manifest_version": 3,
"name": "示例扩展",
"version": "1.0.0",
"permissions": ["storage", "activeTab"],
"host_permissions": ["https://*/*"],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html",
"default_title": "打开面板"
},
"content_scripts": [
{
"matches": ["https://example.com/*"],
"js": ["content.js"],
"css": ["content.css"]
}
]
}
Development and Debugging
- After code changes, go to
chrome://extensionsand click "Reload". - Background: Open DevTools via the "Service Worker" link on the extensions page.
- Content script: In the DevTools of the corresponding web page, select the extension's context to view it.
- Popup: Right-click the extension icon → "Inspect popup".
Notes
- MV3 no longer has a persistent background page; use
chrome.alarmsfor long-running logic, or trigger it by user action. - For injected scripts, prefer
chrome.scripting.executeScript(requiresscriptingpermissions) for dynamic injection, and if necessary, combine withcontent_scripts。 - Publishing on the Chrome Store requires compliance with Chrome Web Store Program Policies; permissions and privacy disclosures must be clear.