@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.
@@ -1,9 +1,9 @@
1
1
  import { n as __require } from "./rolldown-runtime-BhDjJH2R.mjs";
2
- import { E as SERVER_BUILD_FLAGS, T as HYDRATED_CSS, w as CLIENT_BUILD_FLAGS } from "./client-UbH-XkYu.mjs";
2
+ import { A as SSR_PROP_REF_PREFIX, D as HYDRATE_ID, E as HYDRATE_CHILD_ID, O as SERVER_BUILD_FLAGS, T as HYDRATED_CSS, k as SSR_PROPS_REGISTRY_KEY, w as CLIENT_BUILD_FLAGS } from "./client-CqQpuOUk.mjs";
3
3
  import { $ as VALID_CONFIG_OUTPUT_TARGETS, A as DIST_LAZY, D as COPY, E as COLLECTION_MANIFEST_FILE_NAME, J as STANDALONE, L as EVENT_FLAGS, P as DOCS_JSON, Q as TYPES, R as GENERATED_DTS, S as ASSETS, T as COLLECTION_APP_DATA_FILE_NAME, U as LOADER_BUNDLE, X as STYLE_EXT, Y as STATS, a as isBoolean$1, b as unique, c as isFunction, d as isObject, et as WATCH_FLAGS, f as isString$1, g as sortBy, i as fromEntries, l as isIterable, m as noop, p as mergeIntoWith, r as flatOne, t as dashToPascalCase, u as isNumber$1, v as toDashCase, w as COLLECTION, y as toTitleCase, z as GLOBAL_STYLE } from "./helpers-Cpp3qc3u.mjs";
4
4
  import { E as escapeRegExpSpecialCharacters, S as formatComponentRuntimeMeta, T as byteSize, _ as loadRolldownDiagnostics, a as getSourceMappingUrlForEndOfFile, b as splitLineBreaks, c as err, f as augmentDiagnosticWithNode, g as isRolldownError, h as createOnWarnFn, i as getInlineSourceMappingUrlLinker, l as map, m as loadTypeScriptDiagnostics, n as validateComponentTag, p as loadTypeScriptDiagnostic, r as isRemoteUrl, s as rolldownToStencilSourceMap, t as validateComponentModes, u as ok, w as stringifyRuntimeData, x as isRootPath, y as normalizeDiagnostics } from "./validation-BlVm1Vu0.mjs";
5
5
  import { $ as buildWarn, A as isOutputTargetDocsVscode, B as isValidConfigOutputTarget, C as isOutputTargetDistLazy, D as isOutputTargetDocsCustomElementsManifest, E as isOutputTargetDocsCustom, F as isOutputTargetSsrWasm, G as normalizeFsPath, H as shouldExcludeComponent, I as isOutputTargetStandalone, J as relative$1, K as normalizeFsPathQuery, L as isOutputTargetStats, M as isOutputTargetLoaderBundle, N as isOutputTargetServerRenderer, O as isOutputTargetDocsJson, P as isOutputTargetSsr, Q as buildJsonFileError, R as isOutputTargetTypes, S as isOutputTargetCustom, T as isOutputTargetDocsAgentSkill, U as join$2, V as relativeImport, Y as resolve$2, Z as buildError, a as hasDependency, b as isOutputTargetCollection, d as parsePackageJson, et as catchError, f as readOnlyArrayHasStringMember, g as getComponentsDtsSrcFilePath, h as filterExcludedComponents, i as getTextDocs, it as isGlob, j as isOutputTargetGlobalStyle, k as isOutputTargetDocsReadme, l as isTsFile, m as filterActiveTargets, n as createJsVarName, nt as hasWarning, o as isDtsFile, p as readPackageJson, q as normalizePath, r as generatePreamble, t as addDocBlock, tt as hasError, u as isTsxFile, v as getComponentsFromModules, w as isOutputTargetDocs, x as isOutputTargetCopy, y as isOutputTargetAssets, z as isOutputTargetWww } from "./util-C-H1H84W.mjs";
6
- import { i as CustomElementsExportBehaviorOptions, o as buildEvents, r as createNodeLogger, t as createNodeSys } from "./node-eg7pofz5.mjs";
6
+ import { i as CustomElementsExportBehaviorOptions, o as buildEvents, r as createNodeLogger, t as createNodeSys } from "./node-DwwBX_GL.mjs";
7
7
  import ts, { default as ts$1 } from "typescript";
8
8
  import { readFileSync } from "node:fs";
9
9
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
@@ -461,9 +461,9 @@ const scopeCss = (cssText, scopeId, commentOriginalSelector) => {
461
461
  };
462
462
  //#endregion
463
463
  //#region src/version.ts
464
- const version = "5.0.0-beta.34";
465
- const buildId = "1793980027";
466
- const vermoji = "🦀";
464
+ const version = "5.0.0-beta.36";
465
+ const buildId = "1794253443";
466
+ const vermoji = "🌎";
467
467
  /**
468
468
  * Get the installed version of a tool/dependency.
469
469
  * Handles packages with exports maps that point to subdirectories.
@@ -3049,6 +3049,9 @@ const objectLiteralToObjectMap = (objectLiteral, typeChecker, diagnostics, error
3049
3049
  case ts.SyntaxKind.FalseKeyword:
3050
3050
  val = false;
3051
3051
  break;
3052
+ case ts.SyntaxKind.NullKeyword:
3053
+ val = null;
3054
+ break;
3052
3055
  case ts.SyntaxKind.Identifier:
3053
3056
  const escapedText = propAssignment.initializer.escapedText;
3054
3057
  if (escapedText === "String") val = String;
@@ -3235,7 +3238,7 @@ const getAllTypeReferences = (checker, node) => {
3235
3238
  */
