Skip to content

Commit

Permalink
Bundles can be sync or async based on top level await
Browse files Browse the repository at this point in the history
Previously, bundles always utilised top level await, even if the bundled
modules didn't require top level await.  Now, analysis of the bundle is
done and if none of the bundled modules are asynchronously executed,
then the bundle as a whole will be synchronously executed.

Fixes denoland#4055
Fixes denoland#4123
  • Loading branch information
kitsonk committed Feb 25, 2020
1 parent 805992b commit d2dab38
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 30 deletions.
13 changes: 11 additions & 2 deletions cli/js/compiler_bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,16 @@ export function buildBundle(
rootName = normalizeUrl(rootName)
.replace(sharedPath, "")
.replace(/\.\w+$/i, "");
// If one of the modules requires support for top-level-await, TypeScript will
// emit the execute function as an async function. When this is the case we
// need to bubble up the TLA to the instantiation, otherwise we instantiate
// synchronously.
const hasTla = data.match(/execute:\sasync\sfunction\s/);
let instantiate: string;
if (rootExports && rootExports.length) {
instantiate = `const __exp = await __inst("${rootName}");\n`;
instantiate = hasTla
? `const __exp = await __inst("${rootName}");\n`
: `const __exp = __inst_s("${rootName}");\n`;
for (const rootExport of rootExports) {
if (rootExport === "default") {
instantiate += `export default __exp["${rootExport}"];\n`;
Expand All @@ -53,7 +60,9 @@ export function buildBundle(
}
}
} else {
instantiate = `await __inst("${rootName}");\n`;
instantiate = hasTla
? `await __inst("${rootName}");\n`
: `__inst_s("${rootName}");\n`;
}
return `${SYSTEM_LOADER}\n${data}\n${instantiate}`;
}
Expand Down
68 changes: 40 additions & 28 deletions deno_typescript/system_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,13 @@
// This is a specialised implementation of a System module loader.

// eslint-disable-next-line @typescript-eslint/no-unused-vars
let System;
let __inst;
let System, __inst, __inst_s;

(() => {
const mMap = new Map();
System = {
register(id, deps, f) {
mMap.set(id, {
id,
deps,
f,
exp: {}
});
register(id, d, f) {
mMap.set(id, { id, d, f, exp: {} });
}
};

Expand All @@ -28,11 +22,10 @@ let __inst;
};
};

const gE = data => {
const { exp } = data;
return (id, value) => {
const values = typeof id === "string" ? { [id]: value } : id;
for (const [id, value] of Object.entries(values)) {
const gE = ({ exp }) => {
return (id, v) => {
const vs = typeof id === "string" ? { [id]: v } : id;
for (const [id, value] of Object.entries(vs)) {
Object.defineProperty(exp, id, {
value,
writable: true,
Expand All @@ -47,39 +40,58 @@ let __inst;
const enq = ids => {
for (const id of ids) {
if (!iQ.includes(id)) {
const { deps } = mMap.get(id);
const { d } = mMap.get(id);
iQ.push(id);
enq(deps);
enq(d);
}
}
};

const dr = async main => {
const gRQ = main => {
const rQ = [];
let id;
while ((id = iQ.pop())) {
const m = mMap.get(id);
const { f } = m;
if (!f) {
return;
}
rQ.push([m.deps, f(gE(m), gC(m, id === main))]);
m.f = undefined;
const m = mMap.get(id),
{ f } = m;
if (!f) return;
rQ.push([m.d, f(gE(m), gC(m, id === main))]);
delete m.f;
}
return rQ;
};

const dr = async main => {
const rQ = gRQ(main);
let r;
while ((r = rQ.shift())) {
const [deps, { execute, setters }] = r;
for (let i = 0; i < deps.length; i++) setters[i](mMap.get(deps[i])?.exp);
const [d, { execute, setters }] = r;
for (let i = 0; i < d.length; i++) setters[i](mMap.get(d[i])?.exp);
const e = execute();
if (e) await e;
}
};

const dr_s = main => {
const rQ = gRQ(main);
let r;
while ((r = rQ.shift())) {
const [d, { execute, setters }] = r;
for (let i = 0; i < d.length; i++) setters[i](mMap.get(d[i])?.exp);
execute();
}
};

__inst = async id => {
System = undefined;
__inst = undefined;
System = __inst = __inst_s = undefined;
enq([id]);
await dr(id);
return mMap.get(id)?.exp;
};

__inst_s = id => {
System = __inst = __inst_s = undefined;
enq([id]);
dr_s(id);
return mMap.get(id)?.exp;
};
})();

0 comments on commit d2dab38

Please sign in to comment.