@stencil/core 5.0.0-beta.34 → 5.0.0-beta.36

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.
@@ -6772,7 +6772,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
6772
6772
  value: mod,
6773
6773
  enumerable: true
6774
6774
  }) : target, mod));
6775
- const HYDRATE_ID = "s-id";
6776
6775
  const XML_NS = "http://www.w3.org/XML/1998/namespace";
6777
6776
  const XMLNS_NS = "http://www.w3.org/2000/xmlns/";
6778
6777
  /**
@@ -7767,19 +7766,7 @@ function* streamToHtml(node, opts, output) {
7767
7766
  const isWithinWhitespaceSensitiveNode = opts.newLines || (opts.indentSpaces ?? 0) > 0 ? isWithinWhitespaceSensitive(node) : false;
7768
7767
  if (!isWithinWhitespaceSensitiveNode && (opts.indentSpaces ?? 0) > 0 && ignoreTag === false) output.indent = output.indent + (opts.indentSpaces ?? 0);
7769
7768
  for (let i = 0; i < childNodeLength; i++) {
7770
- /**
7771
- * In cases where a user would pass in a declarative shadow dom of a
7772
- * Stencil component, we want to skip over the template tag as we
7773
- * will be parsing the shadow root of the component again.
7774
- *
7775
- * We know it is a hydrated Stencil component by checking if the `HYDRATE_ID`
7776
- * is set on the node.
7777
- */
7778
- const sId = node.attributes.getNamedItem(HYDRATE_ID);
7779
- if (childNodes[i].nodeName.toLowerCase() === "template" && sId) {
7780
- yield `\n${" ".repeat(output.indent)}<!--r.${sId.value}-->`;
7781
- continue;
7782
- }
7769
+ if (childNodes[i].nodeName.toLowerCase() === "template" && node.attributes.getNamedItem("s-id")) continue;
7783
7770
  yield* streamToHtml(childNodes[i], opts, output);
7784
7771
  }