3236
3239
  const getTypeReferenceLocation = (typeName, type, sourceFile, checker, program) => {
3237
3240
  const importTypeDeclaration = sourceFile.statements.find((st) => {
3238
- if (!(ts.isImportDeclaration(st) && st.importClause && ts.isImportClause(st.importClause) && st.importClause.namedBindings && ts.isNamedImports(st.importClause.namedBindings) && Array.isArray(st.importClause.namedBindings.elements) && st.importClause.namedBindings.elements.find((nbe) => nbe.name.getText() === typeName))) return false;
3241
+ if (!(ts.isImportDeclaration(st) && st.importClause && ts.isImportClause(st.importClause) && st.importClause.namedBindings && ts.isNamedImports(st.importClause.namedBindings) && Array.isArray(st.importClause.namedBindings.elements) && st.importClause.namedBindings.elements.find((nbe) => nbe.name.text === typeName))) return false;
3239
3242
  return true;
3240
3243
  });
3241
3244
  const namedImportBindings = importTypeDeclaration?.importClause?.namedBindings;
@@ -3244,7 +3247,7 @@ const getTypeReferenceLocation = (typeName, type, sourceFile, checker, program)
3244
3247
  const options = program.getCompilerOptions();
3245
3248
  const importHomeModule = getHomeModule(sourceFile, localImportPath, options, ts.createCompilerHost(options), program);
3246
3249
  if (importHomeModule) {
3247
- const importElement = namedImportBindings.elements.find((nbe) => nbe.name.getText() === typeName);
3250
+ const importElement = namedImportBindings.elements.find((nbe) => nbe.name.text === typeName);
3248
3251
  const importName = importElement.name;
3249
3252
  const originalTypeName = getOriginalTypeName(importName, checker);
3250
3253
  const importedAs = importElement.propertyName ? importElement.propertyName.getText() : typeName;
@@ -7705,9 +7708,9 @@ const updateStencilCoreImports = (updatedCoreImportPath) => {
7705
7708
  }
7706
7709
  if (moduleSpecifierText === "@stencil/core") {
7707
7710
  if (s.importClause && s.importClause.namedBindings && s.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) {
7708
- const keepImports = s.importClause.namedBindings.elements.map((e) => e.getText()).filter((name) => KEEP_IMPORTS.has(name));
7711
+ const keepImports = s.importClause.namedBindings.elements.filter((e) => KEEP_IMPORTS.has((e.propertyName ?? e.name).text));
7709
7712
  if (keepImports.length > 0) {
7710
- const newImport = ts.factory.updateImportDeclaration(s, void 0, ts.factory.createImportClause(false, void 0, ts.factory.createNamedImports(keepImports.map((name) => ts.factory.createImportSpecifier(false, void 0, ts.factory.createIdentifier(name))))), ts.factory.createStringLiteral(updatedCoreImportPath), void 0);
7713
+ const newImport = ts.factory.updateImportDeclaration(s, void 0, ts.factory.createImportClause(false, void 0, ts.factory.createNamedImports(keepImports.map((e) => ts.factory.createImportSpecifier(false, e.propertyName ? ts.factory.createIdentifier(e.propertyName.text) : void 0, ts.factory.createIdentifier(e.name.text))))), ts.factory.createStringLiteral(updatedCoreImportPath), void 0);
7711
7714
  newStatements.push(newImport);
7712
7715
  }
7713
7716
  }
@@ -12524,10 +12527,44 @@ const SSR_FACTORY_INTRO = `
12524
12527
  // Used for the hydrate timeout timer to avoid being affected by constrainTimeouts.
12525
12528
  var $nativeSetTimeout = (typeof globalThis !== 'undefined' ? globalThis : global).setTimeout;
12526
12529
  var $nativeClearTimeout = (typeof globalThis !== 'undefined' ? globalThis : global).clearTimeout;
12530
+ // Holds the \`ssrProp()\` registry, which template code writes to outside the factory.
12531
+ var $stencilNativeGlobal = typeof globalThis !== 'undefined' ? globalThis : global;
12527
12532
  // Used to abort in-flight fetch() calls and to call any user defined AbortControllers when ssr times out.
12528
12533
  var $stencilNativeAbortController = AbortController;
12529
12534
 
12535
+ // Evaluated SSR platforms, per window and per serializeShadowRoot mode. Evaluating the platform
12536
+ // (runtime, vdom and every component class) is the main fixed cost of a render, so a window that's
12537
+ // rendered into again (see the \`reuseWindow\` option) reuses it. A new window gets a new platform.
12538
+ var $stencilSsrApps = new WeakMap();
12539
+
12530
12540
  export function ssrFactory($stencilWindow, $stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve) {
12541
+ // Rendering shadow components as scoped permanently changes their metadata inside the platform,
12542
+ // so a platform is only shared by renders whose serializeShadowRoot marks the same components as
12543
+ // scoped: keyed by the canonical key the renderer computes for it.
12544
+ var $stencilShadowModeKey = $stencilHydrateOpts.serializeShadowRootKey;
12545
+ var $stencilApp;
12546
+ if (typeof $stencilShadowModeKey !== 'string') {
12547
+ $stencilApp = $stencilCreateSsrApp($stencilWindow);
12548
+ } else {
12549
+ var $stencilWindowApps = $stencilSsrApps.get($stencilWindow);
12550
+ if (!$stencilWindowApps) {
12551
+ $stencilWindowApps = new Map();
12552
+ $stencilSsrApps.set($stencilWindow, $stencilWindowApps);
12553
+ }
12554
+ $stencilApp = $stencilWindowApps.get($stencilShadowModeKey);
12555
+ if (!$stencilApp) {
12556
+ $stencilApp = $stencilCreateSsrApp($stencilWindow);
12557
+ $stencilWindowApps.set($stencilShadowModeKey, $stencilApp);
12558
+ }
12559
+ }
12560
+ $stencilApp($stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve);
12561
+ }
12562
+
12563
+ /**
12564
+ * Evaluates the SSR platform for a window, and returns a function that renders with it.
12565
+ * Renders using the same platform must run one at a time.
12566
+ */
12567
+ function $stencilCreateSsrApp($stencilWindow) {
12531
12568
  var globalThis = $stencilWindow;
12532
12569
  var self = $stencilWindow;
12533
12570
  var top = $stencilWindow;
@@ -12616,7 +12653,9 @@ export function ssrFactory($stencilWindow, $stencilHydrateOpts, $stencilHydrateR
12616
12653
  // Aborted when the render times out or errors, so in-flight fetch() calls
12617
12654
  // made by component code stop holding the render's window/results alive
12618
12655
  // instead of running to completion against a torn-down window. See #6864.
12619
- var $stencilAbortController = new $stencilNativeAbortController();
12656
+ // A new one is created for every render (see the function returned below),
12657
+ // so one render's timeout never cancels the next render's work.
12658
+ var $stencilAbortController;
12620
12659
 
12621
12660
  // Any AbortController a component creates itself is transparently wired to
12622
12661
  // cascade-abort when the render times out too, so component code using the
@@ -12688,10 +12727,19 @@ export function ssrFactory($stencilWindow, $stencilHydrateOpts, $stencilHydrateR
12688
12727
  `;
12689
12728
  const SSR_FACTORY_OUTRO = `
12690
12729
  /*hydrateAppClosure end*/
12691
- ssrApp(window, $stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve, $stencilAbortController);
12730
+ return function ($stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve) {
12731
+ $stencilAbortController = new $stencilNativeAbortController();
12732
+ // a reused window is reset between renders, which removes these; put them back
12733
+ $stencilWindow.fetch = fetch;
12734
+ $stencilWindow.FetchError = FetchError;
12735
+ $stencilWindow.Headers = Headers;
12736
+ $stencilWindow.Request = Request;
12737
+ $stencilWindow.Response = Response;
12738
+ ssrApp(window, $stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve, $stencilAbortController);
12739
+ };
12692
12740
  }
12693
12741
 
12694
- hydrateAppClosure($stencilWindow);
12742
+ return hydrateAppClosure($stencilWindow);
12695
12743
  }
12696
12744
  `;
12697
12745
  //#endregion
@@ -12805,6 +12853,7 @@ const writeSsrOutput = async (config, compilerCtx, buildCtx, outputTarget, rolld
12805
12853
  const hydrateAppDirPath = outputTarget.dir;
12806
12854
  if (!hydrateAppDirPath) throw new Error(`outputTarget config missing the "dir" property`);
12807
12855
  await copySsrRunnerDts(config, compilerCtx, hydrateAppDirPath);
12856
+ await writeSsrPropModule(compilerCtx, hydrateAppDirPath, outputTarget.cjs === true);
12808
12857
  buildCtx.ssrAppFilePath = join$2(hydrateAppDirPath, "index.js");
12809
12858
  const minify = outputTarget.minify === true;
12810
12859
  await Promise.all(rolldownOutput.output.map(async (output) => {
@@ -12828,7 +12877,86 @@ const copySsrRunnerDts = async (config, compilerCtx, hydrateAppDirPath) => {
12828
12877
  const packageDir = join$2(config.sys.getCompilerExecutingPath(), "..", "..");
12829
12878
  const srcSsrDir = join$2(packageDir, "runtime", "server", "runner.d.mts");
12830
12879
  const runnerDtsDestPath = join$2(hydrateAppDirPath, "index.d.ts");
12831
- await compilerCtx.fs.copyFile(srcSsrDir, runnerDtsDestPath);
12880
+ const dts = await config.sys.readFile(srcSsrDir);
12881
+ if (dts == null) return;
12882
+ await compilerCtx.fs.writeFile(runnerDtsDestPath, stripSideEffectImports(dts), { immediateWrite: true });
12883
+ };
12884
+ /**
12885
+ * The bundled runner types keep bare imports (`import "rolldown";`) of modules whose types were
12886
+ * tree-shaken away. They declare nothing, but a library's consumers won't have those packages
12887
+ * (often not even `@stencil/core`), which breaks under `noUncheckedSideEffectImports`.
12888
+ * @param dts the runner's `.d.mts` contents
12889
+ * @returns the contents without bare imports
12890
+ */
12891
+ const stripSideEffectImports = (dts) => dts.replace(/^import\s*["'][^"']+["'];?[ \t]*\r?\n/gm, "");
12892
+ const SSR_PROP_JS = `const PREFIX = ${JSON.stringify(SSR_PROP_REF_PREFIX)};
12893
+ const REGISTRY = Symbol.for(${JSON.stringify(SSR_PROPS_REGISTRY_KEY)});
12894
+ // a value nothing picked up (the page never reached renderToString()) is dropped after this long
12895
+ const TTL = 60000;
12896
+ let nextSweep = 0;
12897
+
12898
+ /**
12899
+ * Pass a value to a component's property from a framework template, so it reaches the component
12900
+ * when it's rendered on the server too. In the browser, returns the value. On the server, keeps
12901
+ * the value and returns a reference to it, which the template renders as an attribute and the
12902
+ * SSR module (in the same process) turns back into the value. Getting it on to the browser is the
12903
+ * prop's job: @Prop({ serialize: 'json' }), or a @PropSerialize() / @AttrDeserialize() pair.
12904
+ */
12905
+ export function ssrProp(value) {
12906
+ if (typeof window !== 'undefined') return value;
12907
+ const registry = globalThis[REGISTRY] || (globalThis[REGISTRY] = new Map());
12908
+ const now = Date.now();
12909
+ if (now > nextSweep) {
12910
+ nextSweep = now + TTL;
12911
+ for (const [id, entry] of registry) if (entry.expires < now) registry.delete(id);
12912
+ }
12913
+ const id = globalThis.crypto && globalThis.crypto.randomUUID
12914
+ ? globalThis.crypto.randomUUID()
12915
+ : Math.random().toString(36).slice(2) + now.toString(36);
12916
+ registry.set(id, { value, expires: now + TTL });
12917
+ return PREFIX + id;
12918
+ }
12919
+ `;
12920
+ const SSR_PROP_DTS = `/**
12921
+ * Pass a value to a component's property from a framework template, so it reaches the component
12922
+ * when it's rendered on the server too.
12923
+ *
12924
+ * \`\`\`vue
12925
+ * <my-chart :data="ssrProp(data)" />
12926
+ * \`\`\`
12927
+ *
12928
+ * In the browser, returns the value. On the server, keeps the value and returns a reference to it
12929
+ * (a string the template renders as an attribute), which the SSR module turns back into the
12930
+ * value. Nothing is serialized, so any value works: a \`Map\`, a \`Date\`, a class instance.
12931
+ *
12932
+ * The SSR module must render the page in the same process, soon after the template runs: the
12933
+ * whole-document \`renderToString()\` hook every framework integration uses.
12934
+ *
12935
+ * This gets the value into the server render only. For the component to have it when it first
12936
+ * renders in the browser too, before the framework sets the property, the prop needs to carry it
12937
+ * in its attribute: \`@Prop({ serialize: 'json' })\`, or a \`@PropSerialize()\` /
12938
+ * \`@AttrDeserialize()\` pair for other formats. Without either, \`renderToString()\` adds a
12939
+ * warning to its \`diagnostics\`.
12940
+ * @param value the property value
12941
+ * @returns \`value\` in the browser, a reference to it (a string) typed as \`T\` on the server
12942
+ */
12943
+ export declare function ssrProp<T>(value: T): T;
12944
+ `;
12945
+ /**
12946
+ * Write `ssr-prop.js` (`./ssr-prop` in export maps): `ssrProp()`, for framework templates. It runs
12947
+ * on both server and client, so it's separate from the server-only SSR module.
12948
+ * @param compilerCtx the compiler context
12949
+ * @param dir the ssr output directory
12950
+ * @param cjs whether to also write a CommonJS copy
12951
+ */
12952
+ const writeSsrPropModule = async (compilerCtx, dir, cjs) => {
12953
+ const opts = { immediateWrite: true };
12954
+ await compilerCtx.fs.writeFile(join$2(dir, "ssr-prop.js"), SSR_PROP_JS, opts);
12955
+ await compilerCtx.fs.writeFile(join$2(dir, "ssr-prop.d.ts"), SSR_PROP_DTS, opts);
12956
+ if (cjs) {
12957
+ const cjsCode = SSR_PROP_JS.replace("export function ssrProp", "function ssrProp") + "exports.ssrProp = ssrProp;\n";
12958
+ await compilerCtx.fs.writeFile(join$2(dir, "ssr-prop.cjs"), cjsCode, opts);
12959
+ }
12832
12960
  };
12833
12961
  //#endregion
12834
12962
  //#region src/compiler/output-targets/ssr/generate-ssr-app.ts
@@ -12941,10 +13069,42 @@ const generateSsrFactoryEntry = async (buildCtx) => {
12941
13069
  return s.toString();
12942
13070
  };
12943
13071
  //#endregion
13072
+ //#region src/compiler/output-targets/ssr/validate-reserved-attributes.ts
13073
+ /** Attributes server rendering writes on component hosts and the nodes they render. */
13074
+ const SSR_ATTRIBUTES = /* @__PURE__ */ new Set([
13075
+ HYDRATE_ID,
13076
+ HYDRATE_CHILD_ID,
13077
+ "s-sn",
13078
+ "s-mode"
13079
+ ]);
13080
+ /**
13081
+ * Report props whose attribute would collide with one server rendering writes (`@Prop() sId` is
13082
+ * `s-id`): the server would overwrite or remove the value and the client would misread it. Only
13083
+ * relevant to builds that render on a server, so it's run by the `ssr` and `ssr-wasm` outputs.
13084
+ *
13085
+ * Complex props have no attribute of their own, but templates bind `ssrProp()` values under the
13086
+ * dash-cased prop name, so that's checked too.
13087
+ *
13088
+ * @param config the validated config
13089
+ * @param buildCtx the current build context
13090
+ */
13091
+ const validateSsrReservedAttributes = (config, buildCtx) => {
13092
+ for (const cmp of buildCtx.components) for (const prop of cmp.properties) {
13093
+ const attribute = prop.attribute ?? toDashCase(prop.name);
13094
+ if (!SSR_ATTRIBUTES.has(attribute)) continue;
13095
+ const err = buildError(buildCtx.diagnostics);
13096
+ err.header = "Reserved Attribute Name";
13097
+ err.messageText = `The "${prop.name}" prop of <${cmp.tagName}> uses the attribute "${attribute}", which Stencil writes when it renders on the server. Rename the prop, or give it another attribute name: @Prop({ attribute: '...' }).`;
13098
+ err.absFilePath = cmp.sourceFilePath;
13099
+ err.relFilePath = relative$1(config.rootDir, cmp.sourceFilePath);
13100
+ }
13101
+ };
13102
+ //#endregion
12944
13103
  //#region src/compiler/output-targets/ssr/index.ts
12945
13104
  const outputSsr = async (config, compilerCtx, buildCtx) => {
12946
13105
  const ssrOutputTargets = filterActiveTargets(config.outputTargets.filter(isOutputTargetSsr), config.devMode);
12947
13106
  if (ssrOutputTargets.length > 0) {
13107
+ validateSsrReservedAttributes(config, buildCtx);
12948
13108
  const timespan = buildCtx.createTimeSpan(`generate SSR app started`);
12949
13109
  await generateSsrApp(config, compilerCtx, buildCtx, ssrOutputTargets);
12950
13110
  timespan.finish(`generate SSR app finished`);
@@ -13081,9 +13241,17 @@ const SSR_WASM_INTERFACE = `declare module "main" {
13081
13241
  export function resetSsrDocData(): void;
13082
13242
  }\n`;
13083
13243
  const SSR_WASM_OUTRO = `
13244
+ // Whether a renderToString call is in progress. Still true at the start of a call means the last
13245
+ // call ended with its render waiting on work that never resolved (see below).
13246
+ var $stencilWasmRenderInProgress = false;
13247
+
13084
13248
  module.exports = {
13085
13249
  renderToString: async function() {
13086
13250
  try {
13251
+ if ($stencilWasmRenderInProgress && typeof resetReusableWindows === 'function') {
13252
+ // That render will never finish, so it would hold its reusable window and queue forever.
13253
+ resetReusableWindows();
13254
+ }
13087
13255
  if (typeof renderToString !== 'function') {
13088
13256
  Host.outputString(JSON.stringify({ __error: 'renderToString is ' + typeof renderToString }));
13089
13257
  return;
@@ -13095,15 +13263,20 @@ module.exports = {
13095
13263
  // silence, then overwrite it once renderToString() actually resolves.
13096
13264
  Host.outputString(JSON.stringify({ __error: 'renderToString did not complete - a component may be waiting on work that never resolves' }));
13097
13265
  var opts = inp.options || {};
13266
+ // A plugin instance runs one call at a time, so its renders can always share one window
13267
+ // (see the reuseWindow option). Skips re-evaluating the whole platform on every call.
13268
+ if (typeof opts.reuseWindow !== 'boolean') opts.reuseWindow = true;
13098
13269
  var budget = typeof opts.timeout === 'number' ? opts.timeout : 15000;
13099
13270
  var timers = globalThis.__stencilSsrWasmTimers;
13100
13271
  var render = timers && timers.start(budget, function() {
13101
13272
  Host.outputString(JSON.stringify({ __error: 'renderToString did not complete within the ' + budget + 'ms timeout - a component may be waiting on work that never resolves, on a timer due after the timeout, or on timers it schedules forever' }));
13102
13273
  });
13103
13274
  var result;
13275
+ $stencilWasmRenderInProgress = true;
13104
13276
  try {
13105
- result = await renderToString(inp.html, inp.options);
13277
+ result = await renderToString(inp.html, opts);
13106
13278
  } finally {
13279
+ $stencilWasmRenderInProgress = false;
13107
13280
  if (render) timers.stop(render);
13108
13281
  }
13109
13282
  // renderToString reports some failures (e.g. input that isn't an HTML string) as an
@@ -13129,6 +13302,9 @@ module.exports = {
13129
13302
  var m = mappings.find(function(x) { return x.from === tag; });
13130
13303
  return m ? m.to : tag;
13131
13304
  });
13305
+ // Platforms register components under their transformed tags when they're set up, so the
13306
+ // reused windows' platforms have to be set up again.
13307
+ if (typeof resetReusableWindows === 'function') resetReusableWindows();
13132
13308
  },
13133
13309
  resetSsrDocData: function() {
13134
13310
  resetSsrDocData();
@@ -13225,6 +13401,7 @@ const compileToWasm = async (buildCtx, jsPath, interfacePath, wasmPath) => {
13225
13401
  const outputSsrWasm = async (config, compilerCtx, buildCtx) => {
13226
13402
  const ssrWasmTargets = filterActiveTargets(config.outputTargets.filter(isOutputTargetSsrWasm), config.devMode);
13227
13403
  if (ssrWasmTargets.length > 0) {
13404
+ if (filterActiveTargets(config.outputTargets.filter(isOutputTargetSsr), config.devMode).length === 0) validateSsrReservedAttributes(config, buildCtx);
13228
13405
  const timespan = buildCtx.createTimeSpan(`generate SSR WASM started`);
13229
13406
  await generateSsrWasmApp(config, compilerCtx, buildCtx, ssrWasmTargets);
13230
13407
  timespan.finish(`generate SSR WASM finished`);
@@ -13305,17 +13482,9 @@ const createDefineCase = (tagName, actionExpression) => {
13305
13482
  return ts.factory.createCaseClause(ts.factory.createStringLiteral(tagName), [ts.factory.createIfStatement(getCheck, ts.factory.createBlock([ts.factory.createExpressionStatement(actionExpression)])), ts.factory.createBreakStatement()]);
13306
13483
  };
13307
13484
  /**
13308
- * Adds the exported `defineCustomElement` function declaration.
13485
+ * Adds the exported `defineCustomElement` function declaration. `__stencil_getRegistry()` returns
13486
+ * `undefined` where there's no `customElements` (e.g. on a server), so the call is a no-op there.
13309
13487
  *
13310
- * Global path:
13311
- * ```js
13312
- * export function defineCustomElement() {
13313
- * if (typeof customElements === 'undefined') return;
13314
- * ['my-comp', ...].forEach(tagName => { switch (tagName) { ... } });
13315
- * }
13316
- * ```
13317
- *
13318
- * Scoped path:
13319
13488
  * ```js
13320
13489
  * export function defineCustomElement(opts) {
13321
13490
  * const _storeReg = __stencil_getRegistry();
@@ -15838,8 +16007,8 @@ var ImportAliasMap = class extends Map {
15838
16007
  for (const importDeclaration of importDeclarations) if (importDeclaration.moduleSpecifier.getText().includes("@stencil/core")) {
15839
16008
  const namedBindings = importDeclaration.importClause?.namedBindings;
15840
16009
  if (namedBindings && ts.isNamedImports(namedBindings)) for (const element of namedBindings.elements) {
15841
- const importName = element.name.getText();
15842
- const originalImportName = element.propertyName?.getText() ?? importName;
16010
+ const importName = element.name.text;
16011
+ const originalImportName = element.propertyName?.text ?? importName;
15843
16012
  if (STENCIL_DECORATORS.includes(originalImportName)) this.set(originalImportName, importName);
15844
16013
  }
15845
16014
  }
@@ -15849,6 +16018,102 @@ var ImportAliasMap = class extends Map {
15849
16018
  }
15850
16019
  };
15851
16020
  //#endregion
16021
+ //#region src/compiler/transformers/decorators-to-static/json-serialize-prop.ts
16022
+ /**
16023
+ * `@Prop({ serialize: 'json' })` is shorthand for a `@PropSerialize()` / `@AttrDeserialize()` pair
16024
+ * that writes the value to the prop's attribute as JSON on the server, and reads it back in the
16025
+ * browser. These are the generated methods' names (no leading `_`: the runtime metadata drops
16026
+ * those keys), and the alias of the `Build` import they use.
16027
+ */
16028
+ const JSON_SERIALIZE_METHOD = "stencilSerializeJson";
16029
+ const JSON_DESERIALIZE_METHOD = "stencilDeserializeJson";
16030
+ const BUILD_ALIAS = "__stencil_Build";
16031
+ /**
16032
+ * Find the props declared `@Prop({ serialize: 'json' })`, reporting invalid combinations.
16033
+ * @param diagnostics for surfacing errors
16034
+ * @param typeChecker a TypeScript typechecker instance
16035
+ * @param decoratedMembers the class's decorated members
16036
+ * @param propDecoratorName the name `@Prop` is imported as
16037
+ * @param handWritten serializers and deserializers written with the decorators
16038
+ * @returns the names of the props to serialize as JSON
16039
+ */
16040
+ const getJsonSerializedProps = (diagnostics, typeChecker, decoratedMembers, propDecoratorName, handWritten) => decoratedMembers.flatMap((member) => {
16041
+ if (!ts.isPropertyDeclaration(member) && !ts.isGetAccessor(member)) return [];
16042
+ const decorator = retrieveTsDecorators(member)?.find(isDecoratorNamed(propDecoratorName));
16043
+ if (!decorator) return [];
16044
+ const [options] = getDecoratorParameters(decorator, typeChecker);
16045
+ if (options?.serialize == null) return [];
16046
+ const { staticName: propName } = tsPropDeclName(member, typeChecker);
16047
+ const error = (messageText) => {
16048
+ const err = buildError(diagnostics);
16049
+ err.messageText = messageText;
16050
+ augmentDiagnosticWithNode(err, decorator);
16051
+ };
16052
+ if (options.serialize !== "json") {
16053
+ error(`@Prop({ serialize }) on "${propName}" must be 'json'. For other formats, use @PropSerialize() and @AttrDeserialize().`);
16054
+ return [];
16055
+ }
16056
+ if (options.attribute === null) {
16057
+ error(`@Prop({ serialize: 'json' }) on "${propName}" needs an attribute to write to, but it has "attribute: null".`);
16058
+ return [];
16059
+ }
16060
+ if (handWritten.some((h) => h.propName === propName)) {
16061
+ error(`"${propName}" has both @Prop({ serialize: 'json' }) and its own @PropSerialize() / @AttrDeserialize(). Use one or the other.`);
16062
+ return [];
16063
+ }
16064
+ return [propName];
16065
+ });
16066
+ /**
16067
+ * The methods `@Prop({ serialize: 'json' })` uses, shared by every such prop in a class:
16068
+ *
16069
+ * ```ts
16070
+ * stencilSerializeJson(value) {
16071
+ * return __stencil_Build.isServer ? JSON.stringify(value) : null;
16072
+ * }
16073
+ * stencilDeserializeJson(value, propName) {
16074
+ * try {
16075
+ * return JSON.parse(value);
16076
+ * } catch {
16077
+ * if (__stencil_Build.isDev) console.warn(...);
16078
+ * // leave the prop as it is
16079
+ * return __stencil_Build.isServer ? undefined : this[propName];
16080
+ * }
16081
+ * }
16082
+ * ```
16083
+ *
16084
+ * The serializer only writes on the server, like a hand-written one should: in the browser the
16085
+ * attribute's job is done, and rewriting it on every change would be wasted work.
16086
+ * @returns the two method declarations
16087
+ */
16088
+ const createJsonSerializerMethods = () => {
16089
+ const f = ts.factory;
16090
+ const build = (flag) => f.createPropertyAccessExpression(f.createIdentifier(BUILD_ALIAS), flag);
16091
+ const jsonCall = (method, arg) => f.createCallExpression(f.createPropertyAccessExpression(f.createIdentifier("JSON"), method), void 0, [arg]);
16092
+ const param = (name) => f.createParameterDeclaration(void 0, void 0, name);
16093
+ const method = (name, params, body) => f.createMethodDeclaration(void 0, void 0, name, void 0, void 0, params.map(param), void 0, f.createBlock(body, true));
16094
+ const serialize = method(JSON_SERIALIZE_METHOD, ["value"], [f.createReturnStatement(f.createConditionalExpression(build("isServer"), void 0, jsonCall("stringify", f.createIdentifier("value")), void 0, f.createNull()))]);
16095
+ const warn = f.createIfStatement(build("isDev"), f.createExpressionStatement(f.createCallExpression(f.createPropertyAccessExpression(f.createIdentifier("console"), "warn"), void 0, [f.createTemplateExpression(f.createTemplateHead("The \""), [f.createTemplateSpan(f.createIdentifier("propName"), f.createTemplateMiddle(`" attribute isn't valid JSON, so the prop was left as it is: `)), f.createTemplateSpan(f.createIdentifier("value"), f.createTemplateTail(""))])])));
16096
+ return [serialize, method(JSON_DESERIALIZE_METHOD, ["value", "propName"], [f.createTryStatement(f.createBlock([f.createReturnStatement(jsonCall("parse", f.createIdentifier("value")))], true), f.createCatchClause(void 0, f.createBlock([warn, f.createReturnStatement(f.createConditionalExpression(build("isServer"), void 0, f.createIdentifier("undefined"), void 0, f.createElementAccessExpression(f.createThis(), f.createIdentifier("propName"))))], true)), void 0)])];
16097
+ };
16098
+ /**
16099
+ * Import `Build` (as {@link BUILD_ALIAS}) from `@stencil/core`, for the generated methods. Added
16100
+ * to an existing `@stencil/core` import, which a component's source always has.
16101
+ * @param sourceFile the source file
16102
+ * @returns the source file with the import
16103
+ */
16104
+ const addBuildImport = (sourceFile) => {
16105
+ const f = ts.factory;
16106
+ const specifier = f.createImportSpecifier(false, f.createIdentifier("Build"), f.createIdentifier(BUILD_ALIAS));
16107
+ let added = false;
16108
+ const statements = sourceFile.statements.map((s) => {
16109
+ if (added || !ts.isImportDeclaration(s) || !ts.isStringLiteral(s.moduleSpecifier) || s.moduleSpecifier.text !== "@stencil/core" || !s.importClause?.namedBindings || !ts.isNamedImports(s.importClause.namedBindings) || s.importClause.isTypeOnly) return s;
16110
+ added = true;
16111
+ return f.updateImportDeclaration(s, s.modifiers, f.updateImportClause(s.importClause, false, s.importClause.name, f.updateNamedImports(s.importClause.namedBindings, [...s.importClause.namedBindings.elements, specifier])), s.moduleSpecifier, s.attributes);
16112
+ });
16113
+ if (!added) statements.unshift(f.createImportDeclaration(void 0, f.createImportClause(false, void 0, f.createNamedImports([specifier])), f.createStringLiteral(STENCIL_CORE_ID)));
16114
+ return f.updateSourceFile(sourceFile, statements);
16115
+ };
16116
+ //#endregion
15852
16117
  //#region src/compiler/transformers/decorators-to-static/listen-decorator.ts
15853
16118
  const listenDecoratorsToStatic = (diagnostics, typeChecker, decoratedMembers, newMembers, decoratorName) => {
15854
16119
  const listeners = decoratedMembers.filter(ts.isMethodDeclaration).map((method) => parseListenDecorators(diagnostics, typeChecker, method, decoratorName));
@@ -16262,7 +16527,7 @@ const isTypePromise = (typeStr) => {
16262
16527
  };
16263
16528
  const validateMethods = (diagnostics, members) => {
16264
16529
  members.filter(ts.isMethodDeclaration).map((method) => {
16265
- if (method.name.getText() === "componentDidUnload") {
16530
+ if (ts.isIdentifier(method.name) && method.name.text === "componentDidUnload") {
16266
16531
  const err = buildError(diagnostics);
16267
16532
  err.header = `Replace "componentDidUnload()" with "disconnectedCallback()"`;
16268
16533
  err.messageText = `The "componentDidUnload()" method was removed in Stencil 2. Please use the "disconnectedCallback()" method instead.`;
@@ -16627,7 +16892,7 @@ const getPropertyNameText = (name) => {
16627
16892
  };
16628
16893
  //#endregion
16629
16894
  //#region src/compiler/transformers/decorators-to-static/serialize-decorators.ts
16630
- const serializeDecoratorsToStatic = (typeChecker, decoratedProps, newMembers, decoratorName, translateType, propDecoratorName) => {
16895
+ const serializeDecoratorsToStatic = (typeChecker, decoratedProps, newMembers, decoratorName, translateType, propDecoratorName, generated = []) => {
16631
16896
  const props = decoratedProps.filter((prop) => ts.isPropertyDeclaration(prop) || ts.isGetAccessor(prop)).flatMap((prop) => {
16632
16897
  if (retrieveTsDecorators(prop)?.find(isDecoratorNamed(propDecoratorName))) {
16633
16898
  const { staticName } = tsPropDeclName(prop, typeChecker);
@@ -16635,7 +16900,7 @@ const serializeDecoratorsToStatic = (typeChecker, decoratedProps, newMembers, de
16635
16900
  }
16636
16901
  return [];
16637
16902
  });
16638
- const serializers = decoratedProps.filter(ts.isMethodDeclaration).flatMap((method) => parseSerializeDecorator(typeChecker, method, decoratorName, props));
16903
+ const serializers = [...decoratedProps.filter(ts.isMethodDeclaration).flatMap((method) => parseSerializeDecorator(typeChecker, method, decoratorName, props)), ...generated];
16639
16904
  if (serializers.length > 0) {
16640
16905
  if (translateType === "PropSerialize") newMembers.push(createStaticGetter("serializers", convertValueToLiteral(serializers)));
16641
16906
  else newMembers.push(createStaticGetter("deserializers", convertValueToLiteral(serializers)));
@@ -16735,6 +17000,8 @@ const parseWatchDecorator = (typeChecker, method, decoratorName) => {
16735
17000
  * @returns a TypeScript transformer factory which can be passed to
16736
17001
  * TypeScript to transform source code during the compilation process
16737
17002
  */
17003
+ /** Source files with a `@Prop({ serialize: 'json' })`, which need a `Build` import. */
17004
+ const filesWithJsonProps = /* @__PURE__ */ new WeakSet();
16738
17005
  const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program, includeClassExpressions = false) => {
16739
17006
  return (transformCtx) => {
16740
17007
  let sourceFile;
@@ -16744,7 +17011,8 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program, in
16744
17011
  };
16745
17012
  return (tsSourceFile) => {
16746
17013
  sourceFile = tsSourceFile;
16747
- return ts.visitEachChild(tsSourceFile, visit, transformCtx);
17014
+ const updated = ts.visitEachChild(tsSourceFile, visit, transformCtx);
17015
+ return filesWithJsonProps.has(tsSourceFile) ? addBuildImport(updated) : updated;
16748
17016
  };
16749
17017
  };
16750
17018
  };
@@ -16782,8 +17050,20 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
16782
17050
  const filteredMethodsAndFields = removeStencilMethodDecorators(Array.from(classMembers), diagnostics, importAliasMap);
16783
17051
  if (componentDecorator && ts.isClassDeclaration(classNode)) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
16784
17052
  if (decoratedMembers.length > 0) {
16785
- const serializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("PropSerialize"), "PropSerialize", importAliasMap.get("Prop"));
16786
- const deserializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("AttrDeserialize"), "AttrDeserialize", importAliasMap.get("Prop"));
17053
+ const handWritten = serializeDecoratorsToStatic(typeChecker, decoratedMembers, [], importAliasMap.get("PropSerialize"), "PropSerialize", importAliasMap.get("Prop")).concat(serializeDecoratorsToStatic(typeChecker, decoratedMembers, [], importAliasMap.get("AttrDeserialize"), "AttrDeserialize", importAliasMap.get("Prop")));
17054
+ const jsonProps = getJsonSerializedProps(diagnostics, typeChecker, decoratedMembers, importAliasMap.get("Prop"), handWritten);
17055
+ if (jsonProps.length > 0) {
17056
+ filteredMethodsAndFields.push(...createJsonSerializerMethods());
17057
+ filesWithJsonProps.add(sourceFile);
17058
+ }
17059
+ const serializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("PropSerialize"), "PropSerialize", importAliasMap.get("Prop"), jsonProps.map((propName) => ({
17060
+ propName,
17061
+ methodName: JSON_SERIALIZE_METHOD
17062
+ })));
17063
+ const deserializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("AttrDeserialize"), "AttrDeserialize", importAliasMap.get("Prop"), jsonProps.map((propName) => ({
17064
+ propName,
17065
+ methodName: JSON_DESERIALIZE_METHOD
17066
+ })));
16787
17067
  propDecoratorsToStatic(config, diagnostics, decoratedMembers, typeChecker, program, filteredMethodsAndFields, importAliasMap.get("Prop"), serializers, deserializers);
16788
17068
  stateDecoratorsToStatic(decoratedMembers, filteredMethodsAndFields, typeChecker, importAliasMap.get("State"));
16789
17069
  eventDecoratorsToStatic(config, diagnostics, decoratedMembers, typeChecker, program, filteredMethodsAndFields, importAliasMap.get("Event"));
@@ -19030,7 +19310,7 @@ const performAutomaticKeyInsertion = (transformCtx) => {
19030
19310
  * @returns the result of handling the node
19031
19311
  */
19032
19312
  function findRenderMethodVisitor(node) {
19033
- if (ts.isMethodDeclaration(node) && node.name.getText() === "render" && numReturnStatements(node) === 1) {
19313
+ if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === "render" && numReturnStatements(node) === 1) {
19034
19314
  resetKeyCounter();
19035
19315
  return ts.visitEachChild(node, jsxElementVisitor, transformCtx);
19036
19316
  } else return ts.visitEachChild(node, findRenderMethodVisitor, transformCtx);
@@ -20392,6 +20672,11 @@ const getGeneratedExports = (config, buildCtx, loaderBundle, standalone, ssr, ty
20392
20672
  import: `${outDir}/index.js`,
20393
20673
  require: ssr.cjs ? `${outDir}/index.cjs` : void 0
20394
20674
  };
20675
+ generated["./ssr-prop"] = {
20676
+ types: `${outDir}/ssr-prop.d.ts`,
20677
+ import: `${outDir}/ssr-prop.js`,
20678
+ require: ssr.cjs ? `${outDir}/ssr-prop.cjs` : void 0
20679
+ };
20395
20680
  }
20396
20681
  if (loaderBundle || standalone) {
20397
20682
  const globalStyles = config.outputTargets.filter(isOutputTargetGlobalStyle);
@@ -2536,6 +2536,16 @@ interface SsrDocumentOptions {
2536
2536
  * Sets `document.referrer`
2537
2537
  */
2538
2538
  referrer?: string;
2539
+ /**
2540
+ * Render into one long-lived mock window, reset between renders, instead of creating a new one
2541
+ * for every call. Skips evaluating the whole SSR platform (runtime and every component)
2542
+ * on each render: most of the cost of rendering a small fragment, and a good part of a whole page.
2543
+ *
2544
+ * Applies to HTML string input (not a `Document`). One window per distinct `serializeShadowRoot` value,
2545
+ * and renders sharing a window run one at a time.
2546
+ * Defaults to `false`, except in the `ssr-wasm` output target, where it defaults to `true`.
2547
+ */
2548
+ reuseWindow?: boolean;
2539
2549
  /**
2540
2550
  * Removes every `<script>` element found in the `document`. Defaults to `false`.
2541
2551
  */
@@ -2672,6 +2682,12 @@ interface SsrFactoryOptions extends SerializeDocumentOptions {
2672
2682
  serializeToHtml: boolean;
2673
2683
  destroyWindow: boolean;
2674
2684
  destroyDocument: boolean;
2685
+ /**
2686
+ * A canonical key for `serializeShadowRoot`, set by the renderer. Renders with the same key
2687
+ * render every component the same way, so they can share an SSR platform.
2688
+ * @internal
2689
+ */
2690
+ serializeShadowRootKey?: string;
2675
2691
  }
2676
2692
  /**
2677
2693
  * Backwards compat for v4
@@ -191,6 +191,16 @@ interface PropOptions {
191
191
  * In this case you can set the `reflect` option to `true`, since it defaults to `false`:
192
192
  */
193
193
  reflect?: boolean;
194
+ /**
195
+ * Carry the prop's value from a server render to the browser in its attribute, as JSON:
196
+ * shorthand for a `@PropSerialize()` that writes `JSON.stringify(value)` on the server and an
197
+ * `@AttrDeserialize()` that reads it back with `JSON.parse()`. Attribute values that aren't
198
+ * valid JSON leave the prop as it is (with a warning in dev builds).
199
+ *
200
+ * For other formats (a `Map`, a `Date`...), write the `@PropSerialize()` /
201
+ * `@AttrDeserialize()` pair yourself.
202
+ */
203
+ serialize?: 'json';
194
204
  }
195
205
  interface MethodDecorator {
196
206
  (opts?: MethodOptions): CustomMethodDecorator<any>;
@@ -1,4 +1,4 @@
1
- import { ar as RafCallback, cr as TagTransformer, lr as UserBuildConditionals, n as ChildType, nr as ErrorHandler, p as HostElement, rr as FunctionalComponent, sr as ResolutionHandler, ur as VNode, v as PropsType, y as RuntimeRef } from "./index-B0NfYeIA.mjs";
1
+ import { ar as RafCallback, cr as TagTransformer, lr as UserBuildConditionals, n as ChildType, nr as ErrorHandler, p as HostElement, rr as FunctionalComponent, sr as ResolutionHandler, ur as VNode, v as PropsType, y as RuntimeRef } from "./index-DG4wtfhx.mjs";
2
2
  //#region src/client/client-build.d.ts
3
3
  /**
4
4
  * `isDev` / `isTesting` are getters, not copies: the transpile path (e.g. `@stencil/unplugin`)
@@ -2583,6 +2583,16 @@ interface SsrDocumentOptions {
2583
2583
  * Sets `document.referrer`
2584
2584
  */
2585
2585
  referrer?: string;
2586
+ /**
2587
+ * Render into one long-lived mock window, reset between renders, instead of creating a new one
2588
+ * for every call. Skips evaluating the whole SSR platform (runtime and every component)
2589
+ * on each render: most of the cost of rendering a small fragment, and a good part of a whole page.
2590
+ *
2591
+ * Applies to HTML string input (not a `Document`). One window per distinct `serializeShadowRoot` value,
2592
+ * and renders sharing a window run one at a time.
2593
+ * Defaults to `false`, except in the `ssr-wasm` output target, where it defaults to `true`.
2594
+ */
2595
+ reuseWindow?: boolean;
2586
2596
  /**
2587
2597
  * Removes every `<script>` element found in the `document`. Defaults to `false`.
2588
2598
  */
@@ -2719,6 +2729,12 @@ interface SsrFactoryOptions extends SerializeDocumentOptions {
2719
2729
  serializeToHtml: boolean;
2720
2730
  destroyWindow: boolean;
2721
2731
  destroyDocument: boolean;
2732
+ /**
2733
+ * A canonical key for `serializeShadowRoot`, set by the renderer. Renders with the same key
2734
+ * render every component the same way, so they can share an SSR platform.
2735
+ * @internal
2736
+ */
2737
+ serializeShadowRootKey?: string;
2722
2738
  }
2723
2739
  /**
2724
2740
  * Backwards compat for v4