Files
aego/tools/gendocs/site/static/loader.js
sanspie 962c479933
ci-platforms / darwin amd64 smoke (push) Skipped
ci-platforms / darwin arm64 smoke (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
ci / checks (push) Successful in 10m24s
ci / build (amd64, linux, ubuntu-24.04) (push) Successful in 12m13s
ci / release (push) Successful in 8m57s
web: the browser build drops the self-update core (D362 amended)
modules/update links aego/update (net/http, TLS, x509, archives) only off js; the web build gets a browser backend with the same section, settings and aego/update API, where Check and Apply fail and State stays idle. A test compares both builds' registrations.
depcheck: wasm-runtime and wasm-try variants, update in wasmDenied, wasmDeniedStd (net/http, crypto/tls, crypto/x509, archive/*) with the wasm-reaches-std rule.
wasmsize -prev: playground-size and try-size print the change since their last run.
Loaders show the compressed download size: wasmGzip in an export's files.json, aego-*-gzip and data-wasm-gzip on the site; docstool writes the .wasm.gz copies.
Demo game.wasm 33.9 -> 26.0 MB, gzip 8.07 -> 6.25 MB.
2026-10-27 20:06:16 +03:00

124 lines
4.4 KiB
JavaScript

"use strict";
(function () {
function meta(name) {
const m = document.querySelector(`meta[name="${name}"]`);
return m ? m.content : "";
}
const root = meta("aego-root");
const runtimes = new Map();
let support = null;
function script(src) {
return new Promise((resolve, reject) => {
const s = document.createElement("script");
s.src = src;
s.onload = resolve;
s.onerror = () => reject(new Error("cannot load " + src));
document.head.appendChild(s);
});
}
function url(dir, file) {
const version = meta("aego-" + dir);
return new URL(root + dir + "/" + file + (version ? "?v=" + version : ""), location.href).href;
}
// seen marks a runtime this browser has started, by its versioned URL.
function seen(u, mark) {
try {
const key = "aego-seen:" + u.split("?")[0];
if (mark) localStorage.setItem(key, u);
return localStorage.getItem(key) === u;
} catch (_) {
return false;
}
}
// cached trusts the mark: versioned runtimes are immutable, and probing the HTTP cache would hold its lock on the same URL.
function cached(u) {
return Promise.resolve(seen(u, false));
}
// count reads one branch of the download for progress, reporting at most once per frame.
async function count(stream, total, wire, report) {
const reader = stream.getReader();
let got = 0;
let queued = false;
const flush = () => {
queued = false;
report({ phase: "download", got, total, wire });
};
for (;;) {
const { done, value } = await reader.read();
if (done) break;
got += value.byteLength;
if (!queued) {
queued = true;
requestAnimationFrame(flush);
}
}
report({ phase: "compile", got, total: total || got });
}
async function start(dir, file, readyHook, api, report) {
const u = url(dir, file);
const total = Number(meta("aego-" + dir + "-size")) || 0;
if (!support) {
const v = meta("aego-" + dir);
support = script(root + dir + "/wasm_exec.js" + (v ? "?v=" + v : "")).catch((e) => {
support = null;
throw e;
});
}
await support;
const ready = new Promise((resolve) => (globalThis[readyHook] = resolve));
const warm = seen(u, false);
if (report) report({ phase: warm ? "cache" : "download", got: 0, total });
let resp = await fetch(u);
if (!resp.ok) throw new Error(`${file}: HTTP ${resp.status}`);
if (report && !warm && resp.body) {
const [compile, progress] = resp.body.tee();
// the status counts the compressed size the server sends
const wire = (resp.headers.get("Content-Encoding") && Number(meta("aego-" + dir + "-gzip"))) || total;
count(progress, total, wire, report).catch(() => {});
resp = new Response(compile, { headers: resp.headers });
}
const go = new Go();
const { instance } = WebAssembly.instantiateStreaming
? await WebAssembly.instantiateStreaming(resp, go.importObject)
: await WebAssembly.instantiate(await resp.arrayBuffer(), go.importObject);
if (report) report({ phase: "start", got: total, total });
go.run(instance);
await ready;
seen(u, true);
const out = globalThis[api];
if (!out) throw new Error(file + " did not start");
if (out.error) throw new Error(out.error);
return out;
}
globalThis.aegoRuntime = function (dir, file, readyHook, api, report) {
const key = dir + "/" + file;
if (!runtimes.has(key)) {
const listeners = new Set();
const p = start(dir, file, readyHook, api, (s) => {
for (const fn of listeners) fn(s);
});
p.listeners = listeners;
runtimes.set(key, p);
p.catch(() => runtimes.delete(key));
}
const p = runtimes.get(key);
if (report) p.listeners.add(report);
return p;
};
globalThis.aegoRuntimeCached = function (dir, file) {
return cached(url(dir, file));
};
globalThis.aegoMB = (n) => (n / 1048576).toFixed(1) + " MB";
})();