ESMification update

Skip to first unread message

Tooru Fujisawa

Jun 9, 2022, 4:09:04 PMJun 9
to dev-platform
Hi everyone.

ESMification is a project to switch the Mozilla-specific JSMs in privileged code to the standard ECMAScript modules (ESM).

Recently, the preparatory phase has started to impact larger parts of the codebase. In the interest of keeping everyone informed, we will send out a few updates regarding the transition process. This is the first such update on what's going on and future planning

Ongoing Preparation Work

Preparation work is split into 4 parts.

Add New APIs

Just like `ChromeUtils.import` and friends for JSM, we're going to add new APIs for importing and handling ESMs.

NOTE: the name of the APIs is subject to change

Most of the work is almost ready, and we can land them once the API naming convention gets fixed.

The filename extension for the system (privileged) ESM is `.sys.mjs`.  This is to distinguish between regular ES module files that use `.mjs`.

Add Compatibility Layer for existing APIs

To make the migration easier, and also to avoid breaking out-of-tree code, the existing APIs like `ChromeUtils.import` are automatically redirected to ESM-ified files, if the JSM is already ESM-ified.

This allows migration to be done per single file, or subtree, without affecting other files, or out-of-tree code.

Also, lexical variables in JSM are now exposed to `Cu.import` return value, and there’s no need to copy lexical variables to the global `this` property by ` = foo;`.

Those layers are already available in 103.

Rewrite ESM-incompatible part in JSM

JSM has a per-module global `this` object, which has been used to declare global variables and lazy getters. The standard ECMAScript module does not have the global `this` object, and code that relies on it needs to be rewritten.

Most of the work is almost done, or getting reviewed.

Please refer to the Lazy Getter Update email and the Lazy Getter Implementation document for more information.

Add ESLint rules

We’ll prepare ESLint rules both for JSMs and ESMs.

For JSMs, new rules will be mostly to avoid adding ESM-incompatible code, and some of them will be applied also to ESMs:

For ESMs, new rules will be to catch some edge cases:


In-tree JSM-to-ESM Migration Phase 1

The first phase of the migration covers the following:
  • Rename `*.jsm` to `*.sys.mjs`
  • Replace `EXPORTED_SYMBOLS` with `export` declaration
  • Replace `ChromeUtils.import` for the module with either:
    • static `import` declaration, if it’s in the system ESM’s top-level
    • `ChromeUtils.importESM` otherwise
  • Rewrite lazy getter for the module
  • Rewrite `` for the module
  • Rewrite `components.conf` for the module
  • Rewrite `ChromeUtils.registerWindowActor` for the module
  • Rewrite `ChromeUtils.registerProcessActor` for the module
  • Rewrite `Cu.isModuleLoaded` for the module
  • Rewrite `Cu.loadedModules` for the module

The migration will be semi-automatic, with scripts for simple cases, and manual work for edge cases. Each team will work at their own pace to apply the scripts and identify edge cases. 

It’s not necessary to migrate all JSMs to ESM. Difficult cases can be left as JSM.

We’ll send the detailed document once it’s ready.

In-tree Migration phase 2

Once all in-tree code becomes ESM, each team can rewrite those files to be more standard ESM-style, such as using `export default` etc.

Out-of-tree Migration

There are multiple out-of-tree consumers of JSM:
  • Firefox’s privileged extensions
  • Thunderbird’s extensions
  • non-sandboxed AutoConfig scripts

And we need to keep the compatibility with them.

During the in-tree migration phase 1, the above compatibility layer guarantees the compatibility as long as:
  • The set of exported symbols is same
  • The behavior of the exported symbols is same
  • The URL is same, except for the extension part (`.jsm` to `.sys.mjs`)

Once the in-tree migration phase 1 finishes, we’ll call for the out-of-tree migration, to use the new APIs.

The out-of-tree code migration period will take some cycles.

Cleanup on the API

Once the out-of-tree migration finishes, we’ll perform cleanup, including gradually removing the deprecated APIs or special behavior around that:

Non-deprecated JSM APIs such as `ChromeUtils.import` aren’t removed, for in-tree difficult-to-migrate cases, and also for out-of-tree compatibility.

Reply all
Reply to author
0 new messages