'How to chrome.runtime.reload() a Chrome Extension when building it with Webpack 5 Boilerplate?

I am using https://github.com/lxieyang/chrome-extension-boilerplate-react as the basis to build a chrome extension. It all works fine, and everything does hot-reloading (popup, background, options, newtab) except for the content-script. Reloading the matching pages, does not reload the underlying .js. It takes to reload/turn-off-on the whole extension in order for the changes to go into effect.

So, in webpack.config.js i commented out 'contentScript' hoping for it to fix that, but it makes no difference.

...
chromeExtensionBoilerplate: {
  notHotReload: [
    //'contentScript'
  ],
},
...

In src/pages/Content/index.js it actually states

console.log('Must reload extension for modifications to take effect.');

When developing another extension in plain vanilla js, i dropped a hot-reload.js from https://github.com/xpl/crx-hotreload which worked perfectly. From what i understand it is the 'chrome.runtime.reload()' call that makes chrome completely reload the extension.

So my question(s) actually is:

  • When changing src/pages/Content/index.js, webpack does re-build the build/contentScript.bundle.js. But why doesn't manually reloading the tab/page recognize these changes, when for popup, background, etc. it does?
  • And if there is no way to let the above boilerplate reload the extension (i don't mind the hard reload) how would i be able to integrate the hot-reload.js (or its effect actually) into this boilerplate? That is, how do i reload the extension when build/contentScript.bundle.js is changed?

Thanks in advance!



Solution 1:[1]

For who is interested. I ended up placing mentioned hot-reload.js in my extension, and loading it from within the background script. That breaks webpack's hot-reloading, by reloading the entire extension on any file-change. But as long as i only work on the content script, thats fine. I can remove it once im done, or if i work on other scripts.

Solution 2:[2]

Use server-sent-events:

const SSEStream = require('ssestream').default;
let sseStream;
...
setupMiddlewares: (middlewares, _devServer) => {
  if (!_devServer) {
    throw new Error('webpack-dev-server is not defined');
  }
  /** ???/reload path SSE */
  middlewares.unshift({
    name: 'handle_content_change',
    // `path` is optional
    path: '/reload',
    middleware: (req, res) => {
      console.log('sse reload');
      sseStream = new SSEStream(req);

      sseStream.pipe(res);
      res.on('close', () => {
        sseStream.unpipe(res);
      });
    },
  });

  return middlewares;
}
  • webpack.compiler.hook
let contentOrBackgroundIsChange = false;
compiler.hooks.watchRun.tap('WatchRun', (comp) => {
  if (comp.modifiedFiles) {
    const changedFiles = Array.from(comp.modifiedFiles, (file) => `\n  ${file}`).join('');
    console.log('FILES CHANGED:', changedFiles);
    if(watchRunDir.some(p => changedFiles.includes(p))) {
      contentOrBackgroundIsChange = true;
    }
  }
});

compiler.hooks.done.tap('contentOrBackgroundChangedDone', () => {
  if(contentOrBackgroundIsChange) {
    contentOrBackgroundIsChange = false;
    console.log('--------- ?? chrome reload ?? ---------');
    sseStream?.writeMessage(
      {
        event: 'content_changed_reload',
        data: {
          action: 'reload extension and refresh current page'
        }
      },
      'utf-8',
      (err) => {
        sseStream?.unpipe();
        if (err) {
          console.error(err);
        }
      },
    );
  }
});
if(process.env.NODE_ENV === 'development') {
    const eventSource = new EventSource(`http://${process.env.REACT_APP__HOST__}:${process.env.REACT_APP__PORT__}/reload/`);
    console.log('--- start listen ---');
    eventSource.addEventListener('content_changed_reload', async ({ data }) => {
        const [tab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true });
        const tabId = tab.id || 0;
        console.log(`tabId is ${tabId}`);
        await chrome.tabs.sendMessage(tabId, { type: 'window.location.reload' });
        console.log('chrome extension will reload', data);
        chrome.runtime.reload();
    });
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 spaxxUnited
Solution 2 godis