@jxsuite/compiler 0.28.5 → 0.30.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/cli.js +114 -109
- package/dist/compiler.js +93 -88
- package/package.json +8 -7
- package/src/cli.ts +38 -29
- package/src/compile-cli.ts +15 -7
- package/src/compiler.ts +6 -14
- package/src/shared.ts +27 -31
- package/src/site/content-loader.ts +7 -5
- package/src/site/context-injection.ts +1 -1
- package/src/site/image-cache.ts +2 -2
- package/src/site/image-optimizer.ts +11 -4
- package/src/site/image-transform.ts +5 -5
- package/src/site/pages-discovery.ts +4 -5
- package/src/site/site-build.ts +95 -42
- package/src/targets/compile-class.ts +7 -11
- package/src/targets/compile-client.ts +102 -42
- package/src/targets/compile-element.ts +82 -70
- package/src/targets/compile-static.ts +8 -0
|
@@ -268,16 +268,17 @@ export function emitElementModule(doc: JxDocument, className: string, elementImp
|
|
|
268
268
|
lines.push(`import { ${names.join(", ")} } from '${srcPath}';`);
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
lines.push(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
271
|
+
lines.push(
|
|
272
|
+
`import { reactive, computed, effect } from '@vue/reactivity';`,
|
|
273
|
+
`import { render, html } from 'lit-html';`,
|
|
274
|
+
"",
|
|
275
|
+
`class ${className} extends HTMLElement {`,
|
|
276
|
+
" #dispose = null;",
|
|
277
|
+
"",
|
|
278
|
+
// Constructor: build reactive state
|
|
279
|
+
" constructor() {",
|
|
280
|
+
" super();",
|
|
281
|
+
);
|
|
281
282
|
|
|
282
283
|
const stateEntries: [string, string][] = [];
|
|
283
284
|
const computedEntries: [string, JxExpressionDef | JxFunctionDef][] = [];
|
|
@@ -330,9 +331,11 @@ export function emitElementModule(doc: JxDocument, className: string, elementImp
|
|
|
330
331
|
// $src function — wrap imported function so it receives state
|
|
331
332
|
lines.push(` this.state.${key} = (${paramList}) => ${key}(${paramList});`);
|
|
332
333
|
} else {
|
|
333
|
-
lines.push(
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
lines.push(
|
|
335
|
+
` this.state.${key} = (${paramList}) => {`,
|
|
336
|
+
` ${def.body ?? ""}`,
|
|
337
|
+
" };",
|
|
338
|
+
);
|
|
336
339
|
}
|
|
337
340
|
}
|
|
338
341
|
}
|
|
@@ -351,13 +354,11 @@ export function emitElementModule(doc: JxDocument, className: string, elementImp
|
|
|
351
354
|
} else {
|
|
352
355
|
lines.push(` this.state.${key} = computed(() => {`);
|
|
353
356
|
const body = (def.body ?? "").replaceAll("state.", "this.state.");
|
|
354
|
-
lines.push(` ${body}
|
|
355
|
-
lines.push(" });");
|
|
357
|
+
lines.push(` ${body}`, " });");
|
|
356
358
|
}
|
|
357
359
|
}
|
|
358
360
|
|
|
359
|
-
lines.push(" }"); // End constructor
|
|
360
|
-
lines.push("");
|
|
361
|
+
lines.push(" }", ""); // End constructor
|
|
361
362
|
|
|
362
363
|
// Collect CSS rules from children tree (assigns .jx-N classes to defs)
|
|
363
364
|
const cssRules: string[] = [];
|
|
@@ -368,35 +369,36 @@ export function emitElementModule(doc: JxDocument, className: string, elementImp
|
|
|
368
369
|
}
|
|
369
370
|
}
|
|
370
371
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
372
|
+
lines.push(
|
|
373
|
+
// Template method
|
|
374
|
+
" template() {",
|
|
375
|
+
" const s = this.state;",
|
|
376
|
+
" return html`",
|
|
377
|
+
emitLitChildren(doc.children, doc.style, " "),
|
|
378
|
+
" `;",
|
|
379
|
+
" }",
|
|
380
|
+
"",
|
|
381
|
+
// ConnectedCallback
|
|
382
|
+
" connectedCallback() {",
|
|
383
|
+
// Read $props from data-jx-props attribute (set by compiler for pre-rendered instances)
|
|
384
|
+
" const _pa = this.getAttribute('data-jx-props');",
|
|
385
|
+
" if (_pa) {",
|
|
386
|
+
" try {",
|
|
387
|
+
" const _p = JSON.parse(_pa);",
|
|
388
|
+
" for (const [k, v] of Object.entries(_p)) {",
|
|
389
|
+
" if (k in this.state) this.state[k] = v;",
|
|
390
|
+
" }",
|
|
391
|
+
" } catch {}",
|
|
392
|
+
" this.removeAttribute('data-jx-props');",
|
|
393
|
+
" }",
|
|
394
|
+
// Merge JS properties set before connection (by parent runtime).
|
|
395
|
+
// Only check own properties to avoid inherited DOM properties like `title`.
|
|
396
|
+
" for (const key of Object.keys(this.state)) {",
|
|
397
|
+
" if (this.hasOwnProperty(key) && this[key] !== undefined) {",
|
|
398
|
+
" this.state[key] = this[key];",
|
|
399
|
+
" }",
|
|
400
|
+
" }",
|
|
401
|
+
);
|
|
400
402
|
if (doc.style && typeof doc.style === "object") {
|
|
401
403
|
const dynamicStyles: [string, string][] = [];
|
|
402
404
|
for (const [prop, value] of Object.entries(doc.style)) {
|
|
@@ -436,31 +438,35 @@ export function emitElementModule(doc: JxDocument, className: string, elementImp
|
|
|
436
438
|
" const _slotted = Array.from(this.childNodes).filter(n => n.nodeType === 1 || (n.nodeType === 3 && n.textContent.trim()));",
|
|
437
439
|
);
|
|
438
440
|
}
|
|
439
|
-
lines.push(
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
441
|
+
lines.push(
|
|
442
|
+
" if (this.hasAttribute('data-jx-prerendered')) {",
|
|
443
|
+
" this.removeAttribute('data-jx-prerendered');",
|
|
444
|
+
" }",
|
|
445
|
+
" this.innerHTML = '';",
|
|
446
|
+
" this.#dispose = effect(() => render(this.template(), this));",
|
|
447
|
+
);
|
|
444
448
|
if (hasSlot) {
|
|
445
449
|
// Replace <slot> placeholder with saved slotted content
|
|
446
|
-
lines.push(
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
450
|
+
lines.push(
|
|
451
|
+
" const _slot = this.querySelector('slot');",
|
|
452
|
+
" if (_slot && _slotted.length > 0) {",
|
|
453
|
+
" for (const n of _slotted) _slot.before(n);",
|
|
454
|
+
" _slot.remove();",
|
|
455
|
+
" }",
|
|
456
|
+
);
|
|
451
457
|
}
|
|
452
|
-
lines.push(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
458
|
+
lines.push(
|
|
459
|
+
" }",
|
|
460
|
+
"",
|
|
461
|
+
// DisconnectedCallback
|
|
462
|
+
" disconnectedCallback() {",
|
|
463
|
+
" if (this.#dispose) { this.#dispose(); this.#dispose = null; }",
|
|
464
|
+
" }",
|
|
465
|
+
"}",
|
|
466
|
+
"",
|
|
467
|
+
`customElements.define('${doc.tagName}', ${className});`,
|
|
468
|
+
"",
|
|
469
|
+
);
|
|
464
470
|
|
|
465
471
|
return lines.join("\n");
|
|
466
472
|
}
|
|
@@ -475,13 +481,14 @@ export function emitElementModule(doc: JxDocument, className: string, elementImp
|
|
|
475
481
|
*/
|
|
476
482
|
function emitLitChildren(
|
|
477
483
|
children: JxMutableNode["children"],
|
|
478
|
-
|
|
484
|
+
_parentStyle: JxStyle | null | undefined,
|
|
479
485
|
indent: string,
|
|
480
486
|
) {
|
|
481
487
|
if (!children) {
|
|
482
488
|
return "";
|
|
483
489
|
}
|
|
484
490
|
|
|
491
|
+
// Legacy whole-children repeater: the array IS the children slot.
|
|
485
492
|
if (isMappedArray(children)) {
|
|
486
493
|
return emitMappedArray(children, indent);
|
|
487
494
|
}
|
|
@@ -490,7 +497,12 @@ function emitLitChildren(
|
|
|
490
497
|
return "";
|
|
491
498
|
}
|
|
492
499
|
|
|
493
|
-
|
|
500
|
+
// Mixed children: elements/text plus array pseudo-elements expanded inline among siblings.
|
|
501
|
+
return children
|
|
502
|
+
.map((child: JxMutableNode | string) =>
|
|
503
|
+
isMappedArray(child) ? emitMappedArray(child, indent) : emitLitNode(child, indent),
|
|
504
|
+
)
|
|
505
|
+
.join("\n");
|
|
494
506
|
}
|
|
495
507
|
|
|
496
508
|
/**
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
escapeHtml,
|
|
13
13
|
isNodeDynamic,
|
|
14
14
|
resolveStaticValue,
|
|
15
|
+
SELF_CLOSING,
|
|
15
16
|
} from "../shared.ts";
|
|
16
17
|
import { emitElementModule } from "./compile-element.ts";
|
|
17
18
|
import type { JxDocument, JxMutableNode, JxStyle } from "@jxsuite/schema/types";
|
|
@@ -143,6 +144,13 @@ function compileNode(
|
|
|
143
144
|
|
|
144
145
|
const tag = def.tagName ?? "div";
|
|
145
146
|
const attrs = buildAttrs(def, nextContext.scope);
|
|
147
|
+
|
|
148
|
+
// Void elements (br, hr, img, …) have no closing tag.
|
|
149
|
+
// Emitting `<br></br>` makes HTML parsers read `</br>` as a second `<br>`.
|
|
150
|
+
if (SELF_CLOSING.has(tag)) {
|
|
151
|
+
return `<${tag}${attrs}>`;
|
|
152
|
+
}
|
|
153
|
+
|
|
146
154
|
const inner = buildInnerWithIslands(def, raw, nextContext, islands);
|
|
147
155
|
|
|
148
156
|
return `<${tag}${attrs}>${inner}</${tag}>`;
|