@markless/bundler 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/preload.d.ts +4 -4
- package/dist/preload.js +2 -2
- package/dist/rolldown-DAsY_7V1.js +4515 -0
- package/dist/rolldown.d.ts +11 -3
- package/dist/rolldown.js +3 -3
- package/dist/{source-module-C8W2THUI.js → source-module-BCEdLQvG.js} +362 -286
- package/dist/source-module-XFgOFX1c.d.ts +8 -0
- package/dist/{types-CzXV_ABj.d.ts → types-BuooJg32.d.ts} +47 -2
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +1298 -115
- package/package.json +6 -6
- package/dist/rolldown-CpG_S-ZJ.js +0 -2554
- package/dist/source-module-BRb5P7wL.d.ts +0 -6
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { joinURL } from "ufo";
|
|
2
|
+
import { ASYNC_PROTOCOL_VERSION } from "@markless/serializer";
|
|
2
3
|
//#region src/build/preload-plan.ts
|
|
3
4
|
const DEFAULT_MIN_PROBABILITY = 0;
|
|
4
5
|
const JAVASCRIPT_MODULE_RE = /\.(?:mjs|js)(?:[?#].*)?$/;
|
|
@@ -33,7 +34,7 @@ function planModulePreloads(input) {
|
|
|
33
34
|
probability
|
|
34
35
|
});
|
|
35
36
|
};
|
|
36
|
-
const visit = (name, probability, priority, fetchPriority, seen, suppressed = false) => {
|
|
37
|
+
const visit = (name, probability, priority, fetchPriority, seen, suppressed = false, suppressRootOnly = false) => {
|
|
37
38
|
if (probability < minProbability || planned.size >= maxPreloads) return;
|
|
38
39
|
if (!suppressed) {
|
|
39
40
|
const priorityRank = PRIORITY_RANK[priority];
|
|
@@ -52,7 +53,7 @@ function planModulePreloads(input) {
|
|
|
52
53
|
if (!suppressed) addModule(name, probability, priority, fetchPriority);
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
|
-
for (const dep of record.deps.filter((item) => item.kind === "static")) visit(dep.name, probability * dep.probability, priority, fetchPriority, nextSeen, suppressed);
|
|
56
|
+
for (const dep of record.deps.filter((item) => item.kind === "static")) visit(dep.name, probability * dep.probability, priority, fetchPriority, nextSeen, suppressed && !suppressRootOnly);
|
|
56
57
|
if (!suppressed) addModule(name, probability, priority, fetchPriority);
|
|
57
58
|
for (const dep of record.deps.filter((item) => item.kind === "dynamic")) {
|
|
58
59
|
const edgeProbability = JAVASCRIPT_MODULE_RE.test(name) ? dep.probability : 1;
|
|
@@ -61,7 +62,7 @@ function planModulePreloads(input) {
|
|
|
61
62
|
};
|
|
62
63
|
for (const root of input.roots) {
|
|
63
64
|
const normalized = normalizeRoot(root);
|
|
64
|
-
visit(normalized.name, 1, normalized.priority, normalized.fetchPriority, /* @__PURE__ */ new Set(), normalized.edges === "dynamic-only");
|
|
65
|
+
visit(normalized.name, 1, normalized.priority, normalized.fetchPriority, /* @__PURE__ */ new Set(), normalized.edges === "dynamic-only" || normalized.edges === "dependencies-only", normalized.edges === "dependencies-only");
|
|
65
66
|
}
|
|
66
67
|
return [...planned.values()].sort((left, right) => {
|
|
67
68
|
const priority = PRIORITY_RANK[right.priority] - PRIORITY_RANK[left.priority];
|
|
@@ -128,179 +129,18 @@ function priorityToFetchPriority(priority) {
|
|
|
128
129
|
if (priority === "auto") return "auto";
|
|
129
130
|
return priority;
|
|
130
131
|
}
|
|
131
|
-
const MARKLESS_BUILD_PREFIX = `build/`;
|
|
132
|
-
const MARKLESS_BUNDLE_GRAPH = `${MARKLESS_BUILD_PREFIX}bundle-graph.json`;
|
|
133
|
-
const WEB_RUNTIME_CAPABILITY_GROUPS = [
|
|
134
|
-
{
|
|
135
|
-
name: "markless-resume-branches",
|
|
136
|
-
test: fileBasenamePattern("resume-branches")
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: "markless-resume-behaviors",
|
|
140
|
-
test: fileBasenamePattern("resume-behaviors")
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
name: "markless-resume-repeats",
|
|
144
|
-
test: fileBasenamePattern("resume-keyed-repeats", "repeat-runtime")
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: "markless-resume-async",
|
|
148
|
-
test: fileBasenamePattern("resume-async-boundaries", "resume-async-wiring")
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
name: "markless-resume-shared-patch",
|
|
152
|
-
test: fileBasenamePattern("resume-shared-patch")
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
name: "markless-resume-runtime",
|
|
156
|
-
test: fileBasenamePattern("resume-runtime")
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
name: "markless-resume-runtime-start",
|
|
160
|
-
test: fileBasenamePattern("resume-runtime-start")
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
name: "markless-resume-runtime-shared",
|
|
164
|
-
test: fileBasenamePattern("resume-runtime-shared")
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
name: "markless-resume-events",
|
|
168
|
-
test: fileBasenamePattern("resume-events")
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
name: "markless-resume-handoff",
|
|
172
|
-
test: fileBasenamePattern("resume-handoff")
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
name: "markless-resume-locators",
|
|
176
|
-
test: fileBasenamePattern("resume-locators")
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
name: "markless-resume-errors",
|
|
180
|
-
test: fileBasenamePattern("resume-errors")
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
name: "markless-resume-sync-computed",
|
|
184
|
-
test: fileBasenamePattern("resume-sync-computed")
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
name: "markless-resume-sync-demand",
|
|
188
|
-
test: fileBasenamePattern("resume-sync-demand")
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
name: "markless-payload-full",
|
|
192
|
-
test: fileBasenamePattern("payload-full")
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
name: "markless-payload-resume",
|
|
196
|
-
test: fileBasenamePattern("payload-resume")
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
name: "markless-inline-payload-document",
|
|
200
|
-
test: /[/\\]web[/\\]src[/\\]inline[/\\]payload-document\.ts(?:[?#].*)?$/
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
name: "markless-payload-document",
|
|
204
|
-
test: fileBasenamePattern("payload-document", "payload-resume-registry")
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
name: "markless-payload-graph-construct",
|
|
208
|
-
test: fileBasenamePattern("payload-graph-construct")
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
name: "markless-dom-journal",
|
|
212
|
-
test: fileBasenamePattern("dom-journal")
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
name: "markless-protocol-decode",
|
|
216
|
-
test: fileBasenamePattern("protocol-client", "protocol-state")
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
name: "markless-value-decode",
|
|
220
|
-
test: fileBasenamePattern("value-decode-client", "value-decode-extensions")
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
name: "markless-payload-leaves",
|
|
224
|
-
test: fileBasenamePattern("payload", "payload-document")
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
name: "markless-dev-log",
|
|
228
|
-
test: /virtual:markless:dev-log|[/\\]web[/\\]src[/\\]dev-log\.ts(?:[?#].*)?$/
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
name: "markless-resume-core",
|
|
232
|
-
test: fileBasenamePattern("resume")
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
name: "markless-runtime-graph-core",
|
|
236
|
-
test: fileBasenamePattern("graph-core")
|
|
237
|
-
},
|
|
238
|
-
{
|
|
239
|
-
name: "markless-runtime-graph-collections",
|
|
240
|
-
test: fileBasenamePattern("graph-collections")
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
name: "markless-runtime-graph-computed",
|
|
244
|
-
test: fileBasenamePattern("graph-computed")
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
name: "markless-runtime-graph-async",
|
|
248
|
-
test: fileBasenamePattern("graph-async")
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
name: "markless-runtime-graph-scheduler",
|
|
252
|
-
test: fileBasenamePattern("graph-scheduler")
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
name: "markless-runtime-graph-shared",
|
|
256
|
-
test: fileBasenamePattern("graph-shared")
|
|
257
|
-
},
|
|
258
|
-
{
|
|
259
|
-
name: "markless-graph",
|
|
260
|
-
test: /[/\\](?:runtime[/\\]src[/\\](?!graph-(?:core|collections|computed|async|scheduler|shared)\.ts)|core[/\\]src[/\\]runtime)[/\\]?/
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
name: "markless-serializer",
|
|
264
|
-
test: /[/\\]serializer[/\\]src[/\\](?!protocol-validation)/
|
|
265
|
-
}
|
|
266
|
-
];
|
|
267
|
-
function fileBasenamePattern(...names) {
|
|
268
|
-
return new RegExp(`[/\\\\](?:${names.join("|")})\\.ts(?:[?#].*)?$`);
|
|
269
|
-
}
|
|
270
|
-
const MARKLESS_RUNTIME_GROUPS = [...WEB_RUNTIME_CAPABILITY_GROUPS, {
|
|
271
|
-
name: "markless-runtime",
|
|
272
|
-
test: /[/\\]@markless[/\\]runtime[/\\]/
|
|
273
|
-
}];
|
|
274
|
-
function outputDefaults(output, environment) {
|
|
275
|
-
if (environment === "lib") return output;
|
|
276
|
-
const next = {
|
|
277
|
-
...output,
|
|
278
|
-
hoistTransitiveImports: false
|
|
279
|
-
};
|
|
280
|
-
if (environment === "server") {
|
|
281
|
-
next.entryFileNames ??= "[name].js";
|
|
282
|
-
next.chunkFileNames ??= "chunk-[hash].js";
|
|
283
|
-
next.codeSplitting = marklessCodeSplitting(next.codeSplitting);
|
|
284
|
-
return next;
|
|
285
|
-
}
|
|
286
|
-
next.entryFileNames ??= `${MARKLESS_BUILD_PREFIX}chunk-[hash].js`;
|
|
287
|
-
next.chunkFileNames ??= `${MARKLESS_BUILD_PREFIX}chunk-[hash].js`;
|
|
288
|
-
next.minifyInternalExports = true;
|
|
289
|
-
next.strictExecutionOrder = true;
|
|
290
|
-
next.codeSplitting = marklessCodeSplitting(next.codeSplitting);
|
|
291
|
-
return next;
|
|
292
|
-
}
|
|
293
|
-
function marklessCodeSplitting(codeSplitting) {
|
|
294
|
-
if (typeof codeSplitting === "boolean") throw new Error("@markless/bundler requires output.codeSplitting to be an object so runtime chunks can be grouped.");
|
|
295
|
-
return {
|
|
296
|
-
...codeSplitting,
|
|
297
|
-
groups: [...MARKLESS_RUNTIME_GROUPS, ...codeSplitting?.groups ?? []]
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
132
|
//#endregion
|
|
301
133
|
//#region src/execution-log.ts
|
|
302
134
|
const MARKLESS_EXECUTION_LOG_MODULE_ID = "virtual:markless:dev-log";
|
|
303
|
-
const
|
|
135
|
+
const EXECUTION_LOG_DISPATCH_MODULE_IDS = ["web:render-csr", "web:resume-events"];
|
|
136
|
+
const MARKLESS_EXECUTION_LEDGER_GLOBAL = "__marklessExecutionLedger";
|
|
137
|
+
const MARKLESS_EXECUTION_LEDGER_INIT = "{ unit: 'chunk-raw-bytes', load: { app: 0, framework: 0, instrument: 0, inline: 0, modules: [] }, total: { app: 0, framework: 0, instrument: 0, inline: 0 }, turns: [], incomplete: null }";
|
|
138
|
+
const EXECUTION_LOG_GESTURE_EVENTS = [
|
|
139
|
+
"pointerdown",
|
|
140
|
+
"touchstart",
|
|
141
|
+
"keydown"
|
|
142
|
+
];
|
|
143
|
+
const EXECUTION_LOG_FRAMEWORK_ID_PATTERN = "/^(?:web|runtime|serializer|router|core|analyzer):/";
|
|
304
144
|
function normalizeExecutionLogMode(mode) {
|
|
305
145
|
return mode ?? "auto";
|
|
306
146
|
}
|
|
@@ -309,6 +149,9 @@ function injectExecutionLogModuleHook(source, moduleId, mode) {
|
|
|
309
149
|
return `globalThis.__mxLog?.add(${JSON.stringify(moduleId)});\n${source}`;
|
|
310
150
|
}
|
|
311
151
|
const EXECUTION_LOG_HOOK_LINE = /^globalThis\.__mxLog\?\.add\("(?:[^"\\]|\\.)*"\);\n/;
|
|
152
|
+
function hasExecutionLogModuleHook(source) {
|
|
153
|
+
return EXECUTION_LOG_HOOK_LINE.test(source);
|
|
154
|
+
}
|
|
312
155
|
function requalifyExecutionLogModuleHook(source, moduleId) {
|
|
313
156
|
if (!EXECUTION_LOG_HOOK_LINE.test(source)) return source;
|
|
314
157
|
return source.replace(EXECUTION_LOG_HOOK_LINE, `globalThis.__mxLog?.add(${JSON.stringify(moduleId)});\n`);
|
|
@@ -334,9 +177,10 @@ const marklessSizesUrl = ${JSON.stringify(options.sizesUrl ?? null)};
|
|
|
334
177
|
let marklessSizesPromise;
|
|
335
178
|
let marklessAttribution;
|
|
336
179
|
let marklessInstallPromise;
|
|
180
|
+
let marklessRenderSummaryTurn;
|
|
337
181
|
function modules(log) { return log ? [...log] : []; }
|
|
338
182
|
function sizeRecord(input) { return !input ? undefined : typeof input === 'number' ? { raw: input, estimated: true } : input; }
|
|
339
|
-
function normalizeSizes(input) { if (!input) return undefined; const map = new Map(); for (const id of Object.keys(input)) if (id !== 'attribution') map.set(id, sizeRecord(input[id])); return map; }
|
|
183
|
+
function normalizeSizes(input) { if (!input) return undefined; const map = new Map(); for (const id of Object.keys(input)) if (id !== 'attribution' && id !== 'unshipped') map.set(id, sizeRecord(input[id])); return map; }
|
|
340
184
|
async function loadModuleSizes(input) {
|
|
341
185
|
if (input.moduleSizes) return normalizeSizes(input.moduleSizes);
|
|
342
186
|
if (marklessDefaultModuleSizes) { marklessAttribution = marklessDefaultAttribution; return normalizeSizes(marklessDefaultModuleSizes); }
|
|
@@ -347,7 +191,20 @@ async function loadModuleSizes(input) {
|
|
|
347
191
|
function symbolParts(id) { const match = /^virtual:markless:symbol:([^:]+):([^:]+)$/.exec(id); if (!match) return null; try { return { source: decodeURIComponent(match[1]), symbolId: decodeURIComponent(match[2]) }; } catch { return null; } }
|
|
348
192
|
function baseSymbolId(id) { if (!id.startsWith('bound:')) return null; const separator = id.indexOf(':', 'bound:'.length); if (separator < 0) return null; try { return decodeURIComponent(id.slice('bound:'.length, separator)); } catch { return null; } }
|
|
349
193
|
function routeFile() { const text = document.querySelector?.('script[type="@markless/core/route"]')?.textContent; if (!text) return null; try { const value = JSON.parse(text).file; return typeof value === 'string' ? value : null; } catch { return null; } }
|
|
350
|
-
|
|
194
|
+
// Attribution tables are keyed by the bare path this lookup can name: the
|
|
195
|
+
// document's route file, or — for a routeless page — the build's single root,
|
|
196
|
+
// which is the only page it can be.
|
|
197
|
+
function attributionScopes(tables) { if (!tables) return undefined; const route = routeFile(); if (route) { if (route.includes('..') || route.includes('\\\\')) return undefined; const canonical = route.replace(/^\\/+/, ''); return Object.prototype.hasOwnProperty.call(tables, canonical) ? tables[canonical] : undefined; } const roots = Object.keys(tables); return roots.length === 1 ? tables[roots[0]] : undefined; }
|
|
198
|
+
// A handler renders inside one component but is owned by whichever component
|
|
199
|
+
// created the closure — a prop-passed onClick renders at the child's scope and
|
|
200
|
+
// belongs to the parent. The owner is therefore somewhere on the host's render
|
|
201
|
+
// ancestry, so once the host's OWN scope is one the table names, the chain is
|
|
202
|
+
// walked outward and the first scope holding exactly one candidate wins. Never a
|
|
203
|
+
// guess: a host in a scope the table does not name is refused outright, a scope
|
|
204
|
+
// with zero or several candidates is skipped, and an id nobody owns uniquely
|
|
205
|
+
// stays unmapped.
|
|
206
|
+
function scopeChain(scope) { const chain = []; for (let current = scope; ; ) { chain.push(current); if (!current) return chain; const next = current.replace(/c\\d+:$/, ''); if (next === current) return chain; current = next; } }
|
|
207
|
+
function qualifySymbolIds(ids, hostNodeId, sizes, tables) { const scopes = attributionScopes(tables); if (!scopes) return ids; const host = /^((?:c\\d+:)*)[^:]+$/.exec(hostNodeId); const hostScope = host && host[1]; return ids.map((id) => { const own = /^((?:c\\d+:)+)(.*)$/.exec(id); const scope = own ? own[1] : hostScope; if (scope === null || scope === undefined || !Object.prototype.hasOwnProperty.call(scopes, scope)) return id; const local = own ? own[2] : id; const base = baseSymbolId(local); const sizeSymbolId = base || local; if (!sizeSymbolId.startsWith('symbol:')) return id; for (const candidate of scopeChain(scope)) { if (!Object.prototype.hasOwnProperty.call(scopes, candidate)) continue; const matches = [...(sizes?.keys() || [])].filter((key) => { const match = /^virtual:markless:symbol:([^:]+):([^:]+)$/.exec(key); if (!match || match[1] !== scopes[candidate]) return false; try { return decodeURIComponent(match[2]) === sizeSymbolId; } catch { return false; } }); if (matches.length !== 1) continue; if (!base) return matches[0]; const match = /^virtual:markless:symbol:([^:]+):/.exec(matches[0]); return match ? 'virtual:markless:symbol:' + match[1] + ':' + encodeURIComponent(local) : id; } return id; }); }
|
|
351
208
|
function canonicalId(id, sizes) {
|
|
352
209
|
if (!sizes || sizes.has(id)) return id;
|
|
353
210
|
const qualified = symbolParts(id); const local = qualified ? qualified.symbolId : id.replace(/^(?:c\\d+:)+/, ''); const sizeSymbolId = baseSymbolId(local) || local;
|
|
@@ -361,11 +218,91 @@ function accounting(items, sizes) {
|
|
|
361
218
|
const ids = [...new Set(items.map((id) => canonicalId(id, sizes)))];
|
|
362
219
|
if (!sizes) return { appBytes: ids.length ? null : 0, instrumentBytes: 0, appModules: ids.length, instrumentModules: 0, estimated: { app: false, instrument: false }, unmappedIds: [] };
|
|
363
220
|
let appBytes = 0, instrumentBytes = 0, appModules = 0, instrumentModules = 0, appEstimated = false, instrumentEstimated = false; const unmappedIds = [];
|
|
364
|
-
for (const id of ids) { const record = sizes.get(id); if (!record) { appModules++; unmappedIds.push(id); continue; } const bytes = record.
|
|
221
|
+
for (const id of ids) { const record = sizes.get(id); if (!record) { appModules++; unmappedIds.push(id); continue; } const bytes = record.raw; if (record.instrument) { instrumentModules++; instrumentBytes += bytes; instrumentEstimated ||= !!record.estimated; } else { appModules++; appBytes += bytes; appEstimated ||= !!record.estimated; } }
|
|
365
222
|
return { appBytes: unmappedIds.length ? null : appBytes, instrumentBytes, appModules, instrumentModules, estimated: { app: appEstimated, instrument: instrumentEstimated }, unmappedIds };
|
|
366
223
|
}
|
|
367
|
-
function category(a, name) { const bytes = name === 'app' ? a.appBytes : a.instrumentBytes; const count = name === 'app' ? a.appModules : a.instrumentModules; if (bytes === null) return count + ' ' + name + ' module' + (count === 1 ? '' : 's') + (name === 'app' && a.unmappedIds.length ? ' (bytes unknown; ' + a.unmappedIds.length + ' unmapped)' : ''); return (bytes / 1024).toFixed(1) + ' KB' + (a.estimated[name] ? ' est. source' : '') + ' ' + name; }
|
|
368
224
|
function rowKb(items, sizes) { const a = accounting(items, sizes); if (a.unmappedIds.length) return 'bytes unknown'; const total = (a.appBytes || 0) + (a.instrumentBytes || 0); return (total / 1024).toFixed(1) + ' KB' + (a.estimated.app || a.estimated.instrument ? ' est. source' : ''); }
|
|
225
|
+
// One cumulative ledger owns every number the console prints. A module's charge
|
|
226
|
+
// is the whole raw byte length of the chunk that absorbed it (several modules in
|
|
227
|
+
// one chunk are each charged the whole chunk), which is what unit says.
|
|
228
|
+
function marklessLedger() { return (globalThis.${MARKLESS_EXECUTION_LEDGER_GLOBAL} ||= ${MARKLESS_EXECUTION_LEDGER_INIT}); }
|
|
229
|
+
function ledgerCategory(id, record) { return record && record.instrument ? 'instrument' : ${EXECUTION_LOG_FRAMEWORK_ID_PATTERN}.test(id) ? 'framework' : 'app'; }
|
|
230
|
+
function ledgerCharge(l, ids, sizes) {
|
|
231
|
+
const seen = (l.chargedIds ||= new Set());
|
|
232
|
+
const seenChunks = (l.chargedChunks ||= new Set());
|
|
233
|
+
const delta = { app: 0, framework: 0, instrument: 0, gzip: 0, modules: [], unmapped: [] };
|
|
234
|
+
for (const raw of ids) {
|
|
235
|
+
const id = canonicalId(raw, sizes);
|
|
236
|
+
const record = sizes && sizes.get(id);
|
|
237
|
+
// The unit is the chunk, so the dedupe unit is the chunk: one chunk reached
|
|
238
|
+
// under two names (a symbol id and the emitted specifier Rolldown rewrote
|
|
239
|
+
// its hook to) is one charge, not two. Dev estimates carry no chunk, so
|
|
240
|
+
// there the id is still the unit.
|
|
241
|
+
const chunk = record && record.chunk;
|
|
242
|
+
if (chunk ? seenChunks.has(chunk) : seen.has(id)) continue;
|
|
243
|
+
if (chunk) seenChunks.add(chunk); else seen.add(id);
|
|
244
|
+
if (!record) { delta.unmapped.push(id); continue; }
|
|
245
|
+
if (record.estimated) l.unit = 'estimated-source-bytes';
|
|
246
|
+
delta[ledgerCategory(id, record)] += record.raw; delta.gzip += record.gzip || 0; delta.modules.push(id);
|
|
247
|
+
}
|
|
248
|
+
if (delta.unmapped.length) l.incomplete = { reason: 'unmapped-id', ids: [...new Set([...(l.incomplete ? l.incomplete.ids : []), ...delta.unmapped])] };
|
|
249
|
+
return delta;
|
|
250
|
+
}
|
|
251
|
+
// Load is everything charged before the FIRST USER GESTURE, which the activation
|
|
252
|
+
// script latches on the gesture itself (loadClosed) rather than on the kind of
|
|
253
|
+
// whichever turn reports first. On an SSR page nothing runs until the click, and
|
|
254
|
+
// the instrument and the wake entry both arrive with it; their render/resume
|
|
255
|
+
// turns are work that gesture caused, so their charge joins the gesture's turn —
|
|
256
|
+
// merged into it if it already exists, carried until it does if it does not.
|
|
257
|
+
function ledgerApply(l, kind, label, delta) {
|
|
258
|
+
const gesture = kind !== 'render' && kind !== 'resume';
|
|
259
|
+
if (gesture) l.loadClosed = true;
|
|
260
|
+
for (const name of ['app', 'framework', 'instrument']) { l.total[name] += delta[name]; if (!l.loadClosed) l.load[name] += delta[name]; }
|
|
261
|
+
l.totalGzip = (l.totalGzip || 0) + delta.gzip;
|
|
262
|
+
if (!l.loadClosed) { l.loadGzip = (l.loadGzip || 0) + delta.gzip; for (const id of delta.modules) l.load.modules.push(id); }
|
|
263
|
+
if (!gesture && l.loadClosed) {
|
|
264
|
+
const open = l.open;
|
|
265
|
+
if (open) { open.delta.app += delta.app; open.delta.framework += delta.framework; open.delta.instrument += delta.instrument; for (const id of delta.modules) open.modules.push(id); return open; }
|
|
266
|
+
const held = (l.carry ||= { app: 0, framework: 0, instrument: 0, modules: [] });
|
|
267
|
+
held.app += delta.app; held.framework += delta.framework; held.instrument += delta.instrument; for (const id of delta.modules) held.modules.push(id);
|
|
268
|
+
delta = { app: 0, framework: 0, instrument: 0, modules: [] };
|
|
269
|
+
}
|
|
270
|
+
const carry = gesture ? l.carry : undefined;
|
|
271
|
+
if (carry) l.carry = undefined;
|
|
272
|
+
const turn = { kind, label, delta: { app: delta.app + (carry ? carry.app : 0), framework: delta.framework + (carry ? carry.framework : 0), instrument: delta.instrument + (carry ? carry.instrument : 0) }, modules: carry ? [...carry.modules, ...delta.modules] : delta.modules };
|
|
273
|
+
l.turns.push(turn); if (gesture) l.open = turn;
|
|
274
|
+
return turn;
|
|
275
|
+
}
|
|
276
|
+
function ledgerKb(bytes) { return (bytes / 1024).toFixed(1) + ' KB'; }
|
|
277
|
+
// The instrument is dev-only weight, so it stays out of the headline totals and
|
|
278
|
+
// keeps its own category, exactly as the pre-ledger lines did.
|
|
279
|
+
function ledgerVisible(part) { return part.app + part.framework + part.inline; }
|
|
280
|
+
function ledgerLine(l, turn) {
|
|
281
|
+
let line = 'markless: ' + ledgerKb(ledgerVisible(l.load)) + ' executed at load';
|
|
282
|
+
if (turn && turn.kind !== 'render' && turn.kind !== 'resume') line += ' · this ' + turn.kind + ' +' + ledgerKb(turn.delta.app + turn.delta.framework);
|
|
283
|
+
line += ' · total ' + ledgerKb(ledgerVisible(l.total));
|
|
284
|
+
if (l.totalGzip) line += ' (gzip ' + ledgerKb(l.totalGzip) + ')';
|
|
285
|
+
if (l.incomplete) line += ' · ' + l.incomplete.ids.length + ' unmapped (excluded)';
|
|
286
|
+
return line;
|
|
287
|
+
}
|
|
288
|
+
function ledgerMirror(l, turn, text, attribute) {
|
|
289
|
+
const root = document.documentElement; if (!root) return;
|
|
290
|
+
root.setAttribute(attribute, text);
|
|
291
|
+
root.setAttribute('data-markless-log-unit', l.unit);
|
|
292
|
+
root.setAttribute('data-markless-log-load-bytes', String(ledgerVisible(l.load)));
|
|
293
|
+
root.setAttribute('data-markless-log-total-bytes', String(ledgerVisible(l.total)));
|
|
294
|
+
root.setAttribute('data-markless-log-inline-bytes', String(l.total.inline));
|
|
295
|
+
if (turn) {
|
|
296
|
+
root.setAttribute('data-markless-log-app-bytes', String(turn.delta.app));
|
|
297
|
+
root.setAttribute('data-markless-log-framework-bytes', String(turn.delta.framework));
|
|
298
|
+
root.setAttribute('data-markless-log-instrument-bytes', String(turn.delta.instrument));
|
|
299
|
+
root.setAttribute('data-markless-log-turn-bytes', String(turn.delta.app + turn.delta.framework));
|
|
300
|
+
root.setAttribute('data-markless-log-turn-modules', turn.modules.join(' '));
|
|
301
|
+
// The headline carries no selector, so the turn's identity lives here.
|
|
302
|
+
root.setAttribute('data-markless-log-turn-label', turn.kind + (turn.label ? ' ' + turn.label : ''));
|
|
303
|
+
}
|
|
304
|
+
if (l.incomplete) root.setAttribute('data-markless-log-incomplete', String(l.incomplete.ids.length)); else root.removeAttribute('data-markless-log-incomplete');
|
|
305
|
+
}
|
|
369
306
|
function warmIds(event) { return [...new Set([event.dispatchModuleId, ...((event.eventRecord && event.eventRecord.symbolIds) || [])].filter(Boolean))]; }
|
|
370
307
|
function causeRows(input) {
|
|
371
308
|
const before = input.before || new Set(); const after = input.after || new Set(); const woken = [...after].filter((id) => !before.has(id)); const record = input.eventRecord;
|
|
@@ -376,34 +313,40 @@ function causeRows(input) {
|
|
|
376
313
|
if (record && !(input.view?.behaviors || []).some((b) => b.hostNodeId === record.hostNodeId)) rows.push('skip behavior — no matching record touched');
|
|
377
314
|
return rows;
|
|
378
315
|
}
|
|
379
|
-
function
|
|
316
|
+
function mirrorInteraction(l, turn, text) {
|
|
380
317
|
const root = document.documentElement; if (!root) return;
|
|
381
|
-
|
|
382
|
-
|
|
318
|
+
root.setAttribute('data-markless-log-interactions', String(Number(root.getAttribute('data-markless-log-interactions') || '0') + 1));
|
|
319
|
+
ledgerMirror(l, turn, text, 'data-markless-log-last');
|
|
383
320
|
}
|
|
384
|
-
function mirrorBytes(root, a) { if (a.appBytes === null || a.instrumentBytes === null) { root.removeAttribute('data-markless-log-app-bytes'); root.removeAttribute('data-markless-log-instrument-bytes'); return; } root.setAttribute('data-markless-log-app-bytes', String(a.appBytes)); root.setAttribute('data-markless-log-instrument-bytes', String(a.instrumentBytes)); }
|
|
385
321
|
export async function installMarklessExecutionLog(input = {}) {
|
|
386
322
|
const log = globalThis.__mxLog; if (!log || globalThis.__mxLogInteraction) return;
|
|
387
323
|
if (marklessInstallPromise) return marklessInstallPromise;
|
|
388
324
|
marklessInstallPromise = (async () => {
|
|
389
|
-
const moduleSizes = await loadModuleSizes(input); const
|
|
325
|
+
const moduleSizes = await loadModuleSizes(input); const current = modules(log);
|
|
390
326
|
if (input.printResumeSummary !== false) {
|
|
391
|
-
const
|
|
392
|
-
|
|
327
|
+
const l = marklessLedger(); const turn = ledgerApply(l, 'resume', undefined, ledgerCharge(l, current, moduleSizes)); const summary = ledgerLine(l, turn);
|
|
328
|
+
// This summary publishes into the ledger and mirrors; it never prints. The
|
|
329
|
+
// ledger's turn line is the one printed line, and a resume that lands
|
|
330
|
+
// beside a render turn would otherwise print the same load figure twice.
|
|
331
|
+
// A turn merged into an open gesture belongs to that gesture, so it mirrors
|
|
332
|
+
// onto the interaction attribute instead of the load one.
|
|
333
|
+
ledgerMirror(l, turn, summary, turn.kind === 'resume' ? 'data-markless-log-summary' : 'data-markless-log-last');
|
|
393
334
|
}
|
|
394
335
|
globalThis.__mxLogInteraction = (event) => {
|
|
395
336
|
const capturedAfter = modules(event.after || log);
|
|
396
337
|
const symbolIds = qualifySymbolIds((event.eventRecord && event.eventRecord.symbolIds) || [], event.eventRecord && event.eventRecord.hostNodeId, moduleSizes, marklessAttribution);
|
|
397
338
|
if (event.eventRecord) event = { ...event, eventRecord: { ...event.eventRecord, symbolIds } };
|
|
398
339
|
const after = capturedAfter; const before = event.before || new Set(); if (log.has(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)}) && !after.includes(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)})) after.push(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)}); const woken = after.filter((id) => !before.has(id)); const warm = warmIds(event);
|
|
340
|
+
const l = marklessLedger(); const label = '[' + (event.selector || 'event target') + ']';
|
|
399
341
|
if (event.noMatch) {
|
|
400
|
-
const
|
|
401
|
-
console.info(line);
|
|
342
|
+
const turn = ledgerApply(l, event.eventName, label, ledgerCharge(l, [], moduleSizes)); const line = ledgerLine(l, turn) + ' · no event record matched ' + label;
|
|
343
|
+
console.info(line); mirrorInteraction(l, turn, line); return;
|
|
402
344
|
}
|
|
403
|
-
const
|
|
345
|
+
const turn = ledgerApply(l, event.eventName, label, ledgerCharge(l, [...woken, ...warm], moduleSizes)); const header = ledgerLine(l, turn);
|
|
404
346
|
console.groupCollapsed(header);
|
|
347
|
+
console.log(event.eventName + ' ' + label + ' · woke ' + woken.length + ' modules · ran warm ' + warm.length + ' modules');
|
|
405
348
|
for (const row of causeRows({ ...event, after: new Set(after), moduleSizes })) console.log(row);
|
|
406
|
-
console.groupEnd();
|
|
349
|
+
console.groupEnd(); mirrorInteraction(l, turn, header);
|
|
407
350
|
};
|
|
408
351
|
log.__marklessInstalled = true;
|
|
409
352
|
})();
|
|
@@ -415,96 +358,47 @@ export async function logMarklessSpecializedInteraction(input, before) {
|
|
|
415
358
|
const tag = typeof target?.tagName === 'string' ? target.tagName.toLowerCase() : 'element';
|
|
416
359
|
await logMarklessInteraction({ eventName: input.event?.type ?? 'event', eventRecord: input.eventRecord, before, selector: tag + (target?.id ? '#' + target.id : ''), after: new Set(globalThis.__mxLog) });
|
|
417
360
|
}
|
|
361
|
+
function marklessRenderSummaryTurnEnd() {
|
|
362
|
+
// Each injected entry module calls in from its own dynamic-import
|
|
363
|
+
// resolution, so a microtask window closes between callers of one render;
|
|
364
|
+
// a frame holds them all. The timeout is the backstop for a document that
|
|
365
|
+
// never paints, and whichever lands first ends the turn.
|
|
366
|
+
if (typeof requestAnimationFrame !== 'function') return Promise.resolve();
|
|
367
|
+
return new Promise((resolve) => { let ended; const end = () => { if (ended) return; ended = true; resolve(); }; requestAnimationFrame(end); setTimeout(end, 50); });
|
|
368
|
+
}
|
|
369
|
+
// Only the console line coalesces: the attribute mirror keeps its per-call
|
|
370
|
+
// last-wins timing, which the interaction mirror interleaves with.
|
|
371
|
+
function coalesceMarklessRenderSummaryLine(summary) {
|
|
372
|
+
if (marklessRenderSummaryTurn) { marklessRenderSummaryTurn.summary = summary; return marklessRenderSummaryTurn.printed; }
|
|
373
|
+
const turn = { summary };
|
|
374
|
+
turn.printed = marklessRenderSummaryTurnEnd().then(() => { marklessRenderSummaryTurn = undefined; console.log(turn.summary); });
|
|
375
|
+
marklessRenderSummaryTurn = turn;
|
|
376
|
+
return turn.printed;
|
|
377
|
+
}
|
|
418
378
|
export async function logMarklessRenderSummary(input = {}) {
|
|
419
379
|
const log = globalThis.__mxLog; if (!log) return;
|
|
420
|
-
const moduleSizes = await loadModuleSizes(input); const
|
|
421
|
-
const
|
|
422
|
-
|
|
380
|
+
const moduleSizes = await loadModuleSizes(input); const l = marklessLedger();
|
|
381
|
+
const turn = ledgerApply(l, 'render', undefined, ledgerCharge(l, modules(log), moduleSizes));
|
|
382
|
+
const summary = ledgerLine(l, turn);
|
|
383
|
+
if (turn.kind !== 'render') { ledgerMirror(l, turn, summary, 'data-markless-log-last'); return; }
|
|
384
|
+
ledgerMirror(l, turn, summary, 'data-markless-log-summary');
|
|
385
|
+
return coalesceMarklessRenderSummaryLine(summary);
|
|
423
386
|
}
|
|
424
387
|
`;
|
|
425
388
|
}
|
|
426
|
-
async function createExecutionSizesAsset(bundle, metadata, canonPath = (fileName) => fileName, attribution) {
|
|
427
|
-
const entries = {};
|
|
428
|
-
const symbolLogIdsByChunk = /* @__PURE__ */ new Map();
|
|
429
|
-
for (const module of metadata.modules) for (const symbol of module.symbols) {
|
|
430
|
-
if (!symbol.fileName) continue;
|
|
431
|
-
const chunk = symbolLogIdsByChunk.get(symbol.fileName) ?? [];
|
|
432
|
-
chunk.push(stripResolvedIdMarker(symbol.virtualModuleId));
|
|
433
|
-
symbolLogIdsByChunk.set(symbol.fileName, chunk);
|
|
434
|
-
}
|
|
435
|
-
for (const item of Object.values(bundle)) {
|
|
436
|
-
if (item.type !== "chunk") continue;
|
|
437
|
-
const chunk = canonPath(item.fileName);
|
|
438
|
-
const logIds = new Set([...item.moduleIds.flatMap((id) => chunkModuleLogId(id) ?? []), ...symbolLogIdsByChunk.get(chunk) ?? []]);
|
|
439
|
-
if (logIds.size === 0) continue;
|
|
440
|
-
if (logIds.has("virtual:markless:dev-log") && logIds.size > 1) {
|
|
441
|
-
const cohabitingIds = [...logIds].filter((id) => id !== MARKLESS_EXECUTION_LOG_MODULE_ID).sort();
|
|
442
|
-
throw new Error(`Markless execution sizes require an isolated dev-log chunk; chunk "${chunk}" also contains logged module ids: ${cohabitingIds.join(", ")}.`);
|
|
443
|
-
}
|
|
444
|
-
const size = {
|
|
445
|
-
raw: item.code.length,
|
|
446
|
-
gzip: await gzipByteLength(item.code),
|
|
447
|
-
chunk
|
|
448
|
-
};
|
|
449
|
-
for (const id of logIds) entries[id] = id === "virtual:markless:dev-log" ? {
|
|
450
|
-
...size,
|
|
451
|
-
instrument: true
|
|
452
|
-
} : size;
|
|
453
|
-
}
|
|
454
|
-
return {
|
|
455
|
-
type: "asset",
|
|
456
|
-
fileName: MARKLESS_EXECUTION_SIZES,
|
|
457
|
-
source: JSON.stringify({
|
|
458
|
-
...sortRecord(entries),
|
|
459
|
-
...attribution && Object.keys(attribution).length > 0 ? { attribution: sortNestedRecord(attribution) } : {}
|
|
460
|
-
})
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
389
|
function executionLogActivationInjection(mode) {
|
|
464
390
|
if (normalizeExecutionLogMode(mode) === "never") return null;
|
|
465
391
|
return {
|
|
466
392
|
tag: "script",
|
|
467
393
|
location: "head",
|
|
468
|
-
children: `(() => { const l = location; if (${mode === "always" ? "true" : "/^https?:\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\])(?::|$)/.test(l.origin) || new URLSearchParams(l.search).has('markless-log') || (() => { try { return localStorage.getItem('marklessLog') === '1'; } catch { return false; } })()"}) globalThis.__mxLog = globalThis.__mxLog || new Set(); })();`
|
|
394
|
+
children: `(() => { const l = location; if (${mode === "always" ? "true" : "/^https?:\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\])(?::|$)/.test(l.origin) || new URLSearchParams(l.search).has('markless-log') || (() => { try { return localStorage.getItem('marklessLog') === '1'; } catch { return false; } })()"}) { globalThis.__mxLog = globalThis.__mxLog || new Set(); const g = globalThis.${MARKLESS_EXECUTION_LEDGER_GLOBAL} = globalThis.${MARKLESS_EXECUTION_LEDGER_GLOBAL} || ${MARKLESS_EXECUTION_LEDGER_INIT}; const s = document.currentScript && document.currentScript.textContent; if (s) { g.total.inline += s.length; if (!g.loadClosed) g.load.inline += s.length; } const c = (e) => { if (e.isTrusted) g.loadClosed = true; }; for (const t of ${JSON.stringify(EXECUTION_LOG_GESTURE_EVENTS)}) addEventListener(t, c, { capture: true, passive: true }); } })();`
|
|
469
395
|
};
|
|
470
396
|
}
|
|
471
|
-
function chunkModuleLogId(id) {
|
|
472
|
-
const path = stripResolvedIdMarker(id);
|
|
473
|
-
if (path === "virtual:markless:dev-log") return path;
|
|
474
|
-
const match = path.match(/[/\\](web|runtime|serializer)[/\\]src[/\\]([^?#]+)\.ts$/);
|
|
475
|
-
return match ? `${match[1]}:${match[2].replace(/[/\\]/g, "/")}` : null;
|
|
476
|
-
}
|
|
477
|
-
function stripResolvedIdMarker(id) {
|
|
478
|
-
return id.startsWith("\0") ? id.slice(1) : id;
|
|
479
|
-
}
|
|
480
|
-
async function gzipByteLength(code) {
|
|
481
|
-
const encoded = new TextEncoder().encode(code);
|
|
482
|
-
const reader = new ReadableStream({ start(controller) {
|
|
483
|
-
controller.enqueue(encoded);
|
|
484
|
-
controller.close();
|
|
485
|
-
} }).pipeThrough(new CompressionStream("gzip")).getReader();
|
|
486
|
-
let total = 0;
|
|
487
|
-
while (true) {
|
|
488
|
-
const { done, value } = await reader.read();
|
|
489
|
-
if (done) break;
|
|
490
|
-
total += value.byteLength;
|
|
491
|
-
}
|
|
492
|
-
return total;
|
|
493
|
-
}
|
|
494
|
-
function sortRecord(record) {
|
|
495
|
-
const next = {};
|
|
496
|
-
for (const key of Object.keys(record).sort()) next[key] = record[key];
|
|
497
|
-
return next;
|
|
498
|
-
}
|
|
499
|
-
function sortNestedRecord(record) {
|
|
500
|
-
const next = {};
|
|
501
|
-
for (const key of Object.keys(record).sort()) next[key] = sortRecord({ ...record[key] });
|
|
502
|
-
return next;
|
|
503
|
-
}
|
|
504
397
|
//#endregion
|
|
505
398
|
//#region src/source-module.ts
|
|
506
399
|
const MARKLESS_VIRTUAL_PREFIX = "virtual:markless:";
|
|
507
400
|
const SMALL_SYMBOL_DIRECT_LOAD_LIMIT = 8;
|
|
401
|
+
const MARKLESS_BOUND_SYMBOLS_EXPORT = "marklessBoundSymbols";
|
|
508
402
|
const SYMBOL_VIRTUAL_PREFIX = `${MARKLESS_VIRTUAL_PREFIX}symbol:`;
|
|
509
403
|
function symbolVirtualModuleId(filename, symbolId) {
|
|
510
404
|
return `${SYMBOL_VIRTUAL_PREFIX}${encodeURIComponent(filename)}:${encodeURIComponent(symbolId)}`;
|
|
@@ -528,6 +422,49 @@ function symbolVirtualModuleSourceFile(moduleId) {
|
|
|
528
422
|
function resumeVirtualModuleId(filename) {
|
|
529
423
|
return `${MARKLESS_VIRTUAL_PREFIX}resume:${encodeURIComponent(filename)}`;
|
|
530
424
|
}
|
|
425
|
+
function prerenderWakeVirtualModuleId(filename) {
|
|
426
|
+
return `${MARKLESS_VIRTUAL_PREFIX}prerender-wake:${encodeURIComponent(filename)}`;
|
|
427
|
+
}
|
|
428
|
+
function settleVirtualModuleId(filename) {
|
|
429
|
+
return `${MARKLESS_VIRTUAL_PREFIX}settle:${encodeURIComponent(filename)}`;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* The settle module: import targets and data, no logic. It carries the DOM
|
|
433
|
+
* filler, each boundary's async runner keyed by graph node, and each bound
|
|
434
|
+
* symbol's compiled derive function keyed by the id the fill plan references.
|
|
435
|
+
* Rolldown resolves the real chunk urls, so nothing here is a url the document
|
|
436
|
+
* has to carry, and a page that never settles an arm never loads it.
|
|
437
|
+
*/
|
|
438
|
+
function emitSettleModule(input) {
|
|
439
|
+
const imports = [...input.runners, ...input.derives].map((entry) => entry.symbol);
|
|
440
|
+
const seen = /* @__PURE__ */ new Map();
|
|
441
|
+
const lines = ["export { marklessApplySettlePlan as f } from '@markless/web/fns/settle-plan';"];
|
|
442
|
+
for (const symbol of imports) {
|
|
443
|
+
if (seen.has(symbol.id)) continue;
|
|
444
|
+
seen.set(symbol.id, symbol.exportName);
|
|
445
|
+
lines.push(`import { ${symbol.exportName} } from ${JSON.stringify(symbol.chunk)};`);
|
|
446
|
+
}
|
|
447
|
+
const entries = (rows) => `{${rows.map((row) => `${JSON.stringify(row.key)}: ${seen.get(row.symbolId)}`).join(",")}}`;
|
|
448
|
+
lines.push(`export const r = ${entries(input.runners.map((entry) => ({
|
|
449
|
+
key: entry.node,
|
|
450
|
+
symbolId: entry.symbol.id
|
|
451
|
+
})))};`);
|
|
452
|
+
lines.push(`export const d = ${entries(input.derives.map((entry) => ({
|
|
453
|
+
key: entry.id,
|
|
454
|
+
symbolId: entry.symbol.id
|
|
455
|
+
})))};`);
|
|
456
|
+
return `${lines.join("\n")}\n`;
|
|
457
|
+
}
|
|
458
|
+
function prerenderWakeVirtualModuleSourceFile(moduleId) {
|
|
459
|
+
const bare = moduleId.startsWith("\0") ? moduleId.slice(1) : moduleId;
|
|
460
|
+
const prefix = `${MARKLESS_VIRTUAL_PREFIX}prerender-wake:`;
|
|
461
|
+
if (!bare.startsWith(prefix)) return null;
|
|
462
|
+
try {
|
|
463
|
+
return decodeURIComponent(bare.slice(prefix.length));
|
|
464
|
+
} catch {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
531
468
|
function scopedSymbolExportName(filename, exportName) {
|
|
532
469
|
return `${exportName}_${stringHash(filename)}`;
|
|
533
470
|
}
|
|
@@ -557,25 +494,31 @@ function emitPublicRenderModule(source, input) {
|
|
|
557
494
|
].join("\n");
|
|
558
495
|
}
|
|
559
496
|
function emitSourceModule(input) {
|
|
497
|
+
if (input.directCsr && input.prerenderRecords) input = {
|
|
498
|
+
...input,
|
|
499
|
+
prerenderRecords: false
|
|
500
|
+
};
|
|
560
501
|
const symbolsOnly = input.environment === "client" && input.clientOutput === "symbols-only";
|
|
561
502
|
const routeSymbols = input.environment === "client" && input.symbolRoutes.length > 0;
|
|
503
|
+
const canonicalRenderData = input.environment === "client" && !symbolsOnly && !input.prerenderRecords && input.canonicalRenderData === true && input.publicRenderRootExportName === null && !!input.publicSsrModuleSource && !!input.renderDataId;
|
|
562
504
|
return [
|
|
505
|
+
!input.publicSsrModuleSource && !input.publicRenderModuleSource || symbolsOnly || !input.renderDataId || input.environment === "client" && !input.publicRenderModuleSource && !input.prerenderRecords && !input.dev && !canonicalRenderData ? "" : canonicalRenderData ? `import { marklessPrerenderData } from '${input.renderDataId}';` : `import { marklessRenderData } from '${input.renderDataId}';`,
|
|
563
506
|
symbolsOnly ? "" : `import { state as payloadState, view as payloadView, runtimeDemandMap as payloadRuntimeDemandMap } from '${input.payloadId}';`,
|
|
564
507
|
"",
|
|
565
508
|
emitLoadSymbol(input),
|
|
509
|
+
input.behaviorSymbols?.length ? emitDirectSourceSymbolLoader(input.behaviorSymbols, "readMarklessBehaviorSourceSymbol").replace("function loadSymbol(", "function loadBehaviorSymbol(") : "",
|
|
566
510
|
input.environment === "client" && input.executionLog !== "never" ? emitExecutionLogLoader() : "",
|
|
567
511
|
routeSymbols ? "const marklessLoadLocalSymbol = loadSymbol;" : "",
|
|
568
|
-
symbolsOnly && !routeSymbols ? "export { loadSymbol };" : "",
|
|
512
|
+
(symbolsOnly || input.publicRenderRootExportName === null) && !routeSymbols ? "export { loadSymbol };" : "",
|
|
569
513
|
symbolsOnly ? "" : "export { payloadView };",
|
|
570
514
|
symbolsOnly ? "" : "export { payloadRuntimeDemandMap };",
|
|
571
515
|
input.devResumeReexport && input.environment === "client" ? `export { resumeContainerEvent } from '${resumeVirtualModuleId(input.filename)}';` : "",
|
|
572
516
|
"",
|
|
573
|
-
input.environment === "server" || symbolsOnly ? "" : emitPublicRenderModule(input.publicRenderModuleSource, {
|
|
517
|
+
input.environment === "server" || symbolsOnly || input.prerenderRecords ? "" : emitPublicRenderModule(input.publicRenderModuleSource, {
|
|
574
518
|
executionLogEnabled: input.executionLog !== "never",
|
|
575
519
|
rootExportName: input.publicRenderRootExportName
|
|
576
520
|
}),
|
|
577
|
-
input.environment === "
|
|
578
|
-
input.environment === "client" ? "" : input.publicSsrModuleSource,
|
|
521
|
+
input.environment === "client" && (symbolsOnly || !input.prerenderRecords && !input.dev) ? "" : input.publicSsrModuleSource,
|
|
579
522
|
routeSymbols ? emitLazySymbolRouteFunction(input.symbolRoutes, "marklessSsrLoadSymbolRoute", "marklessLoadLocalSymbol") : "",
|
|
580
523
|
symbolsOnly && routeSymbols ? "export { marklessSsrLoadSymbolRoute as loadSymbol };" : "",
|
|
581
524
|
symbolsOnly ? "" : emitCompiledAppDefault({
|
|
@@ -584,10 +527,15 @@ function emitSourceModule(input) {
|
|
|
584
527
|
headInjections: input.headInjections,
|
|
585
528
|
storageSeeds: input.storageSeeds,
|
|
586
529
|
inlineResumerSources: input.inlineResumerSources,
|
|
530
|
+
prerenderBoot: input.prerenderBoot,
|
|
587
531
|
resumeModuleUrl: input.resumeModuleUrl,
|
|
532
|
+
prerenderWakeModuleUrl: input.prerenderWakeModuleUrl,
|
|
588
533
|
rootExportName: input.publicRenderRootExportName,
|
|
589
|
-
|
|
590
|
-
ssrExportName: input.publicRenderSsrExportName
|
|
534
|
+
symbolLoaderName: routeSymbols ? "marklessSsrLoadSymbolRoute" : "loadSymbol",
|
|
535
|
+
ssrExportName: input.publicRenderSsrExportName,
|
|
536
|
+
canonicalRenderData,
|
|
537
|
+
prerenderRecords: input.prerenderRecords,
|
|
538
|
+
dev: input.dev
|
|
591
539
|
}),
|
|
592
540
|
""
|
|
593
541
|
].filter((line) => line !== null).join("\n");
|
|
@@ -596,24 +544,63 @@ function emitResumeModule(input) {
|
|
|
596
544
|
const routeSymbols = input.symbolRoutes.length > 0;
|
|
597
545
|
const resumeSymbolLoader = routeSymbols ? "marklessSsrLoadSymbolRoute" : "loadSymbol";
|
|
598
546
|
const scalarSpecializations = scalarDispatcherSpecializations(input);
|
|
547
|
+
const stagedPrerender = (input.prerenderTriggerGroups?.length ?? 0) > 0;
|
|
548
|
+
const streamedResume = stagedPrerender || (input.payloadView?.asyncBoundaries?.length ?? 0) > 0;
|
|
549
|
+
const bareResumeContainerEvent = emitResumeContainerEvent(resumeSymbolLoader, input.needsFullResume ?? false, input.payloadState?.version === ASYNC_PROTOCOL_VERSION, input.symbolRoutes.length > 0 ? "none" : leanResumeMode(input.runtimeDemandMap), scalarSpecializations, input.runtimeDemandMap, input.executionLog !== "never", input.prerenderDataId, stagedPrerender);
|
|
550
|
+
const resumeContainerEvent = streamedResume ? emitQueuedResumeContainerEvent(bareResumeContainerEvent) : bareResumeContainerEvent;
|
|
599
551
|
return [
|
|
552
|
+
input.boundSymbolDescriptors ? `export const ${MARKLESS_BOUND_SYMBOLS_EXPORT} = ${emitBoundSymbolDescriptors(input.boundSymbolDescriptors)};` : null,
|
|
553
|
+
input.prerenderDataId && !stagedPrerender && resumeContainerEvent.includes("marklessPrerenderData") ? `import { marklessPrerenderData } from '${input.prerenderDataId}';` : null,
|
|
554
|
+
stagedPrerender && input.prerenderDataId ? `async function marklessLoadPrerenderData() { const module = await import('${input.prerenderDataId}'); return module.marklessPrerenderData; }` : null,
|
|
600
555
|
`import { runtimeDemandMap as payloadRuntimeDemandMap } from '${input.payloadId}';`,
|
|
601
556
|
scalarSpecializations.length > 0 ? [
|
|
602
|
-
"import { marklessDecodeScalarCell,
|
|
557
|
+
"import { marklessDecodeScalarCell, marklessReadScalarCell, marklessScalarSpecializedError } from '@markless/web/fns/scalar-specialized';",
|
|
603
558
|
"import { marklessWriteScalar } from '@markless/web/fns/write-scalar';",
|
|
604
559
|
"import { marklessUpdateText } from '@markless/web/fns/update-text';"
|
|
605
560
|
].join("\n") : "",
|
|
561
|
+
scalarSpecializations.length > 0 || stagedPrerender ? "import { marklessFindElementAtDomOrderIndex } from '@markless/web/fns/dom-order';" : "",
|
|
606
562
|
"",
|
|
607
563
|
input.executionLog === "never" ? "" : emitExecutionLogLoader(),
|
|
564
|
+
input.installResumeSummary && input.executionLog !== "never" ? "globalThis.__mxLoadLog().then(log => log.installMarklessExecutionLog());" : null,
|
|
608
565
|
"",
|
|
609
|
-
emitLoadSymbol(input),
|
|
566
|
+
emitLoadSymbol(input, stagedPrerender ? "readMarklessWakeSourceSymbol" : void 0),
|
|
610
567
|
routeSymbols ? "const marklessLoadLocalSymbol = loadSymbol;" : "",
|
|
611
568
|
routeSymbols ? emitLazySymbolRouteFunction(input.symbolRoutes, "marklessSsrLoadSymbolRoute", "marklessLoadLocalSymbol") : "",
|
|
612
569
|
routeSymbols ? "export { marklessSsrLoadSymbolRoute as loadSymbol };" : "",
|
|
613
|
-
|
|
570
|
+
stagedPrerender ? emitPrerenderTriggerGroupLoader(input.prerenderTriggerGroups ?? []) : "",
|
|
571
|
+
resumeContainerEvent,
|
|
614
572
|
""
|
|
615
573
|
].filter((line) => line !== null).join("\n");
|
|
616
574
|
}
|
|
575
|
+
function emitBoundSymbolDescriptors(descriptors) {
|
|
576
|
+
return JSON.stringify(Object.fromEntries(Object.keys(descriptors).sort().map((boundaryId) => [boundaryId, descriptors[boundaryId]])));
|
|
577
|
+
}
|
|
578
|
+
function emitQueuedResumeContainerEvent(source) {
|
|
579
|
+
const implementation = source.replace("export async function resumeContainerEvent", "async function marklessResumeContainerEvent");
|
|
580
|
+
if (implementation === source) throw new Error("MARKLESS_RESUME_DISPATCH_EXPORT_MISSING");
|
|
581
|
+
return [
|
|
582
|
+
implementation,
|
|
583
|
+
"export function resumeContainerEvent(input) {",
|
|
584
|
+
" const root = input.root;",
|
|
585
|
+
" if (!root.__marklessDispatch) {",
|
|
586
|
+
" let handler = marklessResumeContainerEvent, tail = Promise.resolve(), lastEvent = null, lastEventTime = undefined;",
|
|
587
|
+
" root.__marklessRegisterDispatch = next => {",
|
|
588
|
+
" const fallback = handler;",
|
|
589
|
+
" handler = input => next(input, fallback);",
|
|
590
|
+
" };",
|
|
591
|
+
" root.__marklessDispatch = next => {",
|
|
592
|
+
" const event = next.event, eventTime = event?.timeStamp;",
|
|
593
|
+
" if (event === lastEvent && eventTime === lastEventTime) return tail;",
|
|
594
|
+
" lastEvent = event;",
|
|
595
|
+
" lastEventTime = eventTime;",
|
|
596
|
+
" const run = () => handler(next);",
|
|
597
|
+
" return tail = tail.then(run, run);",
|
|
598
|
+
" };",
|
|
599
|
+
" }",
|
|
600
|
+
" return root.__marklessDispatch(input);",
|
|
601
|
+
"}"
|
|
602
|
+
].join("\n");
|
|
603
|
+
}
|
|
617
604
|
function emitLazySymbolRouteFunction(routes, functionName, fallbackName = "loadSymbol") {
|
|
618
605
|
if (routes.length === 0) return "";
|
|
619
606
|
return [
|
|
@@ -631,14 +618,18 @@ function symbolRouteImportSource(importSource) {
|
|
|
631
618
|
return importSource.includes("?") ? `${importSource}&markless-symbols` : `${importSource}?markless-symbols`;
|
|
632
619
|
}
|
|
633
620
|
function emitCompiledAppDefault(input) {
|
|
634
|
-
const renderCsrEntry =
|
|
635
|
-
const
|
|
621
|
+
const renderCsrEntry = input.rootExportName && input.environment !== "server" && !input.prerenderRecords ? [` renderCsr: ${input.rootExportName},`] : [];
|
|
622
|
+
const symbolLoaderEntry = input.environment !== "server" && input.rootExportName === null ? [`\tloadSymbol: ${input.symbolLoaderName},`] : input.prerenderRecords === true ? [`\tloadSymbol: ${input.symbolLoaderName},`] : [];
|
|
623
|
+
const renderDataEntry = input.canonicalRenderData ? [" renderData: marklessPrerenderData,"] : [];
|
|
624
|
+
const renderSsrEntry = input.ssrExportName && (input.environment !== "client" || input.prerenderRecords || input.dev) ? [
|
|
636
625
|
" renderSsr(props, marklessRenderContext) {",
|
|
637
626
|
` return ${input.ssrExportName}(props, marklessRenderContext);`,
|
|
638
627
|
" },"
|
|
639
628
|
] : [];
|
|
640
629
|
const resumeModuleEntry = input.resumeModuleUrl && input.environment !== "client" ? [` resumeModuleUrl: ${JSON.stringify(input.resumeModuleUrl)},`] : [];
|
|
630
|
+
const prerenderWakeModuleEntry = input.prerenderWakeModuleUrl && input.environment !== "client" ? [`\tprerenderWakeModuleUrl: ${JSON.stringify(input.prerenderWakeModuleUrl)},`] : [];
|
|
641
631
|
const inlineResumerEntry = input.inlineResumerSources && input.environment !== "client" ? [`\tinlineResumerSources: ${JSON.stringify(input.inlineResumerSources)},`] : [];
|
|
632
|
+
const prerenderBootEntry = input.prerenderBoot && input.environment !== "client" ? [`\tprerenderBoot: ${JSON.stringify(input.prerenderBoot)},`] : [];
|
|
642
633
|
const headInjectionEntry = input.headInjections?.length && input.environment !== "client" ? [` headInjections: ${JSON.stringify(input.headInjections)},`] : [];
|
|
643
634
|
const storageSeedEntry = input.storageSeeds?.length && input.environment !== "client" ? [`\tstorageSeeds: ${JSON.stringify(input.storageSeeds)},`] : [];
|
|
644
635
|
const modulePreloadEntry = input.resumeModuleUrl && input.environment === "server" ? [` modulePreloads: [{ href: ${JSON.stringify(input.resumeModuleUrl)}, fetchPriority: "high" }],`] : [];
|
|
@@ -646,7 +637,9 @@ function emitCompiledAppDefault(input) {
|
|
|
646
637
|
...headInjectionEntry,
|
|
647
638
|
...storageSeedEntry,
|
|
648
639
|
...resumeModuleEntry,
|
|
640
|
+
...prerenderWakeModuleEntry,
|
|
649
641
|
...inlineResumerEntry,
|
|
642
|
+
...prerenderBootEntry,
|
|
650
643
|
...modulePreloadEntry,
|
|
651
644
|
input.executionLog && input.executionLog !== "never" ? ` executionLog: ${JSON.stringify(input.executionLog)},` : "",
|
|
652
645
|
" payloadView,"
|
|
@@ -654,17 +647,62 @@ function emitCompiledAppDefault(input) {
|
|
|
654
647
|
return [
|
|
655
648
|
"const marklessCompiledApp = {",
|
|
656
649
|
...renderCsrEntry,
|
|
650
|
+
...renderDataEntry,
|
|
651
|
+
...symbolLoaderEntry,
|
|
657
652
|
...renderSsrEntry,
|
|
658
653
|
...metadataEntries,
|
|
659
654
|
"};",
|
|
660
655
|
"export default marklessCompiledApp;"
|
|
661
656
|
].join("\n");
|
|
662
657
|
}
|
|
663
|
-
function emitResumeContainerEvent(loadSymbolName, needsFullResume, leanMode, scalarSpecializations, runtimeDemandMap, executionLogEnabled) {
|
|
664
|
-
const fullResumeHandoff = [
|
|
658
|
+
function emitResumeContainerEvent(loadSymbolName, needsFullResume, storageFreePayload, leanMode, scalarSpecializations, runtimeDemandMap, executionLogEnabled, prerenderDataId, stagedPrerender = false) {
|
|
659
|
+
const fullResumeHandoff = stagedPrerender && prerenderDataId ? [
|
|
660
|
+
"async function marklessFullResumeHandoff(handoff) {",
|
|
661
|
+
" handoff.root.__asyncResumeRuntimeStarted = true;",
|
|
662
|
+
" const group = await marklessLoadPrerenderTriggerGroup(handoff);",
|
|
663
|
+
" const { mergePrerenderPayloadRecords, resumePrerenderTriggerGroup } = await import('@markless/web/fns/prerender-trigger-resume');",
|
|
664
|
+
" if (!group) {",
|
|
665
|
+
" const { derivePrerenderResumeRecords, renderPrerenderBoundary, resumeFromPrerenderRecords } = await import('@markless/web/fns/prerender-resume');",
|
|
666
|
+
" handoff.root.__marklessFullResumeRuntime ??= (async () => {",
|
|
667
|
+
" const marklessPrerenderData = await marklessLoadPrerenderData();",
|
|
668
|
+
`\t\t\tconst fallbackRecords = mergePrerenderPayloadRecords(await derivePrerenderResumeRecords(marklessPrerenderData, ${loadSymbolName}), handoff.root);`,
|
|
669
|
+
" return (await resumeFromPrerenderRecords({",
|
|
670
|
+
" ...fallbackRecords,",
|
|
671
|
+
" root: handoff.root,",
|
|
672
|
+
`\t\t\t\tloadSymbol: ${loadSymbolName},`,
|
|
673
|
+
`\t\t\t\trenderAsyncBoundary: (boundaryId, status, graph) => renderPrerenderBoundary(marklessPrerenderData, boundaryId, status, graph, ${loadSymbolName}),`,
|
|
674
|
+
" })).runtime;",
|
|
675
|
+
" })();",
|
|
676
|
+
" const marklessFullRuntime = await handoff.root.__marklessFullResumeRuntime;",
|
|
677
|
+
" await marklessFullRuntime.dispatch(handoff.event, { syncPolicyAlreadyApplied: handoff.syncPolicyAlreadyApplied === true, ignoreUnmatched: true });",
|
|
678
|
+
" return;",
|
|
679
|
+
" }",
|
|
680
|
+
" const records = mergePrerenderPayloadRecords({ state: group.state, view: group.view }, handoff.root);",
|
|
681
|
+
" const { runtime } = await resumePrerenderTriggerGroup({",
|
|
682
|
+
" ...records, groupId: group.groupId, graphNodeIds: group.graphNodeIds,",
|
|
683
|
+
" root: handoff.root, loadSymbol: group.loadSymbol, prepareBoundaryArm: group.prepareBoundaryArm, renderBoundaryArm: group.renderBoundaryArm,",
|
|
684
|
+
" });",
|
|
685
|
+
" await runtime.dispatch(handoff.event, { syncPolicyAlreadyApplied: handoff.syncPolicyAlreadyApplied === true, ignoreUnmatched: true });",
|
|
686
|
+
"}"
|
|
687
|
+
].join("\n") : prerenderDataId ? [
|
|
665
688
|
"async function marklessFullResumeHandoff(handoff) {",
|
|
689
|
+
" handoff.root.__marklessLinkedRenderDataBoot = true;",
|
|
666
690
|
" handoff.root.__asyncResumeRuntimeStarted = true;",
|
|
667
|
-
" const {
|
|
691
|
+
" const { derivePrerenderResumeRecords, mergePrerenderPayloadRecords, renderPrerenderBoundary, resumeFromPrerenderRecords } = await import('@markless/web/fns/prerender-resume');",
|
|
692
|
+
`\tconst records = await derivePrerenderResumeRecords(marklessPrerenderData, ${loadSymbolName});`,
|
|
693
|
+
" const mergedRecords = mergePrerenderPayloadRecords(records, handoff.root);",
|
|
694
|
+
" const { runtime } = await resumeFromPrerenderRecords({",
|
|
695
|
+
" ...mergedRecords,",
|
|
696
|
+
" root: handoff.root,",
|
|
697
|
+
`\t\tloadSymbol: ${loadSymbolName},`,
|
|
698
|
+
`\t\trenderAsyncBoundary: (boundaryId, status, graph) => renderPrerenderBoundary(marklessPrerenderData, boundaryId, status, graph, ${loadSymbolName}),`,
|
|
699
|
+
" });",
|
|
700
|
+
" await runtime.dispatch(handoff.event, { syncPolicyAlreadyApplied: handoff.syncPolicyAlreadyApplied === true, ignoreUnmatched: true });",
|
|
701
|
+
"}"
|
|
702
|
+
].join("\n") : [
|
|
703
|
+
"async function marklessFullResumeHandoff(handoff) {",
|
|
704
|
+
" handoff.root.__asyncResumeRuntimeStarted = true;",
|
|
705
|
+
` const { resumeFromPayloadDocument } = await import('${storageFreePayload ? "@markless/core/web/resume-storage-free" : "@markless/core/web/resume"}');`,
|
|
668
706
|
" const { runtime } = await resumeFromPayloadDocument({",
|
|
669
707
|
" document: handoff.document,",
|
|
670
708
|
" root: handoff.root,",
|
|
@@ -722,6 +760,7 @@ function emitResumeContainerEvent(loadSymbolName, needsFullResume, leanMode, sca
|
|
|
722
760
|
"}"
|
|
723
761
|
].join("\n");
|
|
724
762
|
}
|
|
763
|
+
if (prerenderDataId) return "export async function resumeContainerEvent(_input) {}";
|
|
725
764
|
return [
|
|
726
765
|
fullResumeHandoff,
|
|
727
766
|
"export async function resumeContainerEvent(input) {",
|
|
@@ -729,6 +768,37 @@ function emitResumeContainerEvent(loadSymbolName, needsFullResume, leanMode, sca
|
|
|
729
768
|
"}"
|
|
730
769
|
].join("\n");
|
|
731
770
|
}
|
|
771
|
+
function emitPrerenderTriggerGroupLoader(groups) {
|
|
772
|
+
return [
|
|
773
|
+
"function marklessPrerenderTriggerMatches(input, index, tagName, eventName) {",
|
|
774
|
+
" if (input.event?.type !== eventName) return false;",
|
|
775
|
+
" const host = marklessFindElementAtDomOrderIndex(input.root, index);",
|
|
776
|
+
" if (!host || (tagName !== \"*\" && host.tagName.toLowerCase() !== tagName)) return false;",
|
|
777
|
+
" const target = input.event?.target;",
|
|
778
|
+
" return host === target || (!!target?.nodeType && typeof host.contains === \"function\" && host.contains(target));",
|
|
779
|
+
"}",
|
|
780
|
+
"function marklessPrerenderBranchTriggerMatches(input, startIndex, endIndex, hostPath, eventName) {",
|
|
781
|
+
" if (input.event?.type !== eventName) return false;",
|
|
782
|
+
" const comments = [];",
|
|
783
|
+
" const collect = node => { for (const child of node.childNodes ?? []) { if (child.nodeType === 8) comments.push(child); collect(child); } };",
|
|
784
|
+
" collect(input.root);",
|
|
785
|
+
" const start = comments[startIndex], end = comments[endIndex], armNodes = [];",
|
|
786
|
+
" let within = false, done = false;",
|
|
787
|
+
" const between = node => { for (const child of node.childNodes ?? []) { if (child === start) { within = true; continue; } if (child === end) { done = true; return; } if (within) armNodes.push(child); else between(child); if (done) return; } };",
|
|
788
|
+
" between(input.root);",
|
|
789
|
+
" let host = armNodes[hostPath[0]];",
|
|
790
|
+
" for (let index = 1; host && index < hostPath.length; index++) host = host.childNodes?.[hostPath[index]];",
|
|
791
|
+
" const target = input.event?.target;",
|
|
792
|
+
" return host?.nodeType === 1 && (host === target || (!!target?.nodeType && typeof host.contains === \"function\" && host.contains(target)));",
|
|
793
|
+
"}",
|
|
794
|
+
"function marklessLoadPrerenderTriggerGroup(input) {",
|
|
795
|
+
...groups.map((group) => {
|
|
796
|
+
return `\tif (${group.eventName === "self-wake" ? "input.event === 0" : group.hostPath ? `marklessPrerenderBranchTriggerMatches(input, ${group.branchStartIndex}, ${group.branchEndIndex}, ${JSON.stringify(group.hostPath)}, ${JSON.stringify(group.eventName)})` : `marklessPrerenderTriggerMatches(input, ${group.hostIndex}, ${JSON.stringify(group.hostTagName.toLowerCase())}, ${JSON.stringify(group.eventName)})`}) return import(${JSON.stringify(group.moduleId)});`;
|
|
797
|
+
}),
|
|
798
|
+
" return Promise.resolve(null);",
|
|
799
|
+
"}"
|
|
800
|
+
].join("\n");
|
|
801
|
+
}
|
|
732
802
|
function scalarDispatcherSpecializations(input) {
|
|
733
803
|
const state = input.payloadState;
|
|
734
804
|
const view = input.payloadView;
|
|
@@ -740,11 +810,12 @@ function scalarDispatcherSpecializations(input) {
|
|
|
740
810
|
const plan = action?.plan;
|
|
741
811
|
if (action?.recordKind !== "event" || plan?.version !== 1 || plan?.kind !== "scalar") return [];
|
|
742
812
|
const cellIndex = cells.findIndex((cell) => cell?.graphNodeId === plan.cell);
|
|
813
|
+
const initialCell = cells[cellIndex];
|
|
743
814
|
const host = locators.find((locator) => locator?.hostNodeId === action.hostNodeId);
|
|
744
815
|
const event = view?.events?.find((candidate) => candidate?.hostNodeId === action.hostNodeId && candidate?.eventName === action.eventName);
|
|
745
816
|
const symbolId = scalarActionSymbolId(plan.symbolId, event, input.symbolRoutes ?? []);
|
|
746
817
|
if (!symbolId) return [];
|
|
747
|
-
if (cellIndex < 0 || !host || typeof host.index !== "number") return [];
|
|
818
|
+
if (cellIndex < 0 || !initialCell || !host || typeof host.index !== "number") return [];
|
|
748
819
|
if (event && syncPolicyGraphNodeIds(event.syncPolicy).some((graphNodeId) => graphNodeId !== plan.cell)) return [];
|
|
749
820
|
const textUpdates = (plan.textUpdates ?? []).flatMap((update) => {
|
|
750
821
|
const locator = locators.find((candidate) => candidate?.hostNodeId === update.hostNodeId);
|
|
@@ -763,6 +834,7 @@ function scalarDispatcherSpecializations(input) {
|
|
|
763
834
|
symbolId,
|
|
764
835
|
cell: plan.cell,
|
|
765
836
|
cellIndex,
|
|
837
|
+
initialCell,
|
|
766
838
|
hostIndex: host.index,
|
|
767
839
|
hostTagName: String(host.tagName ?? "*"),
|
|
768
840
|
syncPolicy: event?.syncPolicy ?? null,
|
|
@@ -826,7 +898,7 @@ function emitScalarAction(action, loadSymbolName) {
|
|
|
826
898
|
" let syncPolicyAlreadyApplied = input.syncPolicyAlreadyApplied === true;",
|
|
827
899
|
" const values = input.root.__marklessEventOnlyGraph || new Map();",
|
|
828
900
|
" input.root.__marklessEventOnlyGraph = values;",
|
|
829
|
-
` if (!values.has(${JSON.stringify(action.cell)})) values.set(${JSON.stringify(action.cell)}, marklessDecodeScalarCell(marklessReadScalarCell(input.root, ${action.
|
|
901
|
+
` if (!values.has(${JSON.stringify(action.cell)})) values.set(${JSON.stringify(action.cell)}, marklessDecodeScalarCell(marklessReadScalarCell(input.root, ${JSON.stringify(action.cell)}) ?? ${JSON.stringify(action.initialCell)}, ${JSON.stringify(action.cell)}, ${JSON.stringify(`markless/state cell ${action.cell}`)}));`,
|
|
830
902
|
` const state = { value: values.get(${JSON.stringify(action.cell)}), dirty: false };`,
|
|
831
903
|
" try {",
|
|
832
904
|
` const host = marklessFindElementAtDomOrderIndex(input.root, ${action.hostIndex});`,
|
|
@@ -907,8 +979,12 @@ function leanResumeMode(runtimeDemandMap) {
|
|
|
907
979
|
function emitExecutionLogLoader() {
|
|
908
980
|
return `globalThis.__mxLoadLog ||= () => import(${JSON.stringify(MARKLESS_EXECUTION_LOG_MODULE_ID)});`;
|
|
909
981
|
}
|
|
910
|
-
function emitLoadSymbol(input) {
|
|
911
|
-
if (
|
|
982
|
+
function emitLoadSymbol(input, sourceReaderName) {
|
|
983
|
+
if (input.symbols.length > 0 && input.symbols.length <= SMALL_SYMBOL_DIRECT_LOAD_LIMIT) {
|
|
984
|
+
const direct = emitDirectSourceSymbolLoader(input.symbols, sourceReaderName);
|
|
985
|
+
if (!input.hasBoundSymbols) return direct;
|
|
986
|
+
return [`const marklessSymbolResolverModule = () => import('${input.resolverId}');`, direct.replace(" return Promise.reject(new Error(`Unknown async symbol ${symbolId}`));", " return marklessSymbolResolverModule().then((mod) => mod.loadSymbol(symbolId));")].join("\n");
|
|
987
|
+
}
|
|
912
988
|
return [
|
|
913
989
|
`const marklessSymbolResolverModule = () => import('${input.resolverId}');`,
|
|
914
990
|
"function loadSymbol(symbolId) {",
|
|
@@ -916,18 +992,18 @@ function emitLoadSymbol(input) {
|
|
|
916
992
|
"}"
|
|
917
993
|
].join("\n");
|
|
918
994
|
}
|
|
919
|
-
function emitDirectSourceSymbolLoader(symbols) {
|
|
995
|
+
function emitDirectSourceSymbolLoader(symbols, readerName = "readMarklessSourceSymbol") {
|
|
920
996
|
return [
|
|
921
997
|
"function loadSymbol(symbolId) {",
|
|
922
|
-
...symbols.flatMap((symbol) => [` if (symbolId === ${JSON.stringify(symbol.id)}) return import('${symbol.chunk}')`, ` .then((mod) =>
|
|
998
|
+
...symbols.flatMap((symbol) => [` if (symbolId === ${JSON.stringify(symbol.id)}) return import('${symbol.chunk}')`, ` .then((mod) => ${readerName}(mod, ${JSON.stringify(symbol.exportName)}));`]),
|
|
923
999
|
" return Promise.reject(new Error(`Unknown async symbol ${symbolId}`));",
|
|
924
1000
|
"}",
|
|
925
|
-
emitSourceSymbolExportReader()
|
|
1001
|
+
emitSourceSymbolExportReader(readerName)
|
|
926
1002
|
].join("\n");
|
|
927
1003
|
}
|
|
928
|
-
function emitSourceSymbolExportReader() {
|
|
1004
|
+
function emitSourceSymbolExportReader(name = "readMarklessSourceSymbol") {
|
|
929
1005
|
return [
|
|
930
|
-
|
|
1006
|
+
`function ${name}(mod, exportName) {`,
|
|
931
1007
|
" mod.init__virtual_markless_symbol?.();",
|
|
932
1008
|
" return mod[exportName];",
|
|
933
1009
|
"}"
|
|
@@ -942,4 +1018,4 @@ function stringHash(value) {
|
|
|
942
1018
|
return (hash >>> 0).toString(36);
|
|
943
1019
|
}
|
|
944
1020
|
//#endregion
|
|
945
|
-
export {
|
|
1021
|
+
export { planModulePreloadUrls as C, requalifyExecutionLogModuleHook as S, executionLogActivationInjection as _, encodedSymbolSource as a, injectExecutionLogModuleHook as b, prerenderWakeVirtualModuleSourceFile as c, scopedSymbolExportName as d, settleVirtualModuleId as f, MARKLESS_EXECUTION_LOG_MODULE_ID as g, EXECUTION_LOG_DISPATCH_MODULE_IDS as h, emitSourceModule as i, resumeVirtualModuleId as l, symbolVirtualModuleSourceFile as m, emitResumeModule as n, payloadModule as o, symbolVirtualModuleId as p, emitSettleModule as r, prerenderWakeVirtualModuleId as s, MARKLESS_VIRTUAL_PREFIX as t, rewriteSymbolModuleExport as u, executionLogVirtualModuleSource as v, planModulePreloads as w, normalizeExecutionLogMode as x, hasExecutionLogModuleHook as y };
|