ES Modules for Shared Workers

Author: elkurin@chromium.org (Eriko Kurimoto)

Last update: Feb 18, 2019

Status: Shipped in M82

Tracking bug: https://crbug.com/824646

Chrome Platform status: https://chromestatus.com/feature/5169440012369920

Summary

Chrome browser supports module scripts loading in shared workers. When the ‘module’ type is set on the constructor’s type attribute, worker scripts are loaded as ES modules and the import statement is available on worker contexts.

const worker =

    new SharedWorker(‘worker.js’, { name: ‘worker-name’, type: ‘module’});                  

The specification of this feature is here.

Scope

As of today we support 3 workers: Dedicated Workers, Shared Workers, and Service Workers. Each worker has a different script loading model and implementation. ES modules used to be supported only by Dedicated Workers (ES modules for Dedicated Workers). As a next step, we target Shared Workers that has a similar loading mechanism to Dedicated Workers.

How to use module Shared Workers

Traditionally, we use Shared Workers as follows:

const worker = new SharedWorker(‘worker.js’, ‘worker-name’);

This construction only works for classic script loading. The second argument of SharedWorker constructor used to take only DOMString as a worker’s name. Now, it takes DOMString OR WorkerOptions. (spec for WorkerOptions)

dictionary WorkerOptions {

  WorkerType type = "classic";

  // credentials is only used if type is ‘module’

  RequestCredentials credentials = "same-origin";

  DOMString name = "";

};

enum WorkerType {‘classic’, ‘module’};

enum RequestCredentials {‘include’, ‘same-origin’, ‘omit’};

To use module Shared Workers, you need to set WorkerOptions’ type attribute to ‘module’ when you construct a shared worker. In WorkerOptions, credentials mode can also be specified from {‘include’, ‘same-origin’, ‘omit’}:

const worker = new SharedWorker(‘worker.js’,

                                { name: ‘worker-name’,

                                  type: ‘module’,

                                  credentials: ‘same-origin’});

We continue to support DOMString name as the second argument of SharedWorker constructor and the default value of type attribute is ‘classic’, so the behavior of the traditional way of constructing SharedWorker (as below) doesn’t change.

const worker = new SharedWorker(‘worker.js’, ‘worker-name’);

// new SharedWorker(‘worker.js’, { name: ‘worker-name’, type: ‘classic’ });

Design

Module scripts loading for Dedicated Worker (no changes from current impl)

In Dedicated Worker, a worker thread is in the same renderer process with the main thread which calls a dedicated worker. Scripts loading for Dedicated Workers works as below:

Module scripts loading for Shared Worker (new code path)

As for Shared Workers, on the other hand, a worker thread could be in a different process with the main thread which calls a worker. The Shared Worker process can be accessed from more than one renderer process, so we need to find the Shared Worker process from the browser process. SharedWorkerServiceImpl finds the shared worker host[a][b][c][d][e][f]. It registers the renderer client if the corresponding thread exists, or creates a new thread if not. After finding the host, SharedWorkerHost sends the information to the main thread including the matching worker thread. Through this communication, script type and credentials mode parameters which are given by the constructor must be carried. These parameters are not used during this flow. After this step, the script loading mechanism is the same for Dedicated Workers. Therefore, the implementation for script fetching is using the same code path to Dedicated Workers.

Script loading for Shared Workers works as below:

The codes added in new code path is listed below:

  • Added script type and credentials mode arguments to functions through the loading
  • Codes to fit parameters to the communication format between processes
  • Added FetchAndRunModuleScript() at the end of module script loading path

Implementation plans

Our implementation plans are follows:

  1. Support WorkerOptions argument to Shared Worker’s constructor (crbug)
  2. Pass ‘credentials’ and ‘type’ params to the browser process
  3. Pass ‘credentials’ and ‘type’ params to a worker thread
  4. Support ‘credentials’ param in WorkerOptions for Shared Workers top-level script and static import
  5. Support ‘type’ param in WorkerOptions for Shared Workers static import
  6. Support dynamic import

Testing plans

Module scripts via <script> tag have already shipped in major browsers and there are plenty of web-platform-tests for it.

As for ES modules for Shared Workers, we added web-platform-test in workers/modules directory to test its behavior. SharedWorker cannot be nested nor called from Dedicated Workers, so there are no tests for constructing SharedWorker from workers.

Also we have web-platform-tests for ES modules for SharedWorker here as well: referrer-policy,  mixed-content, upgrade-insecure-request.

Metrics

Our main measure of success is a use counter for the constructor. This use counter is called when constructing a SharedWorker. If it is called without WorkerOption, it is distinguished as classic script loading since the default value of type attribute is ‘classic’. 

You can see the chromestatus here: https://chromestatus.com/feature/5169440012369920

Concerns

Not only module Shared Workers, Shared Workers itself is not yet supported in some browsers including Safari and Android Browser. From the interoperability perspective, this feature will not be supported by other browsers soon. However, module script loading for Dedicated Workers is already shipped and the worker spec has been discussed with other browser vendors and reached consensus.

[a]Is the matching mechanism changed (e.g. do type and credentials mode affect matching)? Or the additional parameters are just passed through browser process as-is without no additional impl/behavior changes?

[b]Currently, the matching mechanism is not changed. This is according to the spec. I'll make that clear in Doc.

But there is an ongoing spec issue whether we use the type value for matching or not (https://github.com/whatwg/html/issues/5235)

[c]_Marked as resolved_

[d]_Re-opened_

[e]_Marked as resolved_

[f]_Re-opened_