Deferred re-exports
update since last plenary
�export defer … from
Nicolò Ribaudo (Igalia, in partnership with Bloomberg)
Last plenary summary
In November the proposal did not advance to Stage 2.7 over concerns with:
We are working on this.
2
The "performance cliff"
3
The "performance cliff"
4
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
Loading
Execution
Initial
// library
export { something } from "./util-1";
export { other } from "./util-2";
export const mainThing = /* ... */
// app.js
import { mainThing } from 'library';
$button.onclick = () => {
use(mainThing);
};
The "performance cliff"
5
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
Loading
Execution
Happening later
Initial
import defer
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
// library
export { something } from "./util-1";
export { other } from "./util-2";
export const mainThing = /* ... */
// app.js
import defer * as lib from 'library';
$button.onclick = () => {
use(lib.mainThing);
};
The "performance cliff"
6
// library
export defer { something } from "./util-1";
export defer { other } from "./util-2";
export const mainThing = /* ... */
// app.js
import { mainThing } from 'library';
$button.onclick = () => {
use(mainThing);
};
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
Loading
Execution
Happening later
Initial
export defer
_library_
_library_
The "performance cliff"
7
// library
export defer { something } from "./util-1";
export defer { other } from "./util-2";
export const mainThing = /* ... */
// app.js
import defer * as lib from 'library';
$button.onclick = () => {
use(lib.mainThing);
};
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
Loading
Execution
Happening later
Initial
import defer export defer
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
The "performance cliff"
8
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
Initial
export defer
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
Loading
Execution
Happening later
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library_
import defer *�export defer
import defer *
Some draft ideas for solutions
9
They all need more concrete details: please join the Module Harmony calls if you are interested in discussing them
Option 1: export defer is just about execution
export defer was born as the export version of import defer: should we go back to its origin?
Like import defer, it would defer execution when used with module namespaces, but it would not affect loading.
10
Option 1
11
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
Initial
import defer *
export defer�(current)
export defer�(new)
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
Loading
Execution
Happening later
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library_
import defer *�export defer
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
Option 2: allow listing names with "namespace" imports
The reason import defer uses * as ns is not because it needs to import everything, but it's because it needs an object to anchor execution to.
Can we get an object while still having a list of imported names?
import { mainThing, other } as lib from 'library';
Bonus: export defer right now cannot skip loading with dynamic imports, and this would allow it:
const lib = await import('library', { select: ['mainThing', 'other'] });
12
Option 2
13
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
Initial
import defer *
export defer
Loading
Execution
Happening later
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
import defer { mainThing } as …�export defer
_library_
_library_
import { mainThing }
export defer
_library_
_library_
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
import defer *
Option 3: namespace imports do not load defer re-exports
Deferred re-exports would keep following the rule that they are only loaded if they are explicitly named: * is not explicitly naming anything, so it does not load them. Same applies to dynamic import().
lib.other is available, but lib.something would be in TDZ until when something else causes it to be loaded.
Maybe some way (an attribute?) to allow explicitly listing some names.
14
// library
export defer { something } from "./util-1";
export { other } from "./util-2";
// app.js
import * as lib from 'library';
Option 3
15
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
Initial
import *
export defer
Loading
Execution
Happening later
_library_
_library/_�_util-1_
_library/_�_util-2_
_library_
_library/_�_util-1_
_library/_�_util-2_
import defer *
export defer
_library_
_library_
import { mainThing }
export defer
_library_
_library_
import defer *
_library_
_library_
Feedback?
16
+ please join the Module Harmony calls if you are interested in discussing more