developer.chrome.com icon indicating copy to clipboard operation
developer.chrome.com copied to clipboard

Describe the behaviors of extension service workers in more detail

Open dotproto opened this issue 3 years ago • 10 comments

Is your feature request related to a problem? Please describe. The current extensions documentation for service workers does not adequately cover their features, capabilities, behaviors, and limitations.

Describe the solution you'd like Revise or rewrite this article to address topics including

  • Basics / overview
    • The service worker lifecycle
      • Event-based
      • Shuts down when idle
      • Forcibly terminated after 5 minutes
      • Extended lifetimes for native messaging ports
    • Scoped service workers
      • Can't access chrome global
      • Can handle network requests for registered subpath
  • Event listener requirements
    • Must be registered on the first turn of the event loop
  • Divergence from the open web
    • How extension service worker installation and update process
      • Extension platform handles SW registration and update - devs don't need to (shouldn't) use navigator.serviceworker.register()
    • Devs don't have to install & update the SW manually (can't, actually)
    • fetch event handler(?)
      • Note: I think I saw some unexpected behavior here. Possibly related to WAR? Needs to investigation.
  • Loading multiple files
    • Classic scripts use importScripts()
    • Module scripts use import statements
    • Note: dynamic import() maybe???
    • Techniques to minimize startup time
      • Wrap code that don't necessarily need to be executed on startup in a function
  • Debugging extension service workers
    • Performance analysis (workarounds)
  • Behavior differences for unpacked extensions
    • runtime.reload() will pick changes from disk, may require SW to restart
      • Note: Need to investigate impact of iframed extension pages.
    • "the current implementation of extension ServiceWorker … updates every 5-6 minutes" (per @guest271314)

dotproto avatar Jun 10 '22 19:06 dotproto

Devs don't have to install & update the SW manually (can't, actually)

What is meant here? Yes, the ServiceWorker can be uppdated manually.

Extended lifetimes for native messaging ports

Has this https://github.com/GoogleChrome/developer.chrome.com/issues/2688 been fixed? Or are you just compounding a qualified claim?

guest271314 avatar Jun 12 '22 15:06 guest271314

Extended lifetimes for native messaging ports

That language does not look accurate.

Native Messaging ports do not have a lifetime.

Did you mena extending the active state of MV3 ServiceWorker when/while Native Messaging port is open?

guest271314 avatar Jun 12 '22 19:06 guest271314

What is meant here? Yes, the ServiceWorker can be uppdated manually.

When I last looked into this I seem to recall Chrome throwing an error that started something to the effect that that this operation is not allowed. Do you happen to have a demo handy, @guest271314?

Has this #2688 been fixed? Or are you just compounding a qualified claim?

There has been doing progress in the relevant Chromium issue, but more broadly our documentation primarily focuses on how we intend for the platform to behave. In this case the underlined bug has not been fully resolved (and I expect to include a note to that effect) but we still need to communicate what developers should expect.

That language does not look accurate. …

Did you mena extending the active state of MV3 ServiceWorker when/while Native Messaging port is open?

That bulleted list was a rough outline of the article content that I sketched out over a few minutes as I prepared the issue.

As you guessed, I was referring to extending the service workers lifetime rather than commenting on the native messaging port’s lifetime.

dotproto avatar Jun 12 '22 22:06 dotproto

chrome.runtime.reload() unless you mean something else by

