awesome-webextension / webpack-target-webextension

WebExtension Target for Webpack 5. Supports code-splitting and HMR.
MIT License
44 stars 5 forks source link

Not support MV3 native ES background worker #24

Open Jack-Works opened 2 years ago

Jack-Works commented 2 years ago

Blocked by https://github.com/w3c/ServiceWorker/issues/1356, otherwise, we need to emit import statements which is not easy in a webpack bundle.

fregante commented 7 months ago

I read your comment in the release notes. It's technically right that the worker only supports importScripts, but not if the file itself was already imported via importScripts

My setup looks like:

  "background": {
    "service_worker": "background.worker.js",
  },
// background.worker.js
self.importScripts("./background.js");

Where:

In my case I think it's failing because serviceWorkerEntry: 'background' will change the primary loading style, which isn't available past the first background.worker.js

For my use case (i.e. adding the onMessage handler to run executeScripts), I think that maybe it already works with this, regardless if manifest version:

      new WebExtensionTarget({
        weakRuntimeCheck: true,

        // Required to support sandboxed iframes
        // https://github.com/awesome-webextension/webpack-target-webextension/pull/42
        background: {
          pageEntry: "background",
        },
      }),
fregante commented 7 months ago

I think that maybe it already works with this, regardless if manifest version:

Yep: https://github.com/pixiebrix/pixiebrix-extension/pull/7472

Jack-Works commented 7 months ago

I'm unsure if your comment relates to this issue, but I'll write down what I recently found as a memo.

Firstly, Chrome supports service workers with native ES modules now, you need to write your manifest like this:

  "background": {
    "service_worker": "background.worker.js",
    "type": "module"
  },

Then the service worker can use import or export statements, not importScripts.

Currently, we use JSONP-style (the default of webpack) to load chunks, this way works well, so even if this issue is not resolved, this plugin is ok to use.

// JSONP-style chunk format
"use strict";
(globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push(...)

As an ES Module enthusiast, I hope we can support ES Module as the chunk format, and also as the chunk loading format.

// ES Module chunk format
export const id = 232;
export const ids = [232];
export const modules = {

/***/ 232:
/***/ (() => {
/***/ })

};

If the chunk format becomes ESM, the only way to load it is static import or dynamic import.

Dynamic import already works to load JSONP-style chunks in the content script (https://github.com/awesome-webextension/webpack-target-webextension#content-script), the problem is dynamic import is not allowed in an ES Module service worker even if the dynamic import is called before first event loop ends. This requires me to emit not dynamic import, but static imports. Webpack now only supports dynamic import (see __webpack_require__.f.j if you're interested) those chunks.

This becomes harder, but not impossible. I think it needs a lot of time to figure out how to make this work. I can emit import statements at the top level, but I need to know their file name, but unluck, file names are generated from a runtime function (__webpack_require__.u) and it's very hard to do it in the compile time.

Since everything works well today, this is not very urgent to fix.

fregante commented 7 months ago

Then the service worker can use import or export statements, not importScripts.

That's very good to know. Parcel forced me to use that syntax but never investigated it. I'll start using it in webpack too because importScript breaks "Pause on uncaught errors" in the dev tools, because the debugger pauses on importScript, regardless of the actual position and source maps.

fregante commented 7 months ago

dynamic import

That didn't seem to work for me 🤷‍♂️ I got the same error as before

Screenshot

Changing it to import statement fixed it.


So technically now I'm using a native ES background worker in webpack-target-webextension. This issue is fixed? Maybe it just needs some documentation?

Jack-Works commented 7 months ago

Native ES service worker works, dynamic import does not.

While using this plugin, compiled ES modules (including dynamic import) work after bundling, loading by importScritps. Native ES service worker does not work with this plugin currently (the screenshot you gave).