Frontend Development 12 min read

Reviving the lastTab Chrome Extension: Manifest Configuration and Core Logic

This article details the revival of the lastTab Chrome extension, explaining the manifest v3 setup, background scripts, and event listeners that ensure each window retains at least two tabs, while providing full source code snippets and implementation notes.

FunTester
FunTester
FunTester
Reviving the lastTab Chrome Extension: Manifest Configuration and Core Logic

Chrome is a dominant desktop browser, and many users rely on extensions to enhance its functionality. The author recounts the frustration of losing the last tab when closing a window and how the now‑defunct lastTab extension solved this problem.

After the original extension disappeared—likely due to Chrome’s upgrade from version 2 to 3—the author obtained an older version and installed it offline. Inspired by recent learning of Chrome extension development basics, they decided to resurrect the tool.

manifest configuration

The following manifest.json (manifest_version 3) defines the extension’s metadata, permissions, icons, background service worker, and content scripts:

{
  "manifest_version": 3,
  "version": "1.0",
  "action": {
    "default_icon": "funtester.png",
    "default_popup": "popup.html"
  },
  "background": {
    "service_worker": "background.js"
  },
  "description": "hello,FunTester !!!",
  "icons": {
    "48": "funtester.png",
    "128": "funtester128.png"
  },
  "name": "FunTester Tab",
  "offline_enabled": true,
  "content_scripts": [{
    "matches": ["
"],
    "js": ["content.js"],
    "run_at": "document_end",
    "all_frames": true
  }],
  "host_permissions": ["
"],
  "permissions": ["tabs", "storage", "contextMenus", "scripting", "activeTab"]
}

Some permissions are unrelated to the core lastTab functionality and remain for other project features.

background

The background script implements the core logic that guarantees each window has at least two tabs. The first tab (index 0) is created by the extension, while the second is the user’s default page. When the penultimate tab is closed, a new tab is opened using the browser’s default newTab page.

Installation

On installation the extension sets a badge text "Fun", defines a red badge background, and opens a page caption.html that lists original articles:

chrome.runtime.onInstalled.addListener(function () {
  chrome.action.setBadgeText({text: "Fun"});
  chrome.action.setBadgeBackgroundColor({color: [255,0,0,255]});
  chrome.tabs.create({url: "caption.html", active: true});
});

The installation listener performs three actions: badge text, badge color, and opening the article list.

Initialization

After installation the script retrieves all windows, checks each one, and creates the first tab if it is missing:

chrome.windows.getAll({populate: true}, initialCheck);
function initialCheck(windows) {
  for (let index = 0; index < windows.length; ++index) {
    let window = windows[index];
    checkWinowClose(window);
    if (!checkIfFirstTabIsOurs(window)) createTabInWindow(windows[index]);
  }
}

New Window Handling

chrome.windows.onCreated.addListener(createNewWindow);
function createNewWindow(window) {
  if (typeof window !== "undefined" && window.type === "normal" && !checkIfFirstTabIsOurs(window)) {
    createTabInWindow(window);
  }
}

The listener ensures a new normal window also contains the required tab.

Tab Removal

chrome.tabs.onRemoved.addListener(tabRemoved);
function tabRemoved(tabId, removeInfo) {
  console.info("Tab removed", tabId, removeInfo);
  if (typeof removeInfo.windowId != 'undefined') {
    chrome.windows.get(removeInfo.windowId, {"populate": true}, function (window) {
      if (typeof window !== 'undefined' && window.type === "normal") {
        setTimeout(function () {
          if (!checkTabIsOurs(window.tabs[0])) {
            createTabInWindow(window);
          } else if (window.tabs.length === 1) {
            createSecondTabInWindow(window);
          }
        }, 400);
      }
    });
  }
}

After a 400 ms delay the script restores a missing tab or adds a second tab when only one remains.

Tab Detach

chrome.tabs.onDetached.addListener(tabDetached);
function tabDetached(tabId, detachInfo) {
  console.info("Tab detached", tabId, detachInfo);
  setTimeout(function () {
    chrome.windows.getAll({populate: true}, initialCheck);
  }, 1000);
  console.info("Checking windows...");
}

A 1 second delay triggers a full window check to re‑establish the required tabs.

Tab Activation

chrome.tabs.onActivated.addListener(tabActivated);
function tabActivated(activeInfo) {
  console.info("Tab activated", activeInfo);
  if (typeof activeInfo.windowId !== 'undefined') {
    chrome.windows.get(activeInfo.windowId, {"populate": true}, function (window) {
      if (window.tabs[0].active === true && window.tabs.length > 1) {
        setTimeout(function () {
          chrome.tabs.update(window.tabs[1].id, {active: true});
        }, 200);
      }
    });
  }
}

If the first tab becomes active while other tabs exist, the script switches focus to the second tab after 200 ms.

Tab Creation

chrome.tabs.onCreated.addListener(checkTab);
function checkTab(tab) {
  console.info("Tab created", tab);
  setTimeout(function () {
    chrome.windows.get(tab.windowId, {"populate": true}, function (window) {
      checkWinowClose(window);
    });
  }, 300);
}

When a new tab appears, the extension waits 300 ms then validates the window’s tab set.

Other Utilities

Additional helper functions ( createTabInWindow , createSecondTabInWindow , checkIfFirstTabIsOurs , checkTabIsOurs , checkWinowClose ) implement the actual tab creation, URL matching via regular expressions, and cleanup of duplicate extension tabs.

The author notes that many features suffer from timeout issues; retry loops increase complexity and contradict the original design intent. Interested readers can contact the author for a revived version of the lastTab extension.

JavaScriptChrome Extensionbrowser-automationManifest V3Tab Management
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.