@zeus-js/output-wc 0.1.0-beta.1 → 0.1.0-beta.3

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.
@@ -1,11 +1,11 @@
1
1
  /**
2
- * output-wc v0.1.0-beta.1
2
+ * output-wc v0.1.0-beta.3
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
6
6
  import path from "node:path";
7
7
  import { resolvePluginDts } from "@zeus-js/bundler-plugin";
8
- import { generateWCDtsFiles } from "@zeus-js/component-dts";
8
+ import { generateLoaderDts, generateWCDtsFiles, generateWCJsxDts } from "@zeus-js/component-dts";
9
9
  //#region packages/web-c/output-wc/src/generateCustomElementsJson.ts
10
10
  function generateCustomElementsJson(options) {
11
11
  const { manifest, getModulePath } = options;
@@ -149,6 +149,136 @@ function getVirtualIndexId() {
149
149
  return "zeus:wc:index";
150
150
  }
151
151
  //#endregion
152
+ //#region packages/web-c/output-wc/src/generateLazyEntry.ts
153
+ function generateLazyEntry(options) {
154
+ const { component, outPath, sourceImport } = options;
155
+ const source = sourceImport !== null && sourceImport !== void 0 ? sourceImport : toRelativeImport(component.source, outPath);
156
+ return [
157
+ `import { mountElementDefinition } from "@zeus-js/runtime-dom";`,
158
+ `import { ${component.exportName} } from ${JSON.stringify(source)};`,
159
+ "",
160
+ `export function createComponent(hostRef) {`,
161
+ ` let mounted;`,
162
+ ` const mountState = {};`,
163
+ "",
164
+ ` return {`,
165
+ ` connected() {`,
166
+ ` if (mounted) return;`,
167
+ "",
168
+ ` mounted = mountElementDefinition(`,
169
+ ` ${component.exportName},`,
170
+ ` hostRef.host,`,
171
+ ` hostRef.values,`,
172
+ ` mountState,`,
173
+ ` );`,
174
+ ` },`,
175
+ "",
176
+ ` disconnected() {`,
177
+ ` mounted?.dispose();`,
178
+ ` mounted = undefined;`,
179
+ ` },`,
180
+ "",
181
+ ` propertyChanged(name, oldValue, newValue) {`,
182
+ ` mounted?.propertyChanged(name, oldValue, newValue);`,
183
+ ` },`,
184
+ ` };`,
185
+ `}`,
186
+ "",
187
+ `export default { createComponent };`,
188
+ ""
189
+ ].join("\n");
190
+ }
191
+ function toRelativeImport(source, outPath) {
192
+ const sourceParts = normalizePath(source).split("/");
193
+ const outParts = normalizePath(outPath).split("/");
194
+ let common = 0;
195
+ for (let i = 0; i < Math.min(sourceParts.length, outParts.length); i++) if (sourceParts[i] === outParts[i]) common++;
196
+ else break;
197
+ return [...outParts.slice(common).map(() => ".."), ...sourceParts.slice(common)].join("/");
198
+ }
199
+ //#endregion
200
+ //#region packages/web-c/output-wc/src/generateLazyManifest.ts
201
+ function generateLazyManifest(options) {
202
+ const { components, getEntryFileName } = options;
203
+ return `export const components = [
204
+ ${components.map((component) => {
205
+ var _component$runtimePro, _component$meta$shado, _component$meta;
206
+ const entryFile = getEntryFileName(component.tag).replace(/\\/g, "/");
207
+ const props = generatePropsArray((_component$runtimePro = component.runtimeProps) !== null && _component$runtimePro !== void 0 ? _component$runtimePro : component.props);
208
+ const importPath = entryFile.startsWith(".") ? JSON.stringify(entryFile) : JSON.stringify(`./${entryFile}`);
209
+ return ` {
210
+ tagName: ${JSON.stringify(component.tag)},
211
+ shadow: ${(_component$meta$shado = (_component$meta = component.meta) === null || _component$meta === void 0 ? void 0 : _component$meta.shadow) !== null && _component$meta$shado !== void 0 ? _component$meta$shado : false},
212
+ load: () => import(${importPath}),
213
+ props: ${props},
214
+ }`;
215
+ }).join(",\n")}
216
+ ];
217
+ `;
218
+ }
219
+ function generatePropsArray(props) {
220
+ const entries = Object.entries(props);
221
+ if (entries.length === 0) return "[]";
222
+ return `[\n${entries.map(([name, prop]) => {
223
+ const parts = [`name: ${JSON.stringify(name)}`];
224
+ if (!isAttributeBackedType(prop.type) || prop.attr === false) parts.push("attrName: false");
225
+ else {
226
+ var _prop$attr;
227
+ const attrName = (_prop$attr = prop.attr) !== null && _prop$attr !== void 0 ? _prop$attr : toKebabCase(name);
228
+ if (attrName !== toKebabCase(name)) parts.push(`attrName: ${JSON.stringify(attrName)}`);
229
+ }
230
+ parts.push(`type: ${JSON.stringify(prop.type)}`);
231
+ if (prop.reflect && isAttributeBackedType(prop.type)) parts.push("reflect: true");
232
+ return ` { ${parts.join(", ")} }`;
233
+ }).join(",\n")}\n ]`;
234
+ }
235
+ function isAttributeBackedType(type) {
236
+ return type === "string" || type === "number" || type === "boolean";
237
+ }
238
+ function toKebabCase(value) {
239
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
240
+ }
241
+ //#endregion
242
+ //#region packages/web-c/output-wc/src/generateLoader.ts
243
+ function generateLoader() {
244
+ return `import { bootstrapLazy } from "@zeus-js/web-c-runtime";
245
+ import { components } from "./components.manifest.js";
246
+
247
+ let defined = false;
248
+
249
+ export function defineCustomElements() {
250
+ if (defined) {
251
+ return;
252
+ }
253
+
254
+ if (typeof customElements === "undefined") {
255
+ return;
256
+ }
257
+
258
+ bootstrapLazy(components);
259
+
260
+ defined = true;
261
+ }
262
+
263
+ export const defineLazyElements = defineCustomElements;
264
+ `;
265
+ }
266
+ function generateAutoEntry() {
267
+ return `import { defineCustomElements } from "./loader.js";
268
+
269
+ defineCustomElements();
270
+
271
+ export {};
272
+ `;
273
+ }
274
+ function generateLazyIndex() {
275
+ return `export {
276
+ defineCustomElements,
277
+ defineLazyElements,
278
+ } from "./loader.js";
279
+ `;
280
+ }
281
+ //#endregion
152
282
  //#region packages/web-c/output-wc/src/generateManifest.ts
153
283
  function generateZeusComponentsManifest(manifest) {
154
284
  return `${JSON.stringify(manifest, null, 2)}\n`;
@@ -156,17 +286,21 @@ function generateZeusComponentsManifest(manifest) {
156
286
  //#endregion
157
287
  //#region packages/web-c/output-wc/src/index.ts
158
288
  function wc(options = {}) {
159
- var _options$outDir, _options$stripPrefix, _options$manifestFile, _options$customElemen, _options$dts, _options$jsxDts, _options$index, _options$warnOnFileNa;
289
+ var _options$register, _options$outDir, _options$stripPrefix, _options$manifestFile, _options$customElemen, _options$dts, _options$jsxDts, _options$index, _options$warnOnFileNa, _options$auto, _options$entryFileNam;
290
+ const registerMode = (_options$register = options.register) !== null && _options$register !== void 0 ? _options$register : "lazy";
160
291
  const normalized = {
161
292
  outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "wc",
162
293
  stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
163
294
  fileName: options.fileName,
164
- manifestFile: (_options$manifestFile = options.manifestFile) !== null && _options$manifestFile !== void 0 ? _options$manifestFile : "zeus.components.json",
165
- customElementsFile: (_options$customElemen = options.customElementsFile) !== null && _options$customElemen !== void 0 ? _options$customElemen : "custom-elements.json",
166
- dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : "auto",
167
- jsxDts: (_options$jsxDts = options.jsxDts) !== null && _options$jsxDts !== void 0 ? _options$jsxDts : "auto",
295
+ manifestFile: registerMode === "lazy" ? false : (_options$manifestFile = options.manifestFile) !== null && _options$manifestFile !== void 0 ? _options$manifestFile : "zeus.components.json",
296
+ customElementsFile: registerMode === "lazy" ? false : (_options$customElemen = options.customElementsFile) !== null && _options$customElemen !== void 0 ? _options$customElemen : "custom-elements.json",
297
+ dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
298
+ jsxDts: (_options$jsxDts = options.jsxDts) !== null && _options$jsxDts !== void 0 ? _options$jsxDts : true,
168
299
  index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true,
169
- warnOnFileNameCollision: (_options$warnOnFileNa = options.warnOnFileNameCollision) !== null && _options$warnOnFileNa !== void 0 ? _options$warnOnFileNa : true
300
+ warnOnFileNameCollision: (_options$warnOnFileNa = options.warnOnFileNameCollision) !== null && _options$warnOnFileNa !== void 0 ? _options$warnOnFileNa : true,
301
+ register: registerMode,
302
+ auto: (_options$auto = options.auto) !== null && _options$auto !== void 0 ? _options$auto : true,
303
+ entryFileName: (_options$entryFileNam = options.entryFileName) !== null && _options$entryFileNam !== void 0 ? _options$entryFileNam : ((tag) => `${tag}.entry`)
170
304
  };
171
305
  let _outDir = normalized.outDir;
172
306
  return {
@@ -181,7 +315,32 @@ function wc(options = {}) {
181
315
  },
182
316
  buildStart(ctx) {
183
317
  if (!ctx.manifest) return;
184
- checkFileNameCollisions(ctx.manifest.components, normalized, { warn: ctx.warn });
318
+ if (normalized.register === "lazy") for (const component of ctx.manifest.components) {
319
+ var _component$runtimePro, _component$runtimePro2;
320
+ const diagnostics = (_component$runtimePro = component.runtimePropsDiagnostics) !== null && _component$runtimePro !== void 0 ? _component$runtimePro : [];
321
+ if (diagnostics.length > 0) ctx.error([`[zeus-output-wc] <${component.tag}> cannot be emitted with register:"lazy" because its runtime props are not statically analyzable.`, ...diagnostics.map((message) => `- ${message}`)].join("\n"));
322
+ const runtimeProps = (_component$runtimePro2 = component.runtimeProps) !== null && _component$runtimePro2 !== void 0 ? _component$runtimePro2 : {};
323
+ for (const [name, prop] of Object.entries(runtimeProps)) {
324
+ if (isAttributeBackedRuntimeProp(prop.type)) continue;
325
+ if (prop.attr !== void 0 && prop.attr !== false) ctx.error([
326
+ `[zeus-output-wc] <${component.tag}> prop "${name}" cannot use attr:${JSON.stringify(prop.attr)} with register:"lazy".`,
327
+ "Lazy Web-C only supports attributes for string, number and boolean props.",
328
+ "Use attr:false and pass object/array/function values as properties instead."
329
+ ].join("\n"));
330
+ if (prop.reflect) ctx.error([
331
+ `[zeus-output-wc] <${component.tag}> prop "${name}" cannot use reflect:true with register:"lazy".`,
332
+ "Lazy Web-C only reflects string, number and boolean props.",
333
+ "Use a string/number/boolean prop or remove reflect:true."
334
+ ].join("\n"));
335
+ }
336
+ }
337
+ checkFileNameCollisions(ctx.manifest.components, {
338
+ getFileName: (tag) => {
339
+ if (normalized.register === "lazy") return getLazyEntryFileName(normalized.entryFileName, tag);
340
+ return normalizeFileName(tag, normalized.stripPrefix, normalized.fileName);
341
+ },
342
+ warnOnFileNameCollision: normalized.warnOnFileNameCollision
343
+ }, { warn: ctx.warn });
185
344
  },
186
345
  virtualModules(ctx) {
187
346
  if (!ctx.manifest) return [];
@@ -195,7 +354,55 @@ function wc(options = {}) {
195
354
  if (hasOutputs) return ctx.outputs.join("wc", fileName);
196
355
  return path.posix.join(_outDir, fileName);
197
356
  };
198
- for (const component of ctx.manifest.components) {
357
+ const isLazy = normalized.register === "lazy";
358
+ if (isLazy) {
359
+ modules.push({
360
+ id: "zeus:wc:components.manifest",
361
+ fileName: joinPath("components.manifest.js"),
362
+ code: generateLazyManifest({
363
+ components: ctx.manifest.components,
364
+ getEntryFileName: (tag) => getLazyEntryFileName(normalized.entryFileName, tag)
365
+ })
366
+ });
367
+ modules.push({
368
+ id: "zeus:wc:loader",
369
+ fileName: joinPath("loader.js"),
370
+ code: generateLoader()
371
+ });
372
+ if (normalized.auto) modules.push({
373
+ id: "zeus:wc:auto",
374
+ fileName: joinPath("auto.js"),
375
+ code: generateAutoEntry()
376
+ });
377
+ }
378
+ for (const component of ctx.manifest.components) if (isLazy) {
379
+ /**
380
+ * Compatibility module consumed by Vue / React wrappers.
381
+ *
382
+ * It only registers lazy Proxy Elements.
383
+ * It does not import the real component implementation.
384
+ */
385
+ modules.push({
386
+ id: getVirtualComponentId(component),
387
+ code: `
388
+ import { defineCustomElements } from "zeus:wc:loader";
389
+
390
+ defineCustomElements();
391
+
392
+ export {};
393
+ `.trimStart()
394
+ });
395
+ const fileName = joinPath(getLazyEntryFileName(normalized.entryFileName, component.tag));
396
+ modules.push({
397
+ id: `zeus:wc:entry:${component.tag}`,
398
+ fileName,
399
+ code: generateLazyEntry({
400
+ component,
401
+ outPath: fileName,
402
+ sourceImport: toAbsoluteImportPath(ctx.root, component.source)
403
+ })
404
+ });
405
+ } else {
199
406
  const fileName = joinPath(getFileName(component.tag));
200
407
  modules.push({
201
408
  id: getVirtualComponentId(component),
@@ -206,7 +413,7 @@ function wc(options = {}) {
206
413
  })
207
414
  });
