Search code examples
google-chrome-extension

Why does chrome.tabs.create create 2 tabs?


When the chrome.tabs.create function is triggered by a message received, it creates 2 tabs. In the following demo code, 1 cat tab is created, and 2 dog tabs are created.

Is this by design or is it a bug? If it is a known bug, can you provide the bug id so I can track its progress? How can I avoid 2 duplicate tabs being created?

The debug console contains the following output, so in fact the duplicate tab is also getting the content script injected even though only one call to secondaryTabCreationCallback_ is printed in the debug output!!!!

Creating secondary tab
Created secondary tab: 11968
Kill request from tab: 11966
Kill request from tab: 11968

background.js

var handler = {
  url1_: 'https://www.google.com/?gws_rd=ssl#q=cat',
  url2_: 'https://www.google.com/?gws_rd=ssl#q=dog',

  windowId_: chrome.windows.WINDOW_ID_CURRENT,

  createPrimaryTab: function() {
    chrome.tabs.create(
        {'url': handler.url1_, 'active': false, 'windowId': handler.windowId_},
        handler.primaryTabCreationCallback_);
  },

  primaryTabCreationCallback_: function(tab) {
    chrome.tabs.executeScript(tab.id, {file: "content_script.js"});
  },

  createSecondaryTab_: function() {
    console.log("Creating secondary tab");
    chrome.tabs.create(
        {'url': handler.url2_, 'active': false, 'windowId': handler.windowId_},
        handler.secondaryTabCreationCallback_);
  },

  secondaryTabCreationCallback_: function(tab) {
    console.log("Created secondary tab: " + tab.id);
    chrome.tabs.executeScript(tab.id, {file: "content_script2.js"});
  },
};

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  switch (message.type) {
    case "CREATE_TAB":
      handler.createSecondaryTab_();
      break;
    case "KILL_ME":
      console.log("Kill request from tab: " + sender.tab.id);
      // chrome.tabs.remove(sender.tab.id);
      break;
    default:
      alert("Not Reached");
      break;
  }
});

chrome.browserAction.onClicked.addListener(function(tab) {
  chrome.tabs.create({'url': chrome.extension.getURL('background.html')});
});

window.onload = function() {
  document.getElementById("start_button").onclick = handler.createPrimaryTab;
}

content_script.js

chrome.runtime.sendMessage({type: "CREATE_TAB"});

content_script2.js

chrome.runtime.sendMessage({type: "KILL_ME"});

background.html

<!doctype html>
<html>
  <head>
    <script src="background.js"></script>
  </head>
  <body>
    <div>
      <input type="button" id="start_button" value="Start">
    </div>
  </body>
</html>

manifest.json

{
  "manifest_version": 2,

  "name": "Tab Bug",
  "description": "Demonstrates bug in chrome.tabs.create.",
  "version": "1.0",

  "permissions": [
    "activeTab",
    "nativeMessaging",
    "tabs",
    "https://www.google.com/"
  ],
  "icons": { "128": "icon128.png" },
  "browser_action": {
    "default_icon": "icon19.png"
  },
  "background": {
    "page": "background.html"
  }
}

Solution

  • The issue is that there are 2 "background" pages running.

    1. The official background page specified in the manifest file.
    2. The tab created by chrome.tabs.create({'url': chrome.extension.getURL('background.html')}).

    This means there are 2 message listeners, which is why 2 tabs are opening.

    The console messages from the official manifest.json background can be found by looking at extension on the chrome extensions page and click on the "Inspect views: background.html". Which shows:

    Creating secondary tab
    Created secondary tab: 11966
    Kill request from tab: 11966
    Kill request from tab: 11968
    

    To work around this issue. The manifest.json background file can point to a script "starter.js" instead of an html page, which simply has the following javascript:

    chrome.browserAction.onClicked.addListener(function(tab) {
      chrome.tabs.create({'url': chrome.extension.getURL('background.html')});
    });