为什么在 Chrome 扩展中使用 RequireJS 调用时 chrome.tabs.query() return 选项卡的 URL 没有?

Why doesn't chrome.tabs.query() return the tab's URL when called using RequireJS in a Chrome extension?

我有一个添加浏览器操作的简单 Chrome 扩展。打开扩展程序的弹出窗口时,它需要访问当前选项卡的 URL。因为它不需要访问所有选项卡,所以我只拥有清单中指定的 activeTab 权限:

{
    "manifest_version": 2,
    "name": "RequireJS Test",
    "version": "0.0.1",
    "description": "Test RequireJS and the activeTab permission.",
    "permissions": [
        "activeTab"
    ],
    "browser_action": {
        "default_popup": "popup.html"
    },
    "web_accessible_resources": [
        "js/*",
        "html/*",
        "css/*",
        "img/*"
    ]
}

理论上,这应该让弹出窗口访问活动选项卡的 URL,但是当我从弹出窗口的 main.js 文件:

require([], function() {
    chrome.tabs.query({"active": true, "lastFocusedWindow": true}, function (tabs) {
        var url = tabs[0].url;
        console.log("URL from main.js", url);
    });

    console.log("URL from global var accessed in main.js", tabURL);
});

控制台显示 undefined URL。但是,如果我从一个不使用 require() 的普通 .js 文件进行相同的调用,它工作正常:

chrome.tabs.query({"active": true, "lastFocusedWindow": true}, function (tabs) {
    tabURL = tabs[0].url;
    console.log("URL from get-url.js", tabURL);
});

显示正确的 URL,我可以在 require() 调用中访问全局 tabURL 就好了。当我右键单击浏览器按钮并检查弹出窗口时,控制台输出如下所示:

URL from get-url.js http://whosebug.com/questions/ask
URL from global var accessed in main.js http://whosebug.com/questions/ask
URL from main.js undefined

更奇怪的是,我 有时 看到 URL 在 require() 调用中对 chrome.tabs.query() 的调用中可用。但大多数情况下它不起作用。关于 RequireJS 如何加载脚本的一些事情似乎混淆了 Chrome 并取消了对加载脚本的 URL 访问。这是在 Windows 上的 Chrome 40。

显然,解决方法是在单独的脚本中获取 URL 并将其存储在变量中,但这感觉有点笨拙。我想看看是否有适当的方法让它与 RequireJS 一起工作。

完整的插件源代码在这里,如果有人想在他们的机器上测试它:https://github.com/fwextensions/requirejs-url-test


编辑

正如 Rob W. 在下面解释的那样,这实际上与 RequireJS 无关。上面我的 get-url.js 文件中的代码返回正确 URL 的唯一原因是它恰好在 运行 打开 devtools window 之前。如果我将该文件更改为:

setTimeout(function() {
chrome.tabs.query({"active": true, "lastFocusedWindow": true}, function (tabs) {
    tabURL = tabs[0].url;
    console.log("URL from get-url.js", tabURL);
});
}, 5000);

然后 运行s 在 devtools window 打开后也失败了。 RequireJS 不是罪魁祸首。

您没有看到 URL,因为您只设置了 activeTab 权限(不是 tabs)权限,最后关注的 window 是开发人员工具(您没有 activeTab 访问权限)(并且由于 Chrome 41,devtools tabs/windows are invisible to extensions,因此 tabs 将是一个空数组).

好消息是这个问题是针对为您的扩展页面打开的开发工具 window 的,所以这个问题只发生在开发过程中,而不是在用户实际使用过程中。

扩展弹出窗口与 window 关联,因此您可以使用 chrome.tabs.querycurrentWindow:true 来获得正确答案:

chrome.tabs.query({
    active: true,
    currentWindow: true
}, function(tabs) {
    var tabURL = tabs[0].url;
    console.log(tabURL);
});

为了克服 Rob W. 在他的 post 中报告的 devTools 错误,以下 getActiveTab 解决方法似乎对我一直有效(即使有多个 devTools windows 打开).它的工作原理是,每当 tabs.onActivated 事件触发时,总是在后台页面中保存对 activeTabId 的引用。

var activeTabId;

chrome.tabs.onActivated.addListener(function(activeInfo) {
  activeTabId = activeInfo.tabId;
});

function getActiveTab(callback) {
  chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
    var tab = tabs[0];

    if (tab) {
      callback(tab);
    } else {
      chrome.tabs.get(activeTabId, function (tab) {
        if (tab) {
          callback(tab);
        } else {
          console.log('No active tab identified.');
        }
      });

    }
  });
}

错误,解决方法是(在“service_worker”:“background.js”):

var activeTab; // Workaround for bug https://bugs.chromium.org/p/chromium/issues/detail?id=462939

// On activated tabs (triggered immediately after declaration)
chrome.tabs.onActivated.addListener(function(tab) {
    activeTab = tab;
    console.debug(activeTab);
});