208
415
  }
209
- if (normalized.index) modules.push({
416
+ if (normalized.index && !isLazy) modules.push({
210
417
  id: getVirtualIndexId(),
211
418
  fileName: joinPath("index.js"),
212
419
  code: generateWCIndex({
@@ -214,16 +421,18 @@ function wc(options = {}) {
214
421
  getFileName
215
422
  })
216
423
  });
424
+ if (isLazy && normalized.index) modules.push({
425
+ id: getVirtualIndexId(),
426
+ fileName: joinPath("index.js"),
427
+ code: generateLazyIndex()
428
+ });
217
429
  return modules;
218
430
  },
219
431
  generateBundle(ctx) {
220
432
  if (!ctx.manifest) return [];
221
433
  const files = [];
222
- if (normalized.manifestFile) files.push({
223
- type: "asset",
224
- fileName: normalized.manifestFile,
225
- source: generateZeusComponentsManifest(ctx.manifest)
226
- });
434
+ const dts = resolvePluginDts(normalized.dts, ctx);
435
+ const jsxDts = resolvePluginDts(normalized.jsxDts, ctx);
227
436
  const hasOutputs = ctx.outputs.has("wc");
228
437
  const getFileName = (tag) => {
229
438
  if (hasOutputs) return ctx.outputs.getFileName("wc", tag);
@@ -233,7 +442,32 @@ function wc(options = {}) {
233
442
  if (hasOutputs) return ctx.outputs.join("wc", fileName);
234
443
  return path.posix.join(_outDir, fileName);
235
444
  };
236
- if (normalized.customElementsFile) files.push({
445
+ const isLazy = normalized.register === "lazy";
446
+ if (isLazy) {
447
+ if (dts) {
448
+ const loaderDts = generateLoaderDts(ctx.manifest);
449
+ files.push({
450
+ type: "asset",
451
+ fileName: joinPath("loader.d.ts"),
452
+ source: loaderDts
453
+ });
454
+ if (normalized.index) files.push({
455
+ type: "asset",
456
+ fileName: joinPath("index.d.ts"),
457
+ source: loaderDts
458
+ });
459
+ }
460
+ if (jsxDts) files.push({
461
+ type: "asset",
462
+ fileName: joinPath("types/jsx.d.ts"),
463
+ source: generateWCJsxDts(ctx.manifest)
464
+ });
465
+ } else if (normalized.manifestFile) files.push({
466
+ type: "asset",
467
+ fileName: normalized.manifestFile,
468
+ source: generateZeusComponentsManifest(ctx.manifest)
469
+ });
470
+ if (!isLazy && normalized.customElementsFile) files.push({
237
471
  type: "asset",
238
472
  fileName: normalized.customElementsFile,
239
473
  source: generateCustomElementsJson({
@@ -241,9 +475,7 @@ function wc(options = {}) {
241
475
  getModulePath: (component) => joinPath(getFileName(component.tag))
242
476
  })
243
477
  });
244
- const dts = resolvePluginDts(normalized.dts, ctx);
245
- const jsxDts = resolvePluginDts(normalized.jsxDts, ctx);
246
- if (dts || jsxDts) {
478
+ if (!isLazy && (dts || jsxDts)) {
247
479
  const dtsFiles = generateWCDtsFiles(ctx.manifest, {
248
480
  outDir: _outDir,
249
481
  stripPrefix: normalized.stripPrefix,
@@ -272,12 +504,22 @@ function normalizeFileName(tag, stripPrefix, fileName) {
272
504
  if (!name.endsWith(".js")) name = `${name}.js`;
273
505
  return name;
274
506
  }
507
+ function normalizeLazyEntryFileName(fileName) {
508
+ const normalized = fileName.replace(/\\/g, "/");
509
+ return normalized.endsWith(".js") ? normalized : `${normalized}.js`;
510
+ }
511
+ function getLazyEntryFileName(entryFileName, tag) {
512
+ return normalizeLazyEntryFileName(entryFileName(tag));
513
+ }
514
+ function isAttributeBackedRuntimeProp(type) {
515
+ return type === "string" || type === "number" || type === "boolean";
516
+ }
275
517
  function checkFileNameCollisions(components, options, reporter) {
276
518
  if (options.warnOnFileNameCollision === false) return;
277
519
  const map = /* @__PURE__ */ new Map();
278
520
  for (const component of components) {
279
521
  var _map$get;
280
- const fileName = normalizeFileName(component.tag, options.stripPrefix, options.fileName);
522
+ const fileName = options.getFileName(component.tag);
281
523
  const list = (_map$get = map.get(fileName)) !== null && _map$get !== void 0 ? _map$get : [];
282
524
  list.push(component);
283
525
  map.set(fileName, list);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeus-js/output-wc",
3
- "version": "0.1.0-beta.1",
3
+ "version": "0.1.0-beta.3",
4
4
  "description": "Zeus Web Component output plugin",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -13,16 +13,25 @@
13
13
  "exports": {
14
14
  ".": {
15
15
  "types": "./dist/output-wc.d.ts",
16
+ "module": "./dist/output-wc.esm-bundler.js",
17
+ "import": "./dist/output-wc.esm-bundler.js",
18
+ "require": "./index.js",
16
19
  "node": {
17
20
  "production": "./dist/output-wc.cjs.prod.js",
18
21
  "development": "./dist/output-wc.cjs.js",
19
22
  "default": "./index.js"
20
- },
21
- "module": "./dist/output-wc.esm-bundler.js",
22
- "import": "./dist/output-wc.esm-bundler.js",
23
- "require": "./index.js"
23
+ }
24
24
  },
25
- "./*": "./*"
25
+ "./capabilities": {
26
+ "types": "./dist/capabilities.d.ts",
27
+ "import": "./dist/capabilities.js",
28
+ "require": "./dist/capabilities.cjs.js",
29
+ "node": {
30
+ "production": "./dist/capabilities.cjs.prod.js",
31
+ "development": "./dist/capabilities.cjs.js",
32
+ "default": "./dist/capabilities.cjs.js"
33
+ }
34
+ }
26
35
  },
27
36
  "sideEffects": false,
28
37
  "repository": {
@@ -34,12 +43,20 @@
34
43
  "formats": [
35
44
  "esm-bundler",
36
45
  "cjs"
46
+ ],
47
+ "additionalEntries": [
48
+ {
49
+ "entry": "capabilities.ts",
50
+ "output": "dist/capabilities.js"
51
+ }
37
52
  ]
38
53
  },
39
54
  "dependencies": {
40
- "@zeus-js/bundler-plugin": "0.1.0-beta.1",
41
- "@zeus-js/component-dts": "0.1.0-beta.1",
42
- "@zeus-js/component-analyzer": "0.1.0-beta.1"
55
+ "@zeus-js/bundler-plugin": "0.1.0-beta.3",
56
+ "@zeus-js/component-analyzer": "0.1.0-beta.3",
57
+ "@zeus-js/runtime-dom": "0.1.0-beta.3",
58
+ "@zeus-js/component-dts": "0.1.0-beta.3",
59
+ "@zeus-js/web-c-runtime": "0.1.0"
43
60
  },
44
61
  "peerDependencies": {
45
62
  "rollup": "^4.0.0"