(can't, actually)

I would be careful with language re ServiceWorker being active/non-active. As per specification it is not intended to be active persistently. However, when you make claims that infer developers in the field can make MV3 ServiceWorker persistent, that should work without caveats or further explanation; else the false claims are just compunded when put to the test in the field.

https://github.com/mdn/content/issues/12370#issuecomment-1020220649

The service worker is not supposed to stay alive, and attempts to make it stay alive will be buggy.

Shared workers however do stay alive.

If you think extensions should be able to use shared workers, that's something to propose to extension folks.

guest271314 avatar Jun 12 '22 22:06 guest271314

chrome.runtime.reload() unless you mean something else by

(can't, actually)

I meant something else. I was referring to the way that developers register and update service workers on the open web. That pattern does not apply to extensions because extensions use a different installation and update model. In extensions, the browser is responsible for registering and updating an extension's service worker.

dotproto avatar Jun 13 '22 21:06 dotproto

chrome.runtime.reload() unless you mean something else by

(can't, actually)

I meant something else. I was referring to the way that developers register and update service workers on the open web. That pattern does not apply to extensions because extensions use a different installation and update model. In extensions, the browser is responsible for registering and updating an extension's service worker.

I think you should make it clear that you are referring to Chrome Web Store or other third-party installation methods.

In Developer mode we install unpacked extensions and have total control over updating and modifying the extension and ServiceWorker.

Your language appears to be entirely scoped towards Chrome Web Store extensions.

guest271314 avatar Jun 14 '22 00:06 guest271314

In extensions, the browser is responsible for registering and updating an extension's service worker.

I still don't think that is entirely correct. A developer can update their unpacked extension at any time. In the case of an extension the "update" is simply reloading the extension; whether changes are made to the source code or not.

Technically, the current implementation of extension ServiceWorker on Chromium/Chrome updates every 5-6 minutes.

guest271314 avatar Jun 14 '22 03:06 guest271314

Your language appears to be entirely scoped towards Chrome Web Store extensions.

Signed .crx packages are the only officially supported distribution mechanism for extensions. Loading an unpacked extension is intended as a developer capability and should not be used by the average user. Documentation on developer.chrome.com should reflect this perspective.

That said, I agree that we should provide more guidance for developers regarding the differences between running packed and unpacked extensions. I've added a top level bullet tentatively titled "Behavior differences for unpacked extensions" to the outline to cover this information.

dotproto avatar Jun 14 '22 20:06 dotproto

Loading an unpacked extension is intended as a developer capability and should not be used by the average user. Documentation on developer.chrome.com should reflect this perspective.

I don't think that is a valid perspective. Why should users trust Chrome Web Store and not their own local installation?

guest271314 avatar Jun 20 '22 13:06 guest271314

Techniques to minimize startup time Wrap code that don't necessarily need to be executed on startup in a function

The title is great, but it's much more complicated.

  1. Even with a trivial extension there's the overhead to start the worker, at least 50ms, which may exceed the time spent in the background script by such a great margin that any optimization of JS is essentially moot.

  2. Postponing won't help reducing the potentially huge load/preparse/parse/compile time before the script even runs. In many extensions it may easily take half a second for a moderate bundle on an average notebook.

  3. It's often impossible to postpone the code e.g. if it's used to rehydrate the state from db/websocket/whatever. There is a limit to what you can achieve by reworking the architecture of the storage or the entire extension and the latter is not always possible due to the lack of a necessary API in Chrome e.g. extensions like Stylus or DarkReader can't rely on chrome.scripting.registerContentScripts as it can't register a dynamically constructed CSS string, so they have to read all the styles and compile their matching rules to find out which of them to apply to the network request that woke the SW. It takes 200-500ms from the moment the navigation occurred (including 50ms of the SW spin-up time) depending on the amount and complexity of the styles. Obviously too long to be usable for fast modern SPA sites that use SW caching.

To reiterate, none of this matters for simple extensions that take much less than 50ms to initialize after SW started as measured in devtools timeline/profiler for the SW context from the moment their SW script is getting loaded from disk.

Here's some impactful solutions for extensions with a huge background script:

  1. Don't put the code in SW context, duh, simple as that. Many advanced web developers mistakenly treat the background script as a "back-end" API server and just put almost everything there. The solution would be to try extracting the parts used only by the popup or the options or another visible page - the things that don't have to run after the view is closed. Split the things that need to run longer, there shouldn't be a lot of them usually.

  2. Use dynamically loaded modules. It's unnecessarily complicated though:

    • importScripts can only work in classic mode
    • MV3 still doesn't have dynamic import() in SW
    • to use importScripts dynamically one needs to duplicate it in self.onstall event per the SW specification to make sure the remote code is cached (which is entirely irrelevant for extensions as they are local and yet this quirk is being enforced thus crippling developer experience). FWIW, the same restriction will apply to the dynamic import in SW when it's added to the web platform.
    • no plugin for webpack/rollup/parcel/react etc. that uses the double-importScripts "trick" which means all this jumping through the hoops is for a few enthusiasts.

tophf avatar Oct 06 '22 22:10 tophf

@jpmedley Should we close this issue? Seems like these topics were addressed in the service worker collection?

AmySteam avatar Aug 08 '23 21:08 AmySteam

I think it's safe to close it. I'm going to verify this list against our whole doc set because I don't think we covered it in quite the way Simeon outlined it. I'll open a new ticket with anything that's missing.

jpmedley avatar Aug 09 '23 14:08 jpmedley