@markless/bundler 0.1.1 → 0.2.1

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/dist/vite.js CHANGED
@@ -1,6 +1,9 @@
1
- import { b as outputDefaults, p as executionLogActivationInjection } from "./source-module-CSRzW4Ny.js";
2
- import { l as createPreloadGraphAdder, t as createMarklessRolldownPlugin } from "./rolldown-Czh1duwk.js";
1
+ import { MARKLESS_DEV_ERROR_CLEAR_EVENT, MARKLESS_DEV_ERROR_CLIENT_ID, MARKLESS_DEV_ERROR_EVENT, normalizeMarklessDevError } from "./dev-error.js";
2
+ import { m as executionLogActivationInjection, x as outputDefaults } from "./source-module-C8W2THUI.js";
3
+ import { a as preflightTsrxModuleDiagnostics, t as createMarklessRolldownPlugin, u as createPreloadGraphAdder } from "./rolldown-CpG_S-ZJ.js";
3
4
  import { joinURL, parsePath } from "ufo";
5
+ import { readFile } from "node:fs/promises";
6
+ import { isAbsolute } from "node:path";
4
7
  //#region src/vite/dev-tags.ts
5
8
  function createDevTags() {
6
9
  const tags = [];
@@ -61,27 +64,211 @@ function fetchableDevEnvironment(environment) {
61
64
  if (typeof maybeFetchable.dispatchFetch === "function") return maybeFetchable;
62
65
  }
63
66
  //#endregion
67
+ //#region src/dev-error/client-asset.ts
68
+ function createDevErrorClientAsset(viteClientUrl) {
69
+ const base = viteClientUrl.endsWith("/@vite/client") ? viteClientUrl.slice(0, -13) : "";
70
+ return `import { createHotContext } from ${JSON.stringify(viteClientUrl)};
71
+ const hot = createHotContext(${JSON.stringify(MARKLESS_DEV_ERROR_CLIENT_ID)});
72
+ const ERROR_EVENT = ${JSON.stringify(MARKLESS_DEV_ERROR_EVENT)};
73
+ const CLEAR_EVENT = ${JSON.stringify(MARKLESS_DEV_ERROR_CLEAR_EVENT)};
74
+ const ELEMENT = 'markless-dev-error-overlay';
75
+ const SUPPRESSION = 'data-markless-vite-overlay-suppression';
76
+ const OPEN_IN_EDITOR = ${JSON.stringify(`${base}/__open-in-editor`)};
77
+ let currentPayload;
78
+ let observer;
79
+
80
+ const styles = ${JSON.stringify(`
81
+ :host{position:fixed;inset:0;z-index:2147483647;display:grid;place-items:center;padding:clamp(1rem,4vw,3rem);background:#0008;color:CanvasText;font-family:system-ui,sans-serif}
82
+ *{box-sizing:border-box}.panel{width:min(60rem,100%);max-height:calc(100vh - 2rem);overflow:auto;padding:clamp(1.25rem,3vw,2.5rem);border:1px solid color-mix(in srgb,CanvasText 20%,transparent);border-top:4px solid #c9362b;border-radius:.5rem;background:Canvas;box-shadow:0 1rem 3rem #0006}
83
+ header{display:flex;flex-direction:column;gap:.6rem}.badge{align-self:flex-start;padding:.15rem .45rem;border-radius:.25rem;background:color-mix(in srgb,#c9362b 14%,Canvas);color:#c9362b;font:600 .75rem ui-monospace,monospace}h1{margin:0;font-size:clamp(1.4rem,3vw,2rem);line-height:1.2}h2{margin:1rem 0 .25rem;font-size:.8rem;text-transform:uppercase;letter-spacing:.06em;color:color-mix(in srgb,CanvasText 65%,transparent)}p{margin:.3rem 0 1rem;line-height:1.55}a{color:LinkText}.location{display:inline-block;margin-top:1rem;font:500 .9rem ui-monospace,monospace}.frame,details pre{overflow:auto;padding:1rem;border-radius:.35rem;background:color-mix(in srgb,CanvasText 7%,Canvas);font:.85rem/1.55 ui-monospace,monospace;white-space:pre}details{margin-top:1rem;border-top:1px solid color-mix(in srgb,CanvasText 15%,transparent);padding-top:1rem}summary{cursor:pointer;font-weight:600}.recovery{margin:1.5rem 0 0;color:color-mix(in srgb,CanvasText 65%,transparent);font-size:.9rem}`)};
84
+
85
+ function append(parent, tag, text, className) {
86
+ const node = document.createElement(tag);
87
+ if (text !== undefined) node.textContent = text;
88
+ if (className) node.className = className;
89
+ parent.append(node);
90
+ return node;
91
+ }
92
+ function diagnosticBody(parent, diagnostic) {
93
+ if (diagnostic.filename && diagnostic.line != null && diagnostic.column != null) {
94
+ const link = append(parent, 'a', diagnostic.filename + ':' + diagnostic.line + ':' + diagnostic.column, 'location');
95
+ link.href = new URL(OPEN_IN_EDITOR + '?file=' + encodeURIComponent(diagnostic.filename + ':' + diagnostic.line + ':' + diagnostic.column), document.baseURI).href;
96
+ }
97
+ if (diagnostic.why) { const section = append(parent, 'section'); append(section, 'h2', 'Why'); append(section, 'p', diagnostic.why); }
98
+ if (diagnostic.suggestion) { const section = append(parent, 'section'); append(section, 'h2', 'Suggested fix'); append(section, 'p', diagnostic.suggestion); }
99
+ if (diagnostic.frame) append(parent, 'pre', diagnostic.frame, 'frame');
100
+ if (diagnostic.docsUrl) {
101
+ try {
102
+ const url = new URL(diagnostic.docsUrl);
103
+ if (url.protocol === 'http:' || url.protocol === 'https:') { const paragraph = append(parent, 'p'); const link = append(paragraph, 'a', 'Read ' + diagnostic.code + ' documentation'); link.href = url.href; }
104
+ } catch { /* Invalid documentation URLs are omitted. */ }
105
+ }
106
+ }
107
+ class MarklessDevErrorOverlay extends HTMLElement {
108
+ constructor() {
109
+ super();
110
+ const shadow = this.attachShadow({ mode: 'open' });
111
+ const style = append(shadow, 'style'); style.textContent = styles;
112
+ const panel = append(shadow, 'article', undefined, 'panel');
113
+ panel.addEventListener('click', (event) => event.stopPropagation());
114
+ this.addEventListener('click', () => this.remove());
115
+ }
116
+ show(payload) {
117
+ const panel = this.shadowRoot.querySelector('.panel');
118
+ panel.replaceChildren();
119
+ const primary = payload.diagnostics[0] || { code: 'MARKLESS_DEV_RUNTIME_ERROR', message: payload.details };
120
+ const header = append(panel, 'header'); append(header, 'span', primary.code, 'badge'); append(header, 'h1', primary.message);
121
+ diagnosticBody(panel, primary);
122
+ for (const diagnostic of payload.diagnostics.slice(1)) {
123
+ const details = append(panel, 'details'); append(details, 'summary', diagnostic.code + ' — ' + diagnostic.message); diagnosticBody(details, diagnostic);
124
+ }
125
+ const technical = append(panel, 'details'); append(technical, 'summary', 'Technical details'); append(technical, 'pre', [payload.details, payload.stack].filter(Boolean).join('\\n\\n'));
126
+ append(panel, 'p', 'Fixing the error clears this overlay. Press Escape or click the backdrop to dismiss it temporarily.', 'recovery');
127
+ }
128
+ }
129
+ if (!customElements.get(ELEMENT)) customElements.define(ELEMENT, MarklessDevErrorOverlay);
130
+ function removeViteOverlays() { document.querySelectorAll('vite-error-overlay').forEach((node) => node.remove()); }
131
+ function suppressViteOverlay() {
132
+ removeViteOverlays();
133
+ if (!document.head.querySelector('style[' + SUPPRESSION + ']')) { const style = append(document.head, 'style'); style.setAttribute(SUPPRESSION, ''); style.textContent = 'vite-error-overlay{display:none!important}'; }
134
+ if (!observer) { observer = new MutationObserver(removeViteOverlays); observer.observe(document.documentElement, { childList: true, subtree: true }); }
135
+ }
136
+ function reset() {
137
+ removeViteOverlays(); document.querySelector(ELEMENT)?.remove(); document.head.querySelector('style[' + SUPPRESSION + ']')?.remove(); observer?.disconnect(); observer = undefined; currentPayload = undefined;
138
+ }
139
+ function show(payload) {
140
+ currentPayload = payload; suppressViteOverlay(); document.querySelector(ELEMENT)?.remove(); const overlay = document.createElement(ELEMENT); overlay.show(payload); document.body.append(overlay);
141
+ }
142
+ hot.on(ERROR_EVENT, show);
143
+ hot.on(CLEAR_EVENT, ({ id }) => { if (currentPayload?.id === id) reset(); });
144
+ hot.on('vite:beforeFullReload', reset);
145
+ addEventListener('keydown', (event) => { if (event.key === 'Escape') document.querySelector(ELEMENT)?.remove(); });
146
+ if (window.__MARKLESS_DEV_ERROR__) show(window.__MARKLESS_DEV_ERROR__);
147
+ `;
148
+ }
149
+ //#endregion
64
150
  //#region src/vite/hmr.ts
65
151
  const SOURCE_FILE_EXTENSION = /\.tsrx(?:[?#].*)?$/;
152
+ const RESOLVED_DEV_ERROR_CLIENT_ID = `\0${MARKLESS_DEV_ERROR_CLIENT_ID}`;
66
153
  function createViteHmr(options) {
67
154
  let server;
155
+ const invalidSources = /* @__PURE__ */ new Set();
156
+ let invalidSourceRecheck;
157
+ let recheckingInvalidSources = false;
158
+ const preflightByFile = /* @__PURE__ */ new Map();
159
+ function preflight(sourceId, source) {
160
+ const cached = preflightByFile.get(sourceId);
161
+ if (cached?.source === source) return cached.verdict;
162
+ const verdict = preflightTsrxModuleDiagnostics({
163
+ filename: sourceId,
164
+ source
165
+ }).then(() => ({ messagesSent: false }), (error) => ({
166
+ error: normalizeMarklessDevError(error, { id: sourceId }),
167
+ messagesSent: false
168
+ }));
169
+ preflightByFile.set(sourceId, {
170
+ source,
171
+ verdict
172
+ });
173
+ return verdict;
174
+ }
175
+ function startInvalidSourceRecheck() {
176
+ if (invalidSourceRecheck || invalidSources.size === 0) return;
177
+ invalidSourceRecheck = setInterval(() => {
178
+ recheckInvalidSources();
179
+ }, options.invalidSourceRecheckMs ?? 300);
180
+ invalidSourceRecheck.unref?.();
181
+ }
182
+ function stopInvalidSourceRecheckIfIdle() {
183
+ if (!invalidSourceRecheck || invalidSources.size !== 0) return;
184
+ clearInterval(invalidSourceRecheck);
185
+ invalidSourceRecheck = void 0;
186
+ }
187
+ function addInvalidSource(id) {
188
+ if (!isAbsolute(id) || !SOURCE_FILE_EXTENSION.test(id)) return;
189
+ invalidSources.add(id);
190
+ startInvalidSourceRecheck();
191
+ }
192
+ function deleteInvalidSource(id) {
193
+ const deleted = invalidSources.delete(id);
194
+ stopInvalidSourceRecheckIfIdle();
195
+ return deleted;
196
+ }
197
+ async function recheckInvalidSources() {
198
+ if (recheckingInvalidSources) return;
199
+ recheckingInvalidSources = true;
200
+ try {
201
+ let recovered = false;
202
+ for (const id of invalidSources) {
203
+ let source;
204
+ try {
205
+ source = await readFile(id, "utf8");
206
+ } catch (error) {
207
+ if (hasErrorCode(error, "ENOENT") || hasErrorCode(error, "EISDIR")) {
208
+ if (deleteInvalidSource(id)) sendClear(id);
209
+ }
210
+ continue;
211
+ }
212
+ try {
213
+ await preflightTsrxModuleDiagnostics({
214
+ filename: id,
215
+ source
216
+ });
217
+ } catch {
218
+ continue;
219
+ }
220
+ if (!deleteInvalidSource(id)) continue;
221
+ sendClear(id);
222
+ recovered = true;
223
+ }
224
+ if (recovered) server?.environments?.[options.clientEnvironment]?.hot?.send?.({ type: "full-reload" });
225
+ } finally {
226
+ recheckingInvalidSources = false;
227
+ stopInvalidSourceRecheckIfIdle();
228
+ }
229
+ }
230
+ function sendClear(id) {
231
+ server?.environments?.[options.clientEnvironment]?.hot?.send?.({
232
+ type: "custom",
233
+ event: MARKLESS_DEV_ERROR_CLEAR_EVENT,
234
+ data: { id }
235
+ });
236
+ }
237
+ function cleanup() {
238
+ if (invalidSourceRecheck) clearInterval(invalidSourceRecheck);
239
+ invalidSourceRecheck = void 0;
240
+ invalidSources.clear();
241
+ }
68
242
  return {
69
243
  configureServer(nextServer) {
70
244
  server = nextServer;
245
+ nextServer.httpServer?.once("close", cleanup);
246
+ nextServer.watcher?.once?.("close", cleanup);
71
247
  if (options.enabled) installFetchViteClient(nextServer, options);
72
248
  },
73
249
  transformIndexHtml() {},
74
- resolveId(_id) {
75
- return null;
250
+ resolveId(id) {
251
+ return id === "virtual:markless:dev-error-client" ? RESOLVED_DEV_ERROR_CLIENT_ID : null;
76
252
  },
77
- load(_id) {
78
- return null;
253
+ load(id) {
254
+ return id === RESOLVED_DEV_ERROR_CLIENT_ID ? createDevErrorClientAsset(joinURL(options.base, "/@vite/client")) : null;
255
+ },
256
+ reportError(environment, error) {
257
+ const hot = clientHot(server, options, environment);
258
+ if (!hot?.send) return;
259
+ const payload = normalizeMarklessDevError(error);
260
+ addInvalidSource(payload.id);
261
+ hot.send({
262
+ type: "custom",
263
+ event: MARKLESS_DEV_ERROR_EVENT,
264
+ data: payload
265
+ });
79
266
  },
80
- hotUpdate(environment, ctx) {
267
+ async hotUpdate(environment, ctx) {
81
268
  if (!environment) return;
82
269
  const env = marklessEnvironment(environment);
83
270
  if (env === "lib") return;
84
- const hot = env === "server" ? server?.environments?.[options.clientEnvironment]?.hot : environment.hot;
271
+ const hot = clientHot(server, options, environment);
85
272
  if (!hot?.send) return;
86
273
  if (!options.enabled) {
87
274
  hot.send({ type: "full-reload" });
@@ -94,13 +281,42 @@ function createViteHmr(options) {
94
281
  files.add(prefix && ctx.file.startsWith(prefix) ? `/${ctx.file.slice(prefix.length)}` : ctx.file);
95
282
  }
96
283
  if (!files.size) return;
284
+ let sendMessages = true;
285
+ if (ctx.file && SOURCE_FILE_EXTENSION.test(ctx.file) && ctx.read) {
286
+ const sourceId = parsePath(ctx.file).pathname;
287
+ let editedSource;
288
+ try {
289
+ editedSource = await ctx.read();
290
+ } catch {}
291
+ if (editedSource !== void 0) {
292
+ const verdict = await preflight(sourceId, editedSource);
293
+ sendMessages = !verdict.messagesSent;
294
+ verdict.messagesSent = true;
295
+ if (verdict.error) {
296
+ if (sendMessages) {
297
+ addInvalidSource(verdict.error.id);
298
+ hot.send({
299
+ type: "custom",
300
+ event: MARKLESS_DEV_ERROR_EVENT,
301
+ data: verdict.error
302
+ });
303
+ }
304
+ return [];
305
+ }
306
+ }
307
+ if (editedSource !== void 0 && sendMessages && deleteInvalidSource(sourceId)) hot.send({
308
+ type: "custom",
309
+ event: MARKLESS_DEV_ERROR_CLEAR_EVENT,
310
+ data: { id: sourceId }
311
+ });
312
+ }
97
313
  const invalidationEnvironments = moduleGraphEnvironments(environment, env === "server" ? server?.environments?.[options.clientEnvironment] : void 0);
98
314
  for (const file of files) for (const candidate of hmrCandidates(file, ctx.file)) for (const id of options.invalidateGeneratedModules?.(candidate, env) ?? []) for (const targetEnvironment of invalidationEnvironments) {
99
315
  const module = targetEnvironment.moduleGraph?.getModuleById?.(id);
100
316
  if (!module) continue;
101
317
  targetEnvironment.moduleGraph?.invalidateModule?.(module, /* @__PURE__ */ new Set(), ctx.timestamp, true);
102
318
  }
103
- hot.send({
319
+ if (sendMessages) hot.send({
104
320
  type: "full-reload",
105
321
  path: firstChangedFile(files),
106
322
  triggeredBy: ctx.file
@@ -109,6 +325,9 @@ function createViteHmr(options) {
109
325
  }
110
326
  };
111
327
  }
328
+ function hasErrorCode(error, code) {
329
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
330
+ }
112
331
  function installFetchViteClient(server, options) {
113
332
  for (const environment of Object.values(server.environments)) {
114
333
  const fetchEnv = fetchableDevEnvironment(environment);
@@ -118,7 +337,7 @@ function installFetchViteClient(server, options) {
118
337
  const response = await dispatchFetch(request);
119
338
  if (!response.headers.get("content-type")?.includes("text/html")) return response;
120
339
  const html = await response.text();
121
- const nextHtml = injectViteClient(html, options.base);
340
+ const nextHtml = injectDevClients(html, options.base);
122
341
  const headers = new Headers(response.headers);
123
342
  if (nextHtml !== html) headers.delete("content-length");
124
343
  return new Response(nextHtml, {
@@ -129,12 +348,16 @@ function installFetchViteClient(server, options) {
129
348
  };
130
349
  }
131
350
  }
132
- function injectViteClient(html, base) {
133
- if (!html || html.includes("/@vite/client")) return html;
134
- const tag = `<script type="module" src="${joinURL(base, "/@vite/client")}"><\/script>`;
135
- if (html.includes("</head>")) return html.replace("</head>", `${tag}</head>`);
136
- if (html.includes("<head>")) return html.replace("<head>", `<head>${tag}`);
137
- return `${tag}${html}`;
351
+ function injectDevClients(html, base) {
352
+ if (!html) return html;
353
+ const tags = [...html.includes("/@vite/client") ? [] : [`<script type="module" src="${joinURL(base, "/@vite/client")}"><\/script>`], ...html.includes("virtual:markless:dev-error-client") ? [] : [`<script type="module" src="${joinURL(base, `/@id/__x00__${MARKLESS_DEV_ERROR_CLIENT_ID}`)}"><\/script>`]].join("");
354
+ if (!tags) return html;
355
+ if (html.includes("</head>")) return html.replace("</head>", `${tags}</head>`);
356
+ if (html.includes("<head>")) return html.replace("<head>", `<head>${tags}`);
357
+ return `${tags}${html}`;
358
+ }
359
+ function clientHot(server, options, environment) {
360
+ return marklessEnvironment(environment) === "server" ? server?.environments?.[options.clientEnvironment]?.hot : environment?.hot;
138
361
  }
139
362
  function changedFiles(modules) {
140
363
  const files = /* @__PURE__ */ new Set();
@@ -197,6 +420,21 @@ function markless(options = {}) {
197
420
  },
198
421
  config(config, env) {
199
422
  command = env.command;
423
+ const devEnabled = env.command === "serve";
424
+ rolldownOptions.executionLog = options.executionLog ?? (devEnabled ? "auto" : "never");
425
+ const debugEnabled = devEnabled || options.debug === true;
426
+ rolldownOptions.inlineResumerDebug = debugEnabled;
427
+ const debugDefine = JSON.stringify(debugEnabled);
428
+ const devDefine = JSON.stringify(devEnabled);
429
+ const consumerDebugDefine = config.define?.__MARKLESS_DEBUG_ENABLED__;
430
+ const consumerDevDefine = config.define?.__MARKLESS_DEV_ENABLED__;
431
+ if (consumerDebugDefine !== void 0 && consumerDebugDefine !== debugDefine && consumerDebugDefine !== debugEnabled) throw new Error("MARKLESS_DEBUG_DEFINE_CONFLICT: __MARKLESS_DEBUG_ENABLED__ is controlled by markless(). Remove the consumer definition or set markless({ debug: true }).");
432
+ if (consumerDevDefine !== void 0 && consumerDevDefine !== devDefine && consumerDevDefine !== devEnabled) throw new Error("MARKLESS_DEV_DEFINE_CONFLICT: __MARKLESS_DEV_ENABLED__ is controlled by markless(). Remove the consumer definition.");
433
+ config.define = {
434
+ ...config.define,
435
+ __MARKLESS_DEBUG_ENABLED__: debugDefine,
436
+ __MARKLESS_DEV_ENABLED__: devDefine
437
+ };
200
438
  configDefaults(config, options, rolldownOptions);
201
439
  },
202
440
  configResolved(resolvedConfig) {
@@ -232,6 +470,7 @@ function markless(options = {}) {
232
470
  }
233
471
  },
234
472
  configureServer(server) {
473
+ server.config.logger?.info("markless diagnostics available - window.__MARKLESS_DEBUG__ records containers, lifecycles, and event routing; markless debugging playbook: run pnpm doctor, or read agent/markless.md in the installed @markless/core package.");
235
474
  rolldownOptions.devServer = { transformRequest: (url, environment) => transformMarklessRequest(server, url, environment, options) };
236
475
  hmr.configureServer(server);
237
476
  },
@@ -260,7 +499,12 @@ function markless(options = {}) {
260
499
  },
261
500
  transform: { async handler(code, id, transformOptions) {
262
501
  if (rolldownOptions.dev === true && TSRX_INPUT_FILE.test(id)) transformedTsrxSources.set(parsePath(id).pathname, code);
263
- return runHook(basePlugin.transform, this, code, id, transformOptions);
502
+ try {
503
+ return await runHook(basePlugin.transform, this, code, id, transformOptions);
504
+ } catch (error) {
505
+ if (rolldownOptions.dev === true && TSRX_INPUT_FILE.test(id)) hmr.reportError(this.environment, error);
506
+ throw error;
507
+ }
264
508
  } },
265
509
  async hotUpdate(ctx) {
266
510
  if (await matchesTransformedTsrxSource(ctx, transformedTsrxSources)) return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markless/bundler",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Markless build plugins for Rolldown and Vite.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,12 +8,16 @@
8
8
  "url": "git+https://github.com/markless-dev/markless.git",
9
9
  "directory": "packages/bundler"
10
10
  },
11
- "publishConfig": {
12
- "access": "public"
13
- },
11
+ "files": [
12
+ "dist"
13
+ ],
14
14
  "type": "module",
15
15
  "sideEffects": false,
16
16
  "exports": {
17
+ "./dev-error": {
18
+ "types": "./dist/dev-error.d.ts",
19
+ "default": "./dist/dev-error.js"
20
+ },
17
21
  "./preload": {
18
22
  "types": "./dist/preload.d.ts",
19
23
  "default": "./dist/preload.js"
@@ -27,12 +31,20 @@
27
31
  "default": "./dist/vite.js"
28
32
  }
29
33
  },
34
+ "publishConfig": {
35
+ "access": "public",
36
+ "provenance": true
37
+ },
30
38
  "dependencies": {
31
39
  "@thi.ng/dgraph": "^2.1.205",
32
40
  "pathe": "^2.0.3",
33
41
  "ufo": "^1.6.4",
34
- "@markless/compiler": "0.1.1",
35
- "@markless/web": "0.1.1"
42
+ "@markless/compiler": "0.2.1",
43
+ "@markless/serializer": "0.2.1",
44
+ "@markless/web": "0.2.1"
45
+ },
46
+ "devDependencies": {
47
+ "@markless/analyzer": "0.2.1"
36
48
  },
37
49
  "peerDependencies": {
38
50
  "rolldown": "1.0.3",
@@ -46,9 +58,6 @@
46
58
  "optional": true
47
59
  }
48
60
  },
49
- "files": [
50
- "dist"
51
- ],
52
61
  "scripts": {
53
62
  "test:boxes": "witness run"
54
63
  }