Skip to content

Worker modules #550

@domenic

Description

@domenic

In the epic #443, we added <script type="module"> to allow execution of scripts using the ES Module syntactic goal and semantics. Previously, in https://www.w3.org/Bugs/Public/show_bug.cgi?id=22700, there was discussion of allowing modules to be the entry point for workers as well. That thread is pretty long though, and the worker-modules idea there was actually a tangent off of the original thread of "inline workers" (i.e. workers without an external file). So let me start a new thread over here specifically focused on worker modules.

My original thought process was to let <script type="module"> sink in for a while, get implemented, and then extend to workers. But @bterlson (Chakra team) pointed out to me that implementers would probably be better served by having an idea what's coming, either so they can implement both at once or so they can at least architect their code to be ready.

I think the best idea is to extend the Worker (and SharedWorker and ServiceWorker and...) constructors: either new Worker(scriptURL, { type: "module" }) or new Worker(scriptURL, { module: true }). The type variant is probably more future-friendly (imagine in the future new Worker(scriptURL, { type: "wasm" }) or similar). But we'd have to decide how much to parallel the <script type=""> attribute, e.g.: do we say that any JavaScript MIME type maps to a classic script worker? do we say that anything that isn't a JavaScript MIME type or "module" is ignored? or throws? Maybe it would be cleaner to pick a new word like new Worker(scriptURL, { mode: "module" }).

Here are some questions that might be debatable, and possible answers for them:

  1. Should we do MIME type checking for module workers? (Classic workers do not; module scripts do per Add <script type="module"> and module resolution/fetching/evaluation #443.) I think we should; we should in general add stricter MIME type checking to all new features.
  2. Should we make import parallel importScripts and be synchronous, instead of the async two-stage process we have for module scripts? This would in particular impact code interleaved between import statements: in import './a.js'; foo(); import './b.js';, is performing foo() blocked on fetching b, or does it execute as soon as a is fetched and executed? (It would not prevent the UA from prefetching and crawling a module tree starting at a module worker.) I think we should probably just stick with the two-stage process from module scripts, since I can't see any real use cases for the sync loading and it seems better to be consistent to avoid potential developer confusion between the different models.
  3. Should we disallow importScripts inside a module worker? I think we should probably be fine allowing it; in theory authors should probably use import instead, but in practice maybe they want to mix and match with classic scripts designed for importScripts usage.
  4. Should new worker constructors automatically be modules, possibly with ability to change? It's probably too late for ServiceWorker and SharedWorker, but some of the Houdini stuff might want to go this route.

I think the actual spec will not be very hard; worker loading is a much smaller portion of the spec, with fewer switches and dials and historical accidents, than script loading. If implementers would like to see a spec, please chime in and I can work on this. Or if you just want to know the general shape of the plans, I think the above sums it up. Let me know.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions