Port closed before response. Extensions won't work

I am creating an extension for Chrome which can reorder the content of a page, specifically videos from TikTok. The goal is that when a user searches for something, e.g. chatgpt, the videos appear in a random order. When the user clicks the extension’s “Sort by Likes” button, the videos should be re-ordered according to the number of likes, either in ascending (ASC) or descending (DESC) order.

So far I have created and initialized the project, but I am encountering an error when I click the “Sort by Likes” button. The error message is: Error: The message port closed before a response was received.

The code I am using is as follows:

//manifest.json
{
    "manifest_version": 3,
    "name": "Sorer",
    "version": "1.0",
    "description": "Sort TikTok videos by likes, comments, and views",
    "icons": {
      "16": "icon.png",
      "48": "icon.png",
      "128": "icon.png"
    },
    "permissions": [
        "activeTab",
        "tabs",
        "scripting",
        "webNavigation"
    ],
    "content_scripts": [
        {
          "matches": ["<all_urls>"],
          "js": ["content.js"]
        }
      ],
    "background": {
        "service_worker": "background.js"
    },
    "action": {
      "default_popup": "popup.html",
      "default_title": "Sorter - TikTok Sorter"
    },
    "host_permissions": [
        "<all_urls>"
    ]
  }
  
// popup.js
document.addEventListener("DOMContentLoaded", function () {
    const sortButton = document.getElementById("sortButton");
    sortButton.addEventListener("click", function () {
      chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
        chrome.tabs.sendMessage(tabs[0].id, { action: "sortVideos", property: ".tiktok-ws4x78-StrongVideoCount" }, function (response) {
          if (chrome.runtime.lastError) {
            // Handle the error gracefully
            console.error("Error: " + chrome.runtime.lastError.message); 
          } else if (response && response.error) {
            // Handle the response error
            console.error("Error: " + response.error);
          } else {
            // Handle the successful response
            console.log("Sorting successful");
          }
        });
      });
    });
  });
// background.js
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
    if (changeInfo.status === "complete" && tab.url.includes("tiktok.com") && tab.url.includes("/search")) {
      console.log("Tab updated:", tabId, tab.url);
      chrome.scripting.executeScript(
        {
          target: { tabId: tabId },
          files: ["content.js"],
        },
        function () {
          if (chrome.runtime.lastError) {
            console.error(chrome.runtime.lastError);
          } else {
            console.log("Content script executed successfully");
            chrome.tabs.sendMessage(tabId, { action: "sortVideos", property: "tiktok-ws4x78-StrongVideoCount" }, function (response) {
              if (chrome.runtime.lastError) {
                console.error("errorr2200" + chrome.runtime.lastError);
              } else if (response && response.error) {
                console.error("Error110" + response.error);
              } else {
                console.log("Received response:", response);
              }
            });
          }
        }
      );
    }
  });
// content.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    if (message.action === "sortVideos") {
      const property = message.property;
      const videos = document.querySelectorAll('[data-e2e="search_top-item"]');
      const sortedVideos = Array.from(videos).sort((a, b) => {
        const aData = parseFloat(a.querySelector(`${property}`).innerText.replace(/[^\d.-]/g, ''));
        const bData = parseFloat(b.querySelector(`${property}`).innerText.replace(/[^\d.-]/g, ''));
        return bData - aData;
      });
      sortedVideos.forEach((video) => {
        const parent = video.parentNode;
        parent.removeChild(video);
        parent.prepend(video);
      });
      sendResponse({ success: true });
    }
  });

I am trying to create an extension for Chrome which can reorder the content of a page, specifically videos from TikTok. When a user searches for something, e.g. chatgpt, the videos should appear in a random order. When the user clicks the extension’s “Sort by Likes” button, the videos should be re-ordered according to the number of likes, either in ascending (ASC) or descending (DESC) order.

However, I am getting the error Error: The message port closed before a response was received. when I click the “Sort by Likes” button. Can anyone please help me figure out how to get the number of likes for each search result and to sort them?

To fix the error Error: The message port closed before a response was received. and get the number of likes for each search result, you need to make the following changes to your code:

  1. In background.js, modify the chrome.tabs.onUpdated.addListener callback function to check for the button click event and send a message to the content script:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
  if (changeInfo.status === "complete" && tab.url.includes("tiktok.com") && tab.url.includes("/search")) {
    console.log("Tab updated:", tabId, tab.url);
  }
});

chrome.action.onClicked.addListener(function(tab) {
  chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
    if (tabs[0].id === tab.id) {
      chrome.tabs.sendMessage(tab.id, { action: "sortVideos", property: ".tiktok-ws4x78-StrongVideoCount" }, function (response) {
        if (chrome.runtime.lastError) {
          console.error("Error: " + chrome.runtime.lastError.message); 
        } else {
          console.log("Sorting successful");
        }
      });
    }
  });
});
  1. In content.js, modify the chrome.runtime.onMessage.addListener callback function to handle the sortVideos action and send the sorted videos back as a response:
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
  if (message.action === "sortVideos") {
    const property = message.property;
    const videos = document.querySelectorAll('[data-e2e="search_top-item"]');
    const sortedVideos = Array.from(videos).sort((a, b) => {
      const aData = parseFloat(a.querySelector(`${property}`).innerText.replace(/[^\d.-]/g, ''));
      const bData = parseFloat(b.querySelector(`${property}`).innerText.replace(/[^\d.-]/g, ''));
      return bData - aData;
    });
    sortedVideos.forEach((video) => {
      const parent = video.parentNode;
      parent.removeChild(video);
      parent.prepend(video);
    });
    sendResponse({ success: true });
  }
});

Make sure to update your manifest.json file with the modified background.js file:

// manifest.json
{
  "manifest_version": 3,
  "name": "Sorter",
  "version": "1.0",
  "description": "Sort TikTok videos by likes, comments, and views",
  "icons": {
    "16": "icon.png",
    "48": "icon.png",
    "128": "icon.png"
  },
  "permissions": [
    "activeTab",
    "tabs",
    "scripting",
    "webNavigation"
  ],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html",
    "default_title": "Sorter - TikTok Sorter"
  },
  "host_permissions": [
    "<all_urls>"
  ]
}

With these changes, the error should be resolved and the videos will be sorted according to the number of likes when the “Sort by Likes” button is clicked.