7785
7772
  if (ignoreTag === false) {
@@ -11910,6 +11897,77 @@ function constrainTimeouts(win) {
11910
11897
  win.__allowInterval = false;
11911
11898
  win.__maxTimeout = 0;
11912
11899
  }
11900
+ /**
11901
+ * Reset a window so the same object can be used for another render, then parse `html` into its
11902
+ * document.
11903
+ *
11904
+ * Code that captured the window's sub-objects (e.g. an SSR platform holding `win.location`,
11905
+ * `win.console` or `win.document`) keeps working: those objects are kept and reset in place,
11906
+ * rather than replaced. Everything else on the window - including anything a previous render
11907
+ * added - is removed.
11908
+ * @param win the window to reset
11909
+ * @param html the HTML for the next render
11910
+ */
11911
+ function resetWindowForReuse(win, html) {
11912
+ const retained = {
11913
+ console: win.console,
11914
+ document: win.document,
11915
+ eventCounts: win.performance.eventCounts,
11916
+ history: win.history,
11917
+ localStorage: win.localStorage,
11918
+ location: win.location,
11919
+ navigator: win.navigator,
11920
+ orientation: win.screen.orientation,
11921
+ performance: win.performance,
11922
+ screen: win.screen,
11923
+ sessionStorage: win.sessionStorage
11924
+ };
11925
+ if (win.__timeouts) win.__timeouts.forEach((timeoutId) => {
11926
+ nativeClearInterval(timeoutId);
11927
+ nativeClearTimeout(timeoutId);
11928
+ });
11929
+ resetObject(retained.console, createConsole());
11930
+ resetObject(retained.history, new MockHistory());
11931
+ resetObject(retained.location, new MockLocation());
11932
+ resetObject(retained.navigator, new MockNavigator());
11933
+ retained.localStorage.clear();
11934
+ retained.sessionStorage.clear();
11935
+ retained.eventCounts.clear();
11936
+ resetObject(retained.performance, {
11937
+ eventCounts: retained.eventCounts,
11938
+ interactionCount: 0,
11939
+ timeOrigin: Date.now()
11940
+ });
11941
+ for (const key of Reflect.ownKeys(win)) delete win[key];
11942
+ resetWindowDefaults(win);
11943
+ resetWindowDimensions(win);
11944
+ const defaultScreen = win.screen;
11945
+ resetObject(retained.orientation, defaultScreen.orientation);
11946
+ resetObject(retained.screen, {
11947
+ ...defaultScreen,
11948
+ orientation: retained.orientation
11949
+ });
11950
+ win.console = retained.console;
11951
+ win.customElements = null;
11952
+ win.document = retained.document;
11953
+ win.history = retained.history;
11954
+ win.localStorage = retained.localStorage;
11955
+ win.location = retained.location;
11956
+ win.navigator = retained.navigator;
11957
+ win.performance = retained.performance;
11958
+ win.screen = retained.screen;
11959
+ win.sessionStorage = retained.sessionStorage;
11960
+ resetDocumentForReuse(retained.document, win, html);
11961
+ }
11962
+ /**
11963
+ * Replace every own property of `target` with those of `defaults`, keeping the object itself.
11964
+ * @param target the object to reset in place
11965
+ * @param defaults the properties it should have afterwards
11966
+ */
11967
+ function resetObject(target, defaults) {
11968
+ for (const key of Reflect.ownKeys(target)) delete target[key];
11969
+ Object.assign(target, defaults);
11970
+ }
11913
11971
  function resetWindow(win) {
11914
11972
  if (win != null) {
11915
11973
  if (win.__timeouts) {
@@ -12210,6 +12268,37 @@ function resetDocument(doc) {
12210
12268
  } catch {}
12211
12269
  }
12212
12270
  }
12271
+ /**
12272
+ * Reset a document so the same object can be used for another render, then parse `html` into
12273
+ * it. The document object itself is kept (code holding a reference to it stays valid), but its
12274
+ * whole element tree is replaced with freshly parsed elements - so caches keyed on elements, like
12275
+ * the runtime's applied-styles cache keyed on `<head>`, start empty.
12276
+ * @param doc the document to reset
12277
+ * @param win the window that owns the document
12278
+ * @param html the HTML to parse into the document
12279
+ */
12280
+ function resetDocumentForReuse(doc, win, html) {
12281
+ resetDocument(doc);
12282
+ for (const key of Reflect.ownKeys(doc)) if (typeof key !== "string" || !REUSABLE_DOC_KEY_KEEPERS.has(key)) delete doc[key];
12283
+ doc.defaultView = win;
12284
+ doc.documentElement = parseDocumentUtil(doc, html).documentElement;
12285
+ }
12286
+ /** Structural document properties kept by {@link resetDocumentForReuse}; everything else is per-render state. */
12287
+ const REUSABLE_DOC_KEY_KEEPERS = /* @__PURE__ */ new Set([
12288
+ "_nodeValue",
12289
+ "nodeName",
12290
+ "nodeType",
12291
+ "ownerDocument",
12292
+ "parentNode",
12293
+ "_childNodes",
12294
+ "__namespaceURI",
12295
+ "__localName",
12296
+ "defaultView",
12297
+ "cookie",
12298
+ "referrer",
12299
+ "compatMode",
12300
+ "contentType"
12301
+ ]);
12213
12302
  const DOC_KEY_KEEPERS = /* @__PURE__ */ new Set([
12214
12303
  "nodeName",
12215
12304
  "nodeType",
@@ -13360,6 +13449,90 @@ function renderCatchError(results, err) {
13360
13449
  return diagnostic;
13361
13450
  }
13362
13451
  //#endregion
13452
+ //#region src/server/runner/reusable-window.ts
13453
+ /**
13454
+ * A canonical key for a `serializeShadowRoot` value: values that render every component the same
13455
+ * way get the same key.
13456
+ *
13457
+ * Rendering shadow components as scoped permanently changes their metadata inside the SSR platform
13458
+ * that rendered them, so a platform (and a reusable window) can only be shared by renders whose
13459
+ * `serializeShadowRoot` marks the same components as scoped. Which components that is depends
13460
+ * only on this value: for the object form, on `default` and the two tag lists - so those are
13461
+ * normalized (lowercased, de-duplicated, sorted) to give equivalent objects one key.
13462
+ * @param serializeShadowRoot the render's `serializeShadowRoot` option
13463
+ * @returns the key
13464
+ */
13465
+ function serializeShadowRootKey(serializeShadowRoot) {
13466
+ if (serializeShadowRoot === null || typeof serializeShadowRoot !== "object") return `${typeof serializeShadowRoot}:${serializeShadowRoot}`;
13467
+ const opts = serializeShadowRoot;
13468
+ const tags = (list) => Array.isArray(list) ? [...new Set(list.map((tag) => String(tag).toLowerCase()))].sort().join(",") : "";
13469
+ return `object:default=${opts.default};dsd=${tags(opts["declarative-shadow-dom"])};scoped=${tags(opts.scoped)}`;
13470
+ }
13471
+ /** The most reusable windows kept at once (one per distinct `serializeShadowRoot` key). */
13472
+ const MAX_REUSABLE_WINDOWS = 16;
13473
+ /** Long-lived windows used by `reuseWindow` renders, by `serializeShadowRoot` key. */
13474
+ const reusableWindows = /* @__PURE__ */ new Map();
13475
+ /** Renders sharing a reusable window must not overlap, so each key has a queue. */
13476
+ const renderQueues = /* @__PURE__ */ new Map();
13477
+ const NOOP$1 = () => {};
13478
+ /**
13479
+ * Run `render` once every earlier render using the same reusable window has finished.
13480
+ * @param key the render's {@link serializeShadowRootKey}
13481
+ * @param render the render to run
13482
+ * @returns the render's result
13483
+ */
13484
+ function enqueueReusableRender(key, render) {
13485
+ const queued = (renderQueues.get(key) ?? Promise.resolve()).then(render, render);
13486
+ renderQueues.set(key, queued.then(NOOP$1, NOOP$1));
13487
+ return queued;
13488
+ }
13489
+ /**
13490
+ * Get the reusable window for a `serializeShadowRoot` key, reset and holding `html`.
13491
+ * @param html the HTML to render
13492
+ * @param key the render's {@link serializeShadowRootKey}
13493
+ * @returns the window to render into
13494
+ */
13495
+ function getReusableWindow(html, key) {
13496
+ let win = reusableWindows.get(key);
13497
+ if (!win) {
13498
+ if (reusableWindows.size >= MAX_REUSABLE_WINDOWS) reusableWindows.delete(reusableWindows.keys().next().value);
13499
+ win = new MockWindow(html);
13500
+ reusableWindows.set(key, win);
13501
+ return win;
13502
+ }
13503
+ try {
13504
+ resetWindowForReuse(win, html);
13505
+ return win;
13506
+ } catch (e) {
13507
+ discardReusableWindow(key);
13508
+ throw e;
13509
+ }
13510
+ }
13511
+ /**
13512
+ * Stop reusing the window for a key, e.g. after a render failed and may have left it in a bad
13513
+ * state. The next render with that key creates a new one.
13514
+ * @param key the render's {@link serializeShadowRootKey}
13515
+ */
13516
+ function discardReusableWindow(key) {
13517
+ const win = reusableWindows.get(key);
13518
+ reusableWindows.delete(key);
13519
+ try {
13520
+ win?.close();
13521
+ } catch {}
13522
+ }
13523
+ /**
13524
+ * Drop every reusable window and render queue. For hosts where a render can be abandoned without
13525
+ * ever settling (the `ssr-wasm` plugin, when a call ends with a render still waiting), so the
13526
+ * next render doesn't queue behind it forever.
13527
+ */
13528
+ function resetReusableWindows() {
13529
+ for (const win of reusableWindows.values()) try {
13530
+ win.close();
13531
+ } catch {}
13532
+ reusableWindows.clear();
13533
+ renderQueues.clear();
13534
+ }
13535
+ //#endregion
13363
13536
  //#region src/server/runner/runtime-log.ts
13364
13537
  function runtimeLogging(win, opts, results) {
13365
13538
  try {
@@ -13464,6 +13637,29 @@ function initializeWindow(win, doc, opts, results) {
13464
13637
  //#region src/server/runner/render.ts
13465
13638
  const NOOP = () => {};
13466
13639
  /**
13640
+ * Render into the long-lived window for this render's `serializeShadowRoot` mode, once any
13641
+ * earlier render using that window has finished. See the `reuseWindow` option.
13642
+ * @param html the HTML to render
13643
+ * @param opts the normalized render options
13644
+ * @param results the results object to fill in
13645
+ * @returns the render results
13646
+ */
13647
+ function renderInReusableWindow(html, opts, results) {
13648
+ opts.destroyWindow = false;
13649
+ opts.destroyDocument = false;
13650
+ const key = opts.serializeShadowRootKey;
13651
+ const run = async () => {
13652
+ try {
13653
+ await render(getReusableWindow(html, key), opts, results);
13654
+ } catch (e) {
13655
+ discardReusableWindow(key);
13656
+ renderCatchError(results, e);
13657
+ }
13658
+ return results;
13659
+ };
13660
+ return enqueueReusableRender(key, run);
13661
+ }
13662
+ /**
13467
13663
  * Renders HTML to a string, returning the full hydration results.
13468
13664
  * This is the primary SSR function and is portable (no Node.js dependencies).
13469
13665
  * @param html - the HTML string or document to render
@@ -13516,9 +13712,11 @@ function ssrDocument(doc, options) {
13516
13712
  * Defines whether we render the shadow root as a declarative shadow root or as scoped shadow root.
13517
13713
  */
13518
13714
  opts.serializeShadowRoot = typeof opts.serializeShadowRoot === "undefined" ? "declarative-shadow-dom" : opts.serializeShadowRoot;
13715
+ opts.serializeShadowRootKey = serializeShadowRootKey(opts.serializeShadowRoot);
13519
13716
  let win = null;
13520
13717
  const results = generateHydrateResults(opts);
13521
13718
  if (hasError(results.diagnostics)) return Promise.resolve(results);
13719
+ if (typeof doc === "string" && opts.reuseWindow) return renderInReusableWindow(doc, opts, results);
13522
13720
  if (typeof doc === "string") try {
13523
13721
  opts.destroyWindow = true;
13524
13722
  opts.destroyDocument = true;
@@ -13682,4 +13880,21 @@ function removeScripts(elm) {
13682
13880
  }
13683
13881
  }
13684
13882
  //#endregion
13685
- export { createWindowFromHtml, hydrateDocument, renderToString, resetSsrDocData, serializeDocumentToString, setTagTransformer, ssrDocument, streamToString, transformTag };
13883
+ //#region src/server/runner/index.ts
13884
+ /**
13885
+ * Render components under transformed tag names, to match tag transformation on the client.
13886
+ *
13887
+ * Components are registered under their transformed names when a window's SSR platform is set up,
13888
+ * so this also discards the reusable windows (see the `reuseWindow` option): later renders set up
13889
+ * new ones that use the new transformer.
13890
+ *
13891
+ * (A function declaration with its own name, so the runtime's `setTagTransformer` keeps its name in
13892
+ * the bundle - the SSR build looks for it - and this is hoisted.)
13893
+ * @param transformer the tag transformer
13894
+ */
13895
+ function setTagTransformerForSsr(transformer) {
13896
+ setTagTransformer(transformer);
13897
+ resetReusableWindows();
13898
+ }
13899
+ //#endregion
13900
+ export { createWindowFromHtml, hydrateDocument, renderToString, resetReusableWindows, resetSsrDocData, serializeDocumentToString, setTagTransformerForSsr as setTagTransformer, ssrDocument, streamToString, transformTag };
@@ -1,4 +1,4 @@
1
- import { Bt as Logger, nt as CompilerSystem } from "../../index-B0NfYeIA.mjs";
1
+ import { Bt as Logger, nt as CompilerSystem } from "../../index-DG4wtfhx.mjs";
2
2
  //#region src/sys/node/logger/index.d.ts
3
3
  /**
4
4
  * Create a logger to run in a Node environment
@@ -1,2 +1,2 @@
1
- import { n as setupNodeProcess, r as createNodeLogger, t as createNodeSys } from "../../node-eg7pofz5.mjs";
1
+ import { n as setupNodeProcess, r as createNodeLogger, t as createNodeSys } from "../../node-DwwBX_GL.mjs";
2
2
  export { createNodeLogger, createNodeSys, setupNodeProcess };
@@ -1,5 +1,5 @@
1
- import { l as createWorkerMessageHandler } from "../../compiler-CVL510L-.mjs";
2
- import { t as createNodeSys } from "../../node-eg7pofz5.mjs";
1
+ import { l as createWorkerMessageHandler } from "../../compiler-DHNkXDvK.mjs";
2
+ import { t as createNodeSys } from "../../node-DwwBX_GL.mjs";
3
3
  //#region src/sys/node/node-worker-thread.ts
4
4
  /**
5
5
  * Initialize a worker thread, setting up various machinery for managing
@@ -33,7 +33,7 @@ import "@rollup/pluginutils";
33
33
  import { createHash } from "crypto";
34
34
  import { afterAll, vi } from "vitest";
35
35
  //#region src/version.ts
36
- const version = "5.0.0-beta.34";
36
+ const version = "5.0.0-beta.36";
37
37
  const MEMBER_FLAGS = {
38
38
  String: 1,
39
39
  Number: 2,
@@ -1184,6 +1184,13 @@ const NODE_TYPE = {
1184
1184
  const HYDRATE_ID = "s-id";
1185
1185
  const HYDRATED_STYLE_ID = "sty-id";
1186
1186
  const HYDRATE_CHILD_ID = "c-id";
1187
+ /**
1188
+ * Starts an attribute value written by the `ssr` output's `ssrProp()` on a server: a reference to
1189
+ * a value it put in the registry below, for the SSR runtime to take out and set as the prop.
1190
+ */
1191
+ const SSR_PROP_REF_PREFIX = "__stencil_ssr_ref:";
1192
+ /** `Symbol.for()` key of the `ssrProp()` registry on the server's real global object. */
1193
+ const SSR_PROPS_REGISTRY_KEY = "stencil.ssrProps";
1187
1194
  const HYDRATED_CSS = "{visibility:hidden}.hydrated{visibility:inherit}";
1188
1195
  const STENCIL_DOC_DATA = "_stencilDocData";
1189
1196
  const DEFAULT_DOC_DATA = {
@@ -1631,7 +1638,9 @@ const patchTextContent = (hostElementPrototype) => {
1631
1638
  Object.defineProperty(hostElementPrototype, "textContent", {
1632
1639
  get: function() {
1633
1640
  let text = "";
1634
- (this.__childNodes ? this.childNodes : getSlottedChildNodes(this.childNodes)).forEach((node) => text += node.textContent || "");
1641
+ (this.__childNodes ? this.childNodes : getSlottedChildNodes(this.childNodes)).forEach((node) => {
1642
+ if (node.nodeType !== NODE_TYPE.CommentNode) text += node.textContent || "";
1643
+ });
1635
1644
  return text;
1636
1645
  },
1637
1646
  set: function(value) {
@@ -1639,7 +1648,7 @@ const patchTextContent = (hostElementPrototype) => {
1639
1648
  if (node["s-ol"]) node["s-ol"].remove();
1640
1649
  node.remove();
1641
1650
  });
1642
- this.insertAdjacentHTML("beforeend", value);
1651
+ if (value != null && value !== "") this.append(this.ownerDocument.createTextNode(String(value)));
1643
1652
  }
1644
1653
  });
1645
1654
  };
@@ -2171,7 +2180,7 @@ const effect = (fn, options) => getCore().effect(fn, options);
2171
2180
  function signal(value, options) {
2172
2181
  return getCore().signal(value, options);
2173
2182
  }
2174
- const getRegistry = () => customElements;
2183
+ const getRegistry = () => globalThis.customElements;
2175
2184
  /**
2176
2185
  * @param elm a defined component host
2177
2186
  * @returns the registry the host's class was defined in, else the active registry
@@ -4146,6 +4155,11 @@ const addSlottedNodes = (slottedNodes, slotNodeId, slotName, slotNode, hostId) =
4146
4155
  * @returns the first corresponding node of the type
4147
4156
  */
4148
4157
  const findCorrespondingNode = (node, type) => {
4158
+ if (type === NODE_TYPE.TextNode) {
4159
+ const next = node.nextSibling;
4160
+ if (next?.nodeType === NODE_TYPE.TextNode) return next;
4161
+ return node.parentNode.insertBefore(node.ownerDocument.createTextNode(""), next);
4162
+ }
4149
4163
  let sibling = node;
4150
4164
  do
4151
4165
  sibling = sibling.nextSibling;
@@ -5615,7 +5629,10 @@ const insertVNodeAnnotations = (doc, hostElm, vnode, docData, cmpData) => {
5615
5629
  if (vnode != null) {
5616
5630
  const hostId = ++docData.hostIds;
5617
5631
  hostElm.setAttribute(HYDRATE_ID, hostId);
5618
- if (hostElm["s-cr"] != null) hostElm["s-cr"].nodeValue = `r.${hostId}`;
5632
+ if (hostElm["s-cr"] != null) {
5633
+ if (hostElm.shadowRoot) hostElm["s-cr"].remove();
5634
+ else hostElm["s-cr"].nodeValue = `r.${hostId}`;
5635
+ }
5619
5636
  if (vnode.$children$ != null) {
5620
5637
  const depth = 0;
5621
5638
  vnode.$children$.forEach((vnodeChild, index) => {
@@ -5975,6 +5992,7 @@ new RegExp(`^(${[.../* @__PURE__ */ new Set([
5975
5992
  "vm",
5976
5993
  "zlib"
5977
5994
  ])].join("|")})$`);
5995
+ `${JSON.stringify(SSR_PROP_REF_PREFIX)}${JSON.stringify(SSR_PROPS_REGISTRY_KEY)}`;
5978
5996
  promisify(execFile);
5979
5997
  process.platform;
5980
5998
  new Set([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stencil/core",
3
- "version": "5.0.0-beta.34",
3
+ "version": "5.0.0-beta.36",
4
4
  "description": "A Compiler for Web Components and Progressive Web Apps",
5
5
  "keywords": [
6
6
  "components",
@@ -126,9 +126,9 @@
126
126
  "terser": "^5.50.0",
127
127
  "tinyglobby": "^0.2.17",
128
128
  "typescript": ">5.0.0 <7.0.0",
129
- "@stencil/cli": "5.0.0-beta.34",
130
- "@stencil/dev-server": "5.0.0-beta.34",
131
- "@stencil/mock-doc": "5.0.0-beta.34"
129
+ "@stencil/dev-server": "5.0.0-beta.36",
130
+ "@stencil/cli": "5.0.0-beta.36",
131
+ "@stencil/mock-doc": "5.0.0-beta.36"
132
132
  },
133
133
  "devDependencies": {
134
134
  "@ionic/prettier-config": "^4.0.0",