
在 manifest v3 下,通过设置 `world: "main"` 可使 content script 直接运行在页面主线程(main world),从而在 `document_start` 阶段就写入 `window` 变量,确保早于网站自身脚本执行。
传统注入方式(如动态创建
根本解法:弃用动态注入,改用 world: "MAIN"
自 Chrome 111 起,Manifest V3 的 content_scripts 支持 world 字段,设为 "MAIN" 后,脚本将脱离隔离沙箱(isolated world),直接运行在页面全局上下文中(即与网站 JS 共享同一个 window 对象)。这意味着:
- ✅ 脚本在 run_at: "document_start" 时立即执行(DOM 尚未构建完成,但 window 已可用);
- ✅ 可直接赋值 window.someVar = true,后续所有页面脚本均可访问;
- ✅ 无需 web_accessible_resources、无需 injected.js、无需 DOM 操作,零延迟。
✅ 正确配置如下:
manifest.json
{
"name": "script-injector",
"manifest_version": 3,
"version": "0.0.1",
"content_scripts": [
{
"matches": ["*://localhost:*/*", "*://127.0.0.1:*/*"],
"js": ["content.js"],
"run_at": "document_start",
"world": "MAIN"
}
]
}content.js(极简、高效)
console.log("CE: MAIN-world script executed at document_start");
window.someVar = true;
window.API_CONFIG = { endpoint: "https://dev.local/api" };
// 所有 window 属性在此刻已就绪,页面 JS 启动时可直接使用⚠️ 重要限制与应对策略
world: "MAIN" 下无法访问 chrome.* API(如 chrome.runtime.sendMessage, chrome.storage 等),因其仅在扩展沙箱中可用。若需结合扩展能力(例如读取 storage 配置、监听消息),推荐采用 双 content script 协作模式:
- MAIN-world script(run_at: "document_start"):仅负责初始化 window 变量;
- Isolated-world script(默认 world,不声明):负责调用 chrome.* API,并通过 CustomEvent 向页面广播数据。
示例(content-isolated.js):
// 从 storage 读取配置并透传至页面
chrome.storage.sync.get('userConfig', ({ userConfig }) => {
const event = new CustomEvent('ExtensionConfigReady', {
detail: { userConfig }
});
window.dispatchEvent(event);
});页面 JS 中监听:
window.addEventListener('ExtensionConfigReady', (e) => {
console.log('Received from extension:', e.detail.userConfig);
});? 总结
- ✅ 优先使用 world: "MAIN" + run_at: "document_start" 实现“真·早执行”;
- ❌ 避免动态
- ? 如需扩展能力,用 CustomEvent 或 window.postMessage 安全桥接两个 world;
- ? 测试建议:在 DevTools Console 中执行 getEventListeners(window) 验证事件绑定,或在页面脚本开头添加 console.log(window.someVar) 确认初始化时机。









