Normally, when you develop content scripts, you’d need to reload the extension in chrome://extensions to see the changes. A simple page reload is not enough.

Here’s a workaround: Use a content script wrapper which tells the background script to inject the real content script using chrome.scripting. This way, the latest version of the content script is loaded without the need to reload the extension.

Sequence digram visualizing the above sentence.

It looks like this.

chrome.runtime.sendMessage({ pageLoaded: true })

Then on the background script, inject content script from there:

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.pageLoaded) {
    if (sender.tab && sender.tab.id != null) {
      chrome.scripting.executeScript({
        target: {
          tabId: sender.tab.id,
        },
        files: ['/dist/content-script.js'],
      })
    }
  }
})