在 manifest v3 下,通过设置 `world: "main"` 可使 content script 直接运行在页面主线程(main world),从而在 `document_start` 阶段就写入 `window` 变量,确保早于网站自身脚本执行。
传统注入方式(如动态创建 —— 这正是你观察到 Content Script → Website JS → Injected JS 顺序的根本原因。
根本解法:弃用动态注入,改用 world: "MAIN"
自 Chrome 111 起,Manifest V3 的 content_scripts 支持 world 字段,设为 "MAIN" 后,脚本将脱离隔离沙箱(isolated world),直接运行在页面全局上下文中(即与网站 JS 共享同一个 window 对象)。这意味着:
✅ 正确配置如下:
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 协作模式:
示例(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);
});? 总结
s(window) 验证事件绑定,或在页面脚本开头添加 console.log(window.someVar) 确认初始化时机。