@stencil/core 5.0.0-beta.0 → 5.0.0-beta.10

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 { S as HYDRATED_CSS } from "./client-BRu0GtRn.mjs";
2
+ import { S as HYDRATED_CSS } from "./client-Db2rdxUM.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-DAdGTrys.mjs";
5
5
  import { $ as catchError, A as isOutputTargetDocsVscode, B as relativeImport, C as isOutputTargetDistLazy, D as isOutputTargetDocsCustomElementsManifest, E as isOutputTargetDocsCustom, F as isOutputTargetStandalone, G as normalizeFsPathQuery, H as join$2, I as isOutputTargetStats, J as resolve$2, K as normalizePath, L as isOutputTargetTypes, M as isOutputTargetLoaderBundle, N as isOutputTargetSsr, O as isOutputTargetDocsJson, P as isOutputTargetSsrWasm, Q as buildWarn, R as isOutputTargetWww, S as isOutputTargetCustom, T as isOutputTargetDocsAgentSkill, W as normalizeFsPath, X as buildError, Z as buildJsonFileError, a as hasDependency, b as isOutputTargetCollection, d as parsePackageJson, et as hasError, f as readOnlyArrayHasStringMember, g as getComponentsDtsSrcFilePath, h as filterExcludedComponents, i as getTextDocs, j as isOutputTargetGlobalStyle, k as isOutputTargetDocsReadme, l as isTsFile, m as filterActiveTargets, n as createJsVarName, o as isDtsFile, p as readPackageJson, q as relative$1, r as generatePreamble, rt as isGlob, t as addDocBlock, tt as hasWarning, u as isTsxFile, v as getComponentsFromModules, w as isOutputTargetDocs, x as isOutputTargetCopy, y as isOutputTargetAssets, z as isValidConfigOutputTarget } from "./util-IKfWWLJo.mjs";
6
- import { i as CustomElementsExportBehaviorOptions, o as buildEvents, r as createNodeLogger, t as createNodeSys } from "./node-75gQKkFz.mjs";
6
+ import { i as CustomElementsExportBehaviorOptions, o as buildEvents, r as createNodeLogger, t as createNodeSys } from "./node-BKtLn2R9.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";
@@ -17,6 +17,7 @@ import postcssSelectorParser from "postcss-selector-parser";
17
17
  import MagicString from "magic-string";
18
18
  import { rolldown } from "rolldown";
19
19
  import resolve$1 from "resolve";
20
+ import { minifySync } from "rolldown/utils";
20
21
  import { minify } from "terser";
21
22
  import { SelectorType, parse, stringify } from "css-what";
22
23
  import { execFile } from "node:child_process";
@@ -72,12 +73,13 @@ const restoreSafeSelector = (placeholders, content) => {
72
73
  const _polyfillHost = "-shadowcsshost";
73
74
  const _polyfillSlotted = "-shadowcssslotted";
74
75
  const _polyfillHostContext = "-shadowcsscontext";
76
+ const _parenSuffix = ")(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)";
75
77
  let _cssColonHostRe;
76
78
  let _cssColonHostContextRe;
77
79
  let _cssColonSlottedRe;
78
- const getCssColonHostRe = () => _cssColonHostRe ??= /* @__PURE__ */ new RegExp("(-shadowcsshost)(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)", "gim");
79
- const getCssColonHostContextRe = () => _cssColonHostContextRe ??= /* @__PURE__ */ new RegExp("(-shadowcsscontext)(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)", "gim");
80
- const getCssColonSlottedRe = () => _cssColonSlottedRe ??= /* @__PURE__ */ new RegExp("(-shadowcssslotted)(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)", "gim");
80
+ const getCssColonHostRe = () => _cssColonHostRe ??= new RegExp("(-shadowcsshost" + _parenSuffix, "gim");
81
+ const getCssColonHostContextRe = () => _cssColonHostContextRe ??= new RegExp("(-shadowcsscontext" + _parenSuffix, "gim");
82
+ const getCssColonSlottedRe = () => _cssColonSlottedRe ??= new RegExp("(-shadowcssslotted" + _parenSuffix, "gim");
81
83
  const _polyfillHostNoCombinator = "-shadowcsshost-no-combinator";
82
84
  const _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
83
85
  const _shadowDOMSelectorsRe = [/::shadow/g, /::content/g];
@@ -340,12 +342,13 @@ const scopeSelector = (selector, scopeSelectorText, hostSelector, slotSelector)
340
342
  else return shallowPart.trim();
341
343
  }).join(", ");
342
344
  };
345
+ const isScopableAtRule = (selector) => selector.startsWith("@media") || selector.startsWith("@supports") || selector.startsWith("@page") || selector.startsWith("@document") || selector.startsWith("@layer");
343
346
  const scopeSelectors = (cssText, scopeSelectorText, hostSelector, slotSelector, commentOriginalSelector) => {
344
347
  return processRules(cssText, (rule) => {
345
348
  let selector = rule.selector;
346
349
  let content = rule.content;
347
350
  if (rule.selector[0] !== "@") selector = scopeSelector(rule.selector, scopeSelectorText, hostSelector, slotSelector);
348
- else if (rule.selector.startsWith("@media") || rule.selector.startsWith("@supports") || rule.selector.startsWith("@page") || rule.selector.startsWith("@document")) content = scopeSelectors(rule.content, scopeSelectorText, hostSelector, slotSelector, commentOriginalSelector);
351
+ else if (isScopableAtRule(rule.selector)) content = scopeSelectors(rule.content, scopeSelectorText, hostSelector, slotSelector, commentOriginalSelector);
349
352
  return {
350
353
  selector: selector.replace(/\s{2,}/g, " ").trim(),
351
354
  content
@@ -437,14 +440,12 @@ const scopeCss = (cssText, scopeId, commentOriginalSelector) => {
437
440
  rule.selector = placeholder + rule.selector;
438
441
  return rule;
439
442
  };
440
- cssText = processRules(cssText, (rule) => {
443
+ const commentSelectors = (input) => processRules(input, (rule) => {
441
444
  if (rule.selector[0] !== "@") return processCommentedSelector(rule);
442
- else if (rule.selector.startsWith("@media") || rule.selector.startsWith("@supports") || rule.selector.startsWith("@page") || rule.selector.startsWith("@document")) {
443
- rule.content = processRules(rule.content, processCommentedSelector);
444
- return rule;
445
- }
445
+ if (isScopableAtRule(rule.selector)) rule.content = commentSelectors(rule.content);
446
446
  return rule;
447
447
  });
448
+ cssText = commentSelectors(cssText);
448
449
  }
449
450
  const scoped = scopeCssText(cssText, scopeId, hostScopeId, slotScopeId, commentOriginalSelector);
450
451
  cssText = [scoped.cssText, ...commentsWithHash].join("\n");
@@ -460,9 +461,9 @@ const scopeCss = (cssText, scopeId, commentOriginalSelector) => {
460
461
  };
461
462
  //#endregion
462
463
  //#region src/version.ts
463
- const version = "5.0.0-beta.0";
464
- const buildId = "1787699045";
465
- const vermoji = "🐥";
464
+ const version = "5.0.0-beta.10";
465
+ const buildId = "1789054824";
466
+ const vermoji = "🚘";
466
467
  /**
467
468
  * Get the installed version of a tool/dependency.
468
469
  * Handles packages with exports maps that point to subdirectories.
@@ -1020,6 +1021,7 @@ const REGISTER_HOST = "__stencil_registerHost";
1020
1021
  const H = "__stencil_h";
1021
1022
  const TRANSFORM_TAG = "__stencil_transformTag";
1022
1023
  const GET_REGISTRY = "__stencil_getRegistry";
1024
+ const INJECT_SIDE_EFFECT_STYLE = "__stencil_injectSideEffectStyle";
1023
1025
  const RUNTIME_APIS = {
1024
1026
  createEvent: `createEvent as ${CREATE_EVENT}`,
1025
1027
  defineCustomElement: `defineCustomElement as ${DEFINE_CUSTOM_ELEMENT}`,
@@ -2421,7 +2423,7 @@ function addTagTransformToCssString(cssCode, tagNames) {
2421
2423
  rule.selectors = rule.selectors.map((sel) => {
2422
2424
  const parsedSelector = postcssSelectorParser().astSync(sel);
2423
2425
  parsedSelector.walkTags((tag) => {
2424
- if (tagNames.includes(tag.value)) tag.value = "${__stencil_transformTag(\"" + tag.value + "\")}";
2426
+ if (tagNames.includes(tag.value)) tag.value = "${" + TRANSFORM_TAG + "(\"" + tag.value + "\")}";
2425
2427
  });
2426
2428
  return parsedSelector.toString();
2427
2429
  });
@@ -3354,9 +3356,9 @@ const runPluginTransformsEsmImports = async (config, compilerCtx, buildCtx, code
3354
3356
  return transformResults;
3355
3357
  };
3356
3358
  //#endregion
3357
- //#region src/compiler/style/optimize-css.ts
3359
+ //#region src/compiler/style/optimize-style-css.ts
3358
3360
  const getCssToolVersions = () => `autoprefixer@${getToolVersion("autoprefixer")}_postcss@${getToolVersion("postcss")}`;
3359
- const optimizeCss$1 = async (config, compilerCtx, diagnostics, styleText, filePath) => {
3361
+ const optimizeStyleCss = async (config, compilerCtx, diagnostics, styleText, filePath) => {
3360
3362
  if (typeof styleText !== "string" || !styleText.length) return styleText;
3361
3363
  if ((config.autoprefixCss === false || config.autoprefixCss === null) && !config.minifyCss) return styleText;
3362
3364
  if (typeof filePath === "string") filePath = normalizePath(filePath);
@@ -3441,7 +3443,7 @@ const collectAndBuildComponentGlobalStyles = async (config, compilerCtx, buildCt
3441
3443
  if (!result) continue;
3442
3444
  const cssCode = typeof result === "string" ? result : result.code;
3443
3445
  if (!cssCode) continue;
3444
- const optimized = await optimizeCss$1(config, compilerCtx, buildCtx.diagnostics, cssCode, path);
3446
+ const optimized = await optimizeStyleCss(config, compilerCtx, buildCtx.diagnostics, cssCode, path);
3445
3447
  compilerCtx.globalStyleCache.set(path, optimized);
3446
3448
  parts.push(optimized);
3447
3449
  }
@@ -3523,7 +3525,7 @@ const buildGlobalStyleFromInput = async (config, compilerCtx, buildCtx, inputPat
3523
3525
  }
3524
3526
  if (hasStencilGlobalsImport(cssCode)) cssCode = await resolveStencilGlobalsImport(cssCode, config, compilerCtx, buildCtx, normalizedPath);
3525
3527
  if (hasStencilHydrateImport(cssCode)) cssCode = resolveStencilHydrateImport(cssCode, config, buildCtx);
3526
- const optimizedCss = await optimizeCss$1(config, compilerCtx, buildCtx.diagnostics, cssCode, normalizedPath);
3528
+ const optimizedCss = await optimizeStyleCss(config, compilerCtx, buildCtx.diagnostics, cssCode, normalizedPath);
3527
3529
  compilerCtx.globalStyleCache.set(normalizedPath, optimizedCss);
3528
3530
  if (Array.isArray(dependencies)) {
3529
3531
  const cssModuleImports = compilerCtx.cssModuleImports.get(normalizedPath) || [];
@@ -3795,9 +3797,22 @@ const appendGlobalStyles = async (config, compilerCtx, buildCtx, s, platform) =>
3795
3797
  * @param s a `MagicString` to append the generated constant onto
3796
3798
  */
3797
3799
  const appendBuildConditionals = (config, buildConditionals, s) => {
3798
- const buildData = Object.keys(buildConditionals).sort().map((key) => key + ": " + JSON.stringify(buildConditionals[key])).join(", ");
3800
+ const buildData = getSortedBuildConditionalEntries(buildConditionals).map(([key, value]) => key + ": " + JSON.stringify(value)).join(", ");
3799
3801
  s.append(`export const BUILD = /* ${config.fsNamespace} */ { ${buildData} };\n`);
3800
3802
  };
3803
+ /**
3804
+ * Builds a `<flag> -> literal-value-as-source-text` map for every build conditional, for use by
3805
+ * {@link buildConditionalsPlugin} to replace `BUILD.<flag>` reads with their literal values.
3806
+ *
3807
+ * @param buildConditionals the build conditionals for this build
3808
+ * @returns a flag name > literal source text map
3809
+ */
3810
+ const getBuildConditionalsLiterals = (buildConditionals) => {
3811
+ const literals = /* @__PURE__ */ new Map();
3812
+ for (const [key, value] of getSortedBuildConditionalEntries(buildConditionals)) literals.set(key, JSON.stringify(value));
3813
+ return literals;
3814
+ };
3815
+ const getSortedBuildConditionalEntries = (buildConditionals) => Object.keys(buildConditionals).sort().map((key) => [key, buildConditionals[key]]);
3801
3816
  const appendEnv = (config, s) => {
3802
3817
  s.append(`export const Env = /* ${config.fsNamespace} */ ${JSON.stringify(config.env)};\n`);
3803
3818
  };
@@ -3912,7 +3927,6 @@ const coreResolvePlugin = (config, compilerCtx, platform, externalRuntime, lazyL
3912
3927
  const hydratedFlag = config.hydratedFlag;
3913
3928
  const hydratedFlagHead = hydratedFlag ? getHydratedFlagHead(hydratedFlag) : null;
3914
3929
  const hydratedReplacements = hydratedFlag && hydratedFlagHead !== "{visibility:hidden}.hydrated{visibility:inherit}" ? buildHydratedReplacements(hydratedFlag, hydratedFlagHead) : null;
3915
- const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3916
3930
  return {
3917
3931
  name: "coreResolvePlugin",
3918
3932
  resolveId: {
@@ -3952,7 +3966,7 @@ const coreResolvePlugin = (config, compilerCtx, platform, externalRuntime, lazyL
3952
3966
  }
3953
3967
  },
3954
3968
  load: {
3955
- filter: { id: new RegExp(`^(${escapeRegex(internalClient)}|${escapeRegex(internalSsr)})(\\?.*)?$`) },
3969
+ filter: { id: getStencilInternalModuleFilter(internalClient, internalSsr) },
3956
3970
  async handler(filePath) {
3957
3971
  if (filePath && !filePath.startsWith("\0")) {
3958
3972
  filePath = normalizeFsPath(filePath);
@@ -3984,6 +3998,19 @@ export const Build = {
3984
3998
  }
3985
3999
  };
3986
4000
  };
4001
+ /**
4002
+ * Builds a filter regex matching only Stencil's own resolved internal runtime module(s),
4003
+ * tolerant of query-string suffixes (e.g. `?app-data=conditional` for lazy builds). Shared by
4004
+ * any plugin that needs to scope its work to Stencil's own runtime code, rather than the rest
4005
+ * of a downstream app's bundle.
4006
+ *
4007
+ * @param moduleIds absolute paths to Stencil's resolved internal runtime module(s)
4008
+ * @returns a regex suitable for a rolldown hook's `id` filter
4009
+ */
4010
+ const getStencilInternalModuleFilter = (...moduleIds) => {
4011
+ const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4012
+ return new RegExp(`^(${moduleIds.map(escapeRegex).join("|")})(\\?.*)?$`);
4013
+ };
3987
4014
  const getStencilInternalModule = (config, compilerExe, internalModule) => {
3988
4015
  if (isRemoteUrl(compilerExe)) return normalizePath(config.sys.getLocalModulePath({
3989
4016
  rootDir: config.rootDir,
@@ -4016,6 +4043,53 @@ const buildHydratedReplacements = (hydratedFlag, hydratedFlagHead) => {
4016
4043
  return replacements;
4017
4044
  };
4018
4045
  //#endregion
4046
+ //#region src/compiler/bundle/build-conditionals-plugin.ts
4047
+ const BUILD_FLAG_RE = /\bBUILD(?:\$\d+)?\.([A-Za-z_$][\w$]*)\b/g;
4048
+ /**
4049
+ * Scoped by `id` to Stencil's own resolved internal runtime module(s) only
4050
+ * and only when the `jsMinifier` = `oxc`.
4051
+ *
4052
+ * Replaces `BUILD.<flag>` reads with their literal values, so a minifier's basic literal-boolean
4053
+ * folding (e.g. `false && x` -> nothing) can eliminate the resulting dead branches.
4054
+ * Oxc cannot dead-code-eliminate using `BUILD.<flag>` reads directly.
4055
+ *
4056
+ * @param config the Stencil configuration for the project
4057
+ * @param buildConditionals the build conditionals for this build
4058
+ * @returns a rolldown plugin, or null if this build doesn't need it
4059
+ */
4060
+ const buildConditionalsPlugin = (config, buildConditionals) => {
4061
+ if (config.jsMinifier !== "oxc" || !buildConditionals) return null;
4062
+ const literals = getBuildConditionalsLiterals(buildConditionals);
4063
+ if (literals.size === 0) return null;
4064
+ const compilerExe = config.sys.getCompilerExecutingPath();
4065
+ const internalClient = getStencilInternalModule(config, compilerExe, "client/runtime.js");
4066
+ const internalSsr = getStencilInternalModule(config, compilerExe, "server/index.mjs");
4067
+ return {
4068
+ name: "stencil-build-conditionals",
4069
+ transform: {
4070
+ filter: {
4071
+ id: getStencilInternalModuleFilter(internalClient, internalSsr),
4072
+ code: /\bBUILD(?:\$\d+)?\.\w/
4073
+ },
4074
+ handler(code) {
4075
+ const s = new MagicString(code);
4076
+ let didReplace = false;
4077
+ for (const match of code.matchAll(BUILD_FLAG_RE)) {
4078
+ const literal = literals.get(match[1]);
4079
+ if (literal === void 0) continue;
4080
+ s.overwrite(match.index, match.index + match[0].length, literal);
4081
+ didReplace = true;
4082
+ }
4083
+ if (!didReplace) return null;
4084
+ return {
4085
+ code: s.toString(),
4086
+ map: s.generateMap({ hires: true })
4087
+ };
4088
+ }
4089
+ }
4090
+ };
4091
+ };
4092
+ //#endregion
4019
4093
  //#region src/compiler/bundle/constants.ts
4020
4094
  const DEV_MODULE_DIR = `~dev-module`;
4021
4095
  //#endregion
@@ -4250,9 +4324,10 @@ const extTransformsPlugin = (config, compilerCtx, buildCtx) => {
4250
4324
  if (typeof code !== "string") compilerCtx.cssTransformCache.set(id, null);
4251
4325
  else {
4252
4326
  const pluginTransforms = await runPluginTransformsEsmImports(config, compilerCtx, buildCtx, code, filePath);
4327
+ const cssInput = data.tag ? pluginTransforms.code : inlineRelativeCssUrlAssets(pluginTransforms.code, filePath);
4253
4328
  const cssTransformResults = await compilerCtx.worker.transformCssToEsm({
4254
4329
  file: pluginTransforms.id,
4255
- input: pluginTransforms.code,
4330
+ input: cssInput,
4256
4331
  tag: data.tag,
4257
4332
  tags: buildCtx.components.map((c) => c.tagName),
4258
4333
  addTagTransformers: !!buildCtx.config.compat.additionalTagTransformers,
@@ -4340,13 +4415,46 @@ const extTransformsPlugin = (config, compilerCtx, buildCtx) => {
4340
4415
  return {
4341
4416
  code: cacheEntry.cssTransformOutput.output,
4342
4417
  map: cacheEntry.cssTransformOutput.map,
4343
- moduleSideEffects: false
4418
+ moduleSideEffects: cacheEntry.cssTransformOutput.moduleSideEffects ?? false
4344
4419
  };
4345
4420
  }
4346
4421
  return null;
4347
4422
  }
4348
4423
  };
4349
4424
  };
4425
+ /**
4426
+ * 3rd-party stylesheets with relative `url(./font.ttf)` (font-face `src`, a background-image, ...)
4427
+ * have nowhere to resolve that path once this CSS is self-injected as a CSSStyleSheet:
4428
+ * there's no bundler output location for it to be relative *to*.
4429
+ * Inlining the referenced file as a `data:` URI sidesteps needing one - no separate asset
4430
+ * to serve, works the same regardless of how/where the final bundle is deployed.
4431
+ */
4432
+ const CSS_URL_RE = /url\(\s*(['"]?)([^'"()]+)\1\s*\)/g;
4433
+ const CSS_URL_ASSET_MIME_TYPES = {
4434
+ ttf: "font/ttf",
4435
+ otf: "font/otf",
4436
+ woff: "font/woff",
4437
+ woff2: "font/woff2",
4438
+ eot: "application/vnd.ms-fontobject",
4439
+ png: "image/png",
4440
+ jpg: "image/jpeg",
4441
+ jpeg: "image/jpeg",
4442
+ gif: "image/gif",
4443
+ svg: "image/svg+xml"
4444
+ };
4445
+ const inlineRelativeCssUrlAssets = (cssText, cssFilePath) => cssText.replace(CSS_URL_RE, (original, _quote, url) => {
4446
+ if (/^(data:|[a-z][a-z0-9+.-]*:|\/\/|\/)/i.test(url)) return original;
4447
+ const cleanUrl = url.split(/[?#]/)[0];
4448
+ const ext = cleanUrl.split(".").pop()?.toLowerCase();
4449
+ const mimeType = ext && CSS_URL_ASSET_MIME_TYPES[ext];
4450
+ if (!mimeType) return original;
4451
+ try {
4452
+ const assetPath = resolve(dirname(cssFilePath), cleanUrl);
4453
+ return `url("data:${mimeType};base64,${readFileSync(assetPath).toString("base64")}")`;
4454
+ } catch {
4455
+ return original;
4456
+ }
4457
+ });
4350
4458
  //#endregion
4351
4459
  //#region src/compiler/bundle/file-load-plugin.ts
4352
4460
  const RESOLVE_EXTENSIONS = [
@@ -4482,11 +4590,13 @@ const pluginHelper = (config, builtCtx, platform) => {
4482
4590
  handler(importee, importer) {
4483
4591
  if (importee.endsWith("/")) importee = importee.slice(0, -1);
4484
4592
  if (builtIns.has(importee)) {
4593
+ const alias = config.nodeResolve?.alias;
4594
+ if (alias?.[importee] ?? alias?.[`${importee}$`]) return null;
4485
4595
  let fromMsg = "";
4486
4596
  if (importer) fromMsg = ` from ${relative$1(config.rootDir, importer)}`;
4487
4597
  const diagnostic = buildError(builtCtx.diagnostics);
4488
4598
  diagnostic.header = `Node Polyfills Required`;
4489
- diagnostic.messageText = `For the import "${importee}" to be bundled${fromMsg}, ensure the "rolldown-plugin-node-polyfills" plugin is installed and added to the stencil config plugins (${platform}). Please see the bundling docs for more information.
4599
+ diagnostic.messageText = `For the import "${importee}" to be bundled${fromMsg}, ensure the "@rolldown/plugin-node-polyfills" plugin is installed and added to the stencil config plugins (${platform}). Please see the bundling docs for more information.
4490
4600
  Further information: https://stenciljs.com/docs/module-bundling`;
4491
4601
  }
4492
4602
  return null;
@@ -4713,7 +4823,59 @@ const userIndexPlugin = (config, compilerCtx) => {
4713
4823
  };
4714
4824
  };
4715
4825
  //#endregion
4716
- //#region src/compiler/optimize/minify-js.ts
4826
+ //#region src/compiler/optimize/minify-js-oxc.ts
4827
+ /**
4828
+ * Performs the minification of JavaScript source using oxc
4829
+ * @param input the JavaScript source to minify
4830
+ * @param opts the options used by the minifier
4831
+ * @returns the resulting minified JavaScript
4832
+ */
4833
+ const minifyJsOxc = async (input, opts) => {
4834
+ const results = {
4835
+ output: input,
4836
+ sourceMap: null,
4837
+ diagnostics: []
4838
+ };
4839
+ try {
4840
+ const minifyResult = minifySync("module.js", input, opts);
4841
+ if (minifyResult.errors.length > 0) {
4842
+ loadMinifyJsOxcDiagnostics(results.diagnostics, minifyResult.errors);
4843
+ return results;
4844
+ }
4845
+ results.output = minifyResult.code;
4846
+ results.sourceMap = minifyResult.map ? {
4847
+ file: minifyResult.map.file ?? "module.js",
4848
+ mappings: minifyResult.map.mappings,
4849
+ names: minifyResult.map.names,
4850
+ sourceRoot: minifyResult.map.sourceRoot,
4851
+ sources: minifyResult.map.sources,
4852
+ sourcesContent: minifyResult.map.sourcesContent,
4853
+ version: minifyResult.map.version
4854
+ } : null;
4855
+ } catch (e) {
4856
+ if (e instanceof Error) console.log(e.stack);
4857
+ loadMinifyJsOxcDiagnostics(results.diagnostics, [{
4858
+ message: String(e),
4859
+ codeframe: null
4860
+ }]);
4861
+ }
4862
+ return results;
4863
+ };
4864
+ const loadMinifyJsOxcDiagnostics = (diagnostics, errors) => {
4865
+ for (const error of errors) diagnostics.push({
4866
+ level: "error",
4867
+ type: "build",
4868
+ language: "javascript",
4869
+ header: "Minify JS (oxc)",
4870
+ code: "",
4871
+ messageText: error.codeframe ?? error.message,
4872
+ absFilePath: void 0,
4873
+ relFilePath: void 0,
4874
+ lines: []
4875
+ });
4876
+ };
4877
+ //#endregion
4878
+ //#region src/compiler/optimize/minify-js-terser.ts
4717
4879
  /**
4718
4880
  * Performs the minification of JavaScript source
4719
4881
  * @param input the JavaScript source to minify
@@ -4732,14 +4894,6 @@ const minifyJs = async (input, opts) => {
4732
4894
  const mangleProperties = mangle.properties;
4733
4895
  if (mangleProperties && mangleProperties.regex) mangleProperties.regex = new RegExp(mangleProperties.regex);
4734
4896
  }
4735
- if (opts.sourceMap)
4736
- /**
4737
- * sourceMap, when used in conjunction with compress, can lead to sourcemaps that don't in every browser. despite
4738
- * there being a sourcemap spec, each browser has it's own tricks for trying to get sourcemaps to properly map
4739
- * minified JS back to its original form. for the most consistent results across all browsers, explicitly disable
4740
- * compress.
4741
- */
4742
- opts.compress = void 0;
4743
4897
  }
4744
4898
  try {
4745
4899
  const minifyResults = await minify(input, opts);
@@ -4845,7 +4999,8 @@ const optimizeModule = async (config, compilerCtx, opts) => {
4845
4999
  sourceMap: opts.sourceMap
4846
5000
  };
4847
5001
  const isDebug = config.logLevel === "debug";
4848
- const cacheKey = await compilerCtx.cache.createKey("optimizeModule", getToolVersion("terser"), opts, isDebug);
5002
+ const jsMinifier = config.jsMinifier;
5003
+ const cacheKey = await compilerCtx.cache.createKey("optimizeModule", jsMinifier, getToolVersion(jsMinifier === "oxc" ? "rolldown" : "terser"), opts, isDebug);
4849
5004
  const cachedContent = await compilerCtx.cache.get(cacheKey);
4850
5005
  if (cachedContent != null) {
4851
5006
  const cachedMap = await compilerCtx.cache.get(cacheKey + "Map");
@@ -4855,8 +5010,26 @@ const optimizeModule = async (config, compilerCtx, opts) => {
4855
5010
  sourceMap: cachedMap ? JSON.parse(cachedMap) : null
4856
5011
  };
4857
5012
  }
4858
- const minifyOpts = getTerserOptions(config, opts.sourceTarget, isDebug);
4859
5013
  const code = opts.input;
5014
+ const results = jsMinifier === "oxc" ? await minifyJsOxc(code, getOxcMinifyOptions(config, opts, isDebug)) : await compilerCtx.worker.prepareModule(code, getTerserMinifyOptions(config, opts, isDebug));
5015
+ if (results != null && typeof results.output === "string" && results.diagnostics.length === 0 && compilerCtx != null) {
5016
+ if (opts.isCore) results.output = results.output.replace(/disconnectedCallback\(\)\{\},/g, "");
5017
+ await compilerCtx.cache.put(cacheKey, results.output);
5018
+ if (results.sourceMap) await compilerCtx.cache.put(cacheKey + "Map", JSON.stringify(results.sourceMap));
5019
+ }
5020
+ return results;
5021
+ };
5022
+ /**
5023
+ * Builds the terser options for a specific module being optimized, layering the module's
5024
+ * `isCore`/source map needs on top of the baseline options from {@link getTerserOptions}.
5025
+ *
5026
+ * @param config the Stencil configuration file that was provided as a part of the build step
5027
+ * @param opts the options for the module being optimized
5028
+ * @param isDebug if true, set the necessary flags to produce readable, debuggable output
5029
+ * @returns the minification options to hand to terser
5030
+ */
5031
+ const getTerserMinifyOptions = (config, opts, isDebug) => {
5032
+ const minifyOpts = getTerserOptions(config, opts.sourceTarget, isDebug);
4860
5033
  if (config.sourceMap) minifyOpts.sourceMap = { content: opts.sourceMap != null ? {
4861
5034
  ...opts.sourceMap,
4862
5035
  version: 3
@@ -4878,13 +5051,7 @@ const optimizeModule = async (config, compilerCtx, opts) => {
4878
5051
  compressOpts.unsafe = true;
4879
5052
  compressOpts.unsafe_undefined = true;
4880
5053
  }
4881
- const results = await compilerCtx.worker.prepareModule(code, minifyOpts);
4882
- if (results != null && typeof results.output === "string" && results.diagnostics.length === 0 && compilerCtx != null) {
4883
- if (opts.isCore) results.output = results.output.replace(/disconnectedCallback\(\)\{\},/g, "");
4884
- await compilerCtx.cache.put(cacheKey, results.output);
4885
- if (results.sourceMap) await compilerCtx.cache.put(cacheKey + "Map", JSON.stringify(results.sourceMap));
4886
- }
4887
- return results;
5054
+ return minifyOpts;
4888
5055
  };
4889
5056
  /**
4890
5057
  * Builds a configuration object to be used by Terser for the purposes of minifying a user's JavaScript
@@ -4941,6 +5108,81 @@ function getTerserManglePropertiesConfig() {
4941
5108
  };
4942
5109
  }
4943
5110
  /**
5111
+ * Builds the oxc (rolldown minifier) options for a specific module being optimized.
5112
+ *
5113
+ * A few terser knobs have no oxc equivalent and so are dropped:
5114
+ * - `global_defs` (used to fold `supportsListenerOptions` to `true` in the core runtime bundle)
5115
+ * - `unsafe`/`unsafe_undefined`/`inline` compress passes
5116
+ * - `passes` (oxc's compressor iterates to a fix point automatically)
5117
+ *
5118
+ * @param config the Stencil configuration file that was provided as a part of the build step
5119
+ * @param opts the options for the module being optimized
5120
+ * @param isDebug if true, set the necessary flags to produce readable, debuggable output
5121
+ * @returns the minification options to hand to oxc
5122
+ */
5123
+ const getOxcMinifyOptions = (config, opts, isDebug) => {
5124
+ const minifyOpts = {
5125
+ module: true,
5126
+ sourcemap: !!config.sourceMap,
5127
+ inputMap: config.sourceMap ? opts.sourceMap ?? void 0 : void 0,
5128
+ mangleProps: getOxcManglePropertiesConfig(isDebug)
5129
+ };
5130
+ if (isDebug) {
5131
+ minifyOpts.mangle = false;
5132
+ minifyOpts.compress = {
5133
+ dropConsole: false,
5134
+ dropDebugger: false
5135
+ };
5136
+ minifyOpts.codegen = {
5137
+ removeWhitespace: false,
5138
+ legalComments: "inline"
5139
+ };
5140
+ } else {
5141
+ minifyOpts.mangle = { toplevel: true };
5142
+ minifyOpts.compress = { treeshake: {
5143
+ propertyReadSideEffects: false,
5144
+ manualPureFunctions: opts.isCore ? ["getHostRef"] : []
5145
+ } };
5146
+ }
5147
+ return minifyOpts;
5148
+ };
5149
+ /**
5150
+ * `ComponentRuntimeMeta` (the shape of a component class's static `cmpMeta` getter) is
5151
+ * produced by one compiled unit and read by another (e.g. a component's own chunk vs the
5152
+ * SSR/hydrate runtime, or a lazy component's entry chunk vs the core runtime chunk).
5153
+ *
5154
+ * Oxc's mangleProps` has been observed to mangle a property at its read site but leave the same
5155
+ * property's key unmangled silently breaking that read (e.g. `cmpMeta.$tagName$` reads as `undefined`).
5156
+ * Reserving these names avoids the mismatch entirely.
5157
+ *
5158
+ * Assess in time with rolldown / oxc updates via `cd test/build/output && pnpm test`
5159
+ */
5160
+ const RESERVED_CMP_META_PROPS = [
5161
+ "$flags$",
5162
+ "$tagName$",
5163
+ "$members$",
5164
+ "$listeners$",
5165
+ "$attrsToReflect$",
5166
+ "$watchers$",
5167
+ "$lazyBundleId$",
5168
+ "$serializers$",
5169
+ "$deserializers$"
5170
+ ];
5171
+ /**
5172
+ * Get baseline configuration for oxc's `mangleProps` option, mirroring
5173
+ * {@link getTerserManglePropertiesConfig}.
5174
+ *
5175
+ * @param isDebug if true, produce readable `_$name$_`-style output names instead of minified ones
5176
+ * @returns an object with our baseline property mangling configuration
5177
+ */
5178
+ function getOxcManglePropertiesConfig(isDebug) {
5179
+ return {
5180
+ include: /^\$.+\$$/,
5181
+ reserved: ["$hostElement$", ...RESERVED_CMP_META_PROPS],
5182
+ debug: isDebug
5183
+ };
5184
+ }
5185
+ /**
4944
5186
  * This method is likely to be called by a worker on the compiler context, rather than directly.
4945
5187
  * @param input the source code to minify
4946
5188
  * @param minifyOpts options to be used by the minifier
@@ -5089,7 +5331,7 @@ const buildWorker = async (config, compilerCtx, buildCtx, ctx, workerEntryPath)
5089
5331
  let code = entryPoint.code;
5090
5332
  const results = await optimizeModule(config, compilerCtx, {
5091
5333
  input: code,
5092
- sourceTarget: "es2017",
5334
+ sourceTarget: "es2022",
5093
5335
  isCore: false,
5094
5336
  minify: config.minifyJs,
5095
5337
  inlineHelpers: true
@@ -5393,6 +5635,7 @@ const getRolldownOptions = (config, compilerCtx, buildCtx, bundleOpts) => {
5393
5635
  },
5394
5636
  coreResolvePlugin(config, compilerCtx, bundleOpts.platform, !!bundleOpts.externalRuntime, bundleOpts.conditionals?.lazyLoad ?? false),
5395
5637
  appDataPlugin(config, compilerCtx, buildCtx, bundleOpts.conditionals, bundleOpts.platform),
5638
+ buildConditionalsPlugin(config, bundleOpts.conditionals),
5396
5639
  lazyComponentPlugin(buildCtx),
5397
5640
  loaderPlugin(bundleOpts.loader),
5398
5641
  userIndexPlugin(config, compilerCtx),
@@ -6569,10 +6812,6 @@ const addStaticImports = (rolldownChunkResults, bundleModules) => {
6569
6812
  const generateCjs = isCjsFormat(index) ? generateCaseClauseCjs : generateCaseClause;
6570
6813
  index.code = index.code.replace("/*!__STENCIL_STATIC_IMPORT_SWITCH__*/", `
6571
6814
  if (!hmrVersionId || !BUILD.hotModuleReplacement) {
6572
- const processMod = importedModule => {
6573
- cmpModules.set(bundleId, importedModule);
6574
- return importedModule[exportName];
6575
- }
6576
6815
  switch(bundleId) {
6577
6816
  ${bundleModules.map((mod) => generateCjs(mod.output.bundleId)).join("")}
6578
6817
  }
@@ -6606,7 +6845,7 @@ const generateCaseClause = (bundleId) => {
6606
6845
  case '${bundleId}':
6607
6846
  return import(
6608
6847
  /* webpackMode: "lazy" */
6609
- './${bundleId}.entry.js').then(processMod, consoleError);`;
6848
+ './${bundleId}.entry.js').then(onLoad, onError);`;
6610
6849
  };
6611
6850
  /**
6612
6851
  * Generate a 'case' clause to be used within a `switch` statement. The case clause generated will key-off the provided
@@ -6619,7 +6858,7 @@ const generateCaseClauseCjs = (bundleId) => {
6619
6858
  case '${bundleId}':
6620
6859
  return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(
6621
6860
  /* webpackMode: "lazy" */
6622
- './${bundleId}.entry.js')); }).then(processMod, consoleError);`;
6861
+ './${bundleId}.entry.js')); }).then(onLoad, onError);`;
6623
6862
  };
6624
6863
  const generateLazyEntryModule = async (config, compilerCtx, buildCtx, rolldownResult, outputTargetType, destinations, sourceTarget, shouldMinify, isBrowserBuild) => {
6625
6864
  const entryModule = buildCtx.entryModules.find((em) => em.entryKey === rolldownResult.entryKey);
@@ -6847,7 +7086,7 @@ const generateCjs = async (config, compilerCtx, buildCtx, rolldownBuild, outputT
6847
7086
  const results = await generateRolldownOutput(rolldownBuild, esmOpts, config, buildCtx.entryModules);
6848
7087
  if (results != null) {
6849
7088
  const destinations = cjsOutputs.map((o) => o.cjsDir).filter((cjsDir) => typeof cjsDir === "string");
6850
- buildCtx.commonJsComponentBundle = await generateLazyModules(config, compilerCtx, buildCtx, outputTargetType, destinations, results, "es2017", false);
7089
+ buildCtx.commonJsComponentBundle = await generateLazyModules(config, compilerCtx, buildCtx, outputTargetType, destinations, results, "es2022", false);
6851
7090
  await generateShortcuts$1(compilerCtx, results, cjsOutputs);
6852
7091
  }
6853
7092
  }
@@ -7133,7 +7372,13 @@ function createEntryModule(cmps) {
7133
7372
  }
7134
7373
  const getLazyEntry = (isBrowser, assetPath, externalRuntime = false) => {
7135
7374
  const s = new MagicString(``);
7136
- s.append(`export { setNonce, setRegistry, setTagTransformer } from '${STENCIL_CORE_ID}';\n`);
7375
+ const platformExports = [
7376
+ "setNonce",
7377
+ "setRegistry",
7378
+ "setTagTransformer"
7379
+ ];
7380
+ if (assetPath) platformExports.push("setAssetPath");
7381
+ s.append(`export { ${platformExports.join(", ")} } from '${STENCIL_CORE_ID}';\n`);
7137
7382
  s.append(`import { bootstrapLazy } from '${STENCIL_CORE_ID}';\n`);
7138
7383
  if (isBrowser) {
7139
7384
  if (assetPath) s.append(`import { setAssetPath } from '${STENCIL_CORE_ID}';\n`);
@@ -9148,15 +9393,17 @@ const generateStandaloneTypesOutput = async (config, compilerCtx, buildCtx, type
9148
9393
  if (outputTarget.autoLoader) {
9149
9394
  const loaderFileName = typeof outputTarget.autoLoader === "object" ? outputTarget.autoLoader.fileName || "loader" : "loader";
9150
9395
  const loaderDtsPath = join$2(outputTarget.dir, `${loaderFileName}.d.ts`);
9151
- const loaderDtsCode = generateLoaderType();
9396
+ const hasAssets = buildCtx.components.some((cmp) => cmp.assetsDirs != null && cmp.assetsDirs.length > 0);
9397
+ const loaderDtsCode = generateLoaderType(hasAssets);
9152
9398
  await compilerCtx.fs.writeFile(loaderDtsPath, loaderDtsCode, { outputTargetType: outputTarget.type });
9153
9399
  }
9154
9400
  };
9155
9401
  /**
9156
9402
  * Generate a type declaration file for the auto-loader module
9403
+ * @param hasAssets whether any component declares assets, matching whether setAssetPath is actually exported
9157
9404
  * @returns the contents of the type declaration file for the loader
9158
9405
  */
9159
- const generateLoaderType = () => {
9406
+ const generateLoaderType = (hasAssets) => {
9160
9407
  return [
9161
9408
  `/**`,
9162
9409
  ` * Start the auto-loader, scanning the DOM and watching for changes.`,
@@ -9170,7 +9417,18 @@ const generateLoaderType = () => {
9170
9417
  ` * Stop the auto-loader and disconnect the MutationObserver.`,
9171
9418
  ` */`,
9172
9419
  `export declare function stop(): void;`,
9173
- ``
9420
+ ``,
9421
+ ...hasAssets ? [
9422
+ `/**`,
9423
+ ` * Used to manually set the base path where component assets can be found. The`,
9424
+ ` * default is relative to this module's own location, which may not hold once a`,
9425
+ ` * consuming bundler relocates it - call this before start() to override.`,
9426
+ ` * @param path the asset path to set`,
9427
+ ` * @returns the set path`,
9428
+ ` */`,
9429
+ `export declare function setAssetPath(path: string): string;`,
9430
+ ``
9431
+ ] : []
9174
9432
  ].join("\n");
9175
9433
  };
9176
9434
  /**
@@ -9660,7 +9918,7 @@ const FORM_ASSOCIATED_ATTRIBUTES = [
9660
9918
  * @param cmp the metadata for the component that a type definition string is generated for
9661
9919
  * @param typeImportData locally/imported/globally used type names, which may be used to prevent naming collisions
9662
9920
  * @param areTypesInternal `true` if types being generated are for a project's internal purposes, `false` otherwise
9663
- * @param signalBacking `true` if the component is using signal backing for its props; includes the signals map on the element interface
9921
+ * @param signalBacking `true` if the component is using signal backing for its props; includes the signals map on the element interface and unions JSX prop types with `ReadonlySignal<T>`
9664
9922
  * @returns the generated types string alongside additional metadata
9665
9923
  */
9666
9924
  const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBacking = false) => {
@@ -9677,8 +9935,12 @@ const generateComponentTypes = (cmp, typeImportData, areTypesInternal, signalBac
9677
9935
  const isDep = cmp.isCollectionDependency;
9678
9936
  const propNames = new Set(propAttributes.map((p) => p.name));
9679
9937
  const formAssociatedAttrs = cmp.formAssociated ? FORM_ASSOCIATED_ATTRIBUTES.filter((attr) => !propNames.has(attr.name)) : [];
9938
+ const jsxPropAttributes = signalBacking ? propAttributes.map((attr) => ({
9939
+ ...attr,
9940
+ type: `${attr.type} | ReadonlySignal<${attr.type}>`
9941
+ })) : propAttributes;
9680
9942
  const jsxAttributes = attributesToMultiLineString([
9681
- ...propAttributes,
9943
+ ...jsxPropAttributes,
9682
9944
  ...eventAttributes,
9683
9945
  ...formAssociatedAttrs
9684
9946
  ], true, areTypesInternal);
@@ -10115,8 +10377,9 @@ const generateTypesOutput = async (config, compilerCtx, buildCtx, outputTarget)
10115
10377
  await generateAppTypes(config, compilerCtx, buildCtx, distPath);
10116
10378
  const typesDir = outputTarget.dir;
10117
10379
  if (distDtsFilePath) await generateStandaloneTypes(config, compilerCtx, buildCtx, typesDir);
10118
- if (config.outputTargets.some(isOutputTargetLoaderBundle)) await generateLoaderTypes(compilerCtx, typesDir);
10119
- if (config.outputTargets.some(isOutputTargetStandalone)) await generateStandaloneApiTypes(compilerCtx, typesDir);
10380
+ const hasAssets = buildCtx.components.some((cmp) => cmp.assetsDirs != null && cmp.assetsDirs.length > 0);
10381
+ if (config.outputTargets.some(isOutputTargetLoaderBundle)) await generateLoaderTypes(compilerCtx, typesDir, hasAssets);
10382
+ if (config.outputTargets.some(isOutputTargetStandalone)) await generateStandaloneApiTypes(compilerCtx, typesDir, hasAssets);
10120
10383
  };
10121
10384
  /**
10122
10385
  * Generate loader.d.ts file for the loader entry point.
@@ -10124,8 +10387,9 @@ const generateTypesOutput = async (config, compilerCtx, buildCtx, outputTarget)
10124
10387
  *
10125
10388
  * @param compilerCtx the current compiler context
10126
10389
  * @param typesDir the directory to write the loader.d.ts file to
10390
+ * @param hasAssets whether any component declares assets, matching whether setAssetPath is actually exported
10127
10391
  */
10128
- const generateLoaderTypes = async (compilerCtx, typesDir) => {
10392
+ const generateLoaderTypes = async (compilerCtx, typesDir, hasAssets) => {
10129
10393
  const loaderDtsContent = `export * from './components';
10130
10394
  export interface CustomElementsDefineOptions {
10131
10395
  exclude?: string[];
@@ -10161,7 +10425,17 @@ export type TagTransformer = (tag: string) => string;
10161
10425
  * Useful for namespacing (e.g. \`my-button\` → \`acme-button\`) in multi-library pages.
10162
10426
  */
10163
10427
  export declare function setTagTransformer(transformer: TagTransformer): void;
10164
- `;
10428
+ ${hasAssets ? `
10429
+ /**
10430
+ * Used to manually set the base path where component assets can be found. The
10431
+ * default is relative to this module's own location, which may not hold once a
10432
+ * bundler relocates it, or once its CDN URL diverges from the assets' own -
10433
+ * import and call this before the module's default has been used to override it.
10434
+ * @param path the asset path to set
10435
+ * @returns the set path
10436
+ */
10437
+ export declare function setAssetPath(path: string): string;
10438
+ ` : ""}`;
10165
10439
  const loaderDtsPath = join$2(typesDir, "loader.d.ts");
10166
10440
  await compilerCtx.fs.writeFile(loaderDtsPath, loaderDtsContent);
10167
10441
  };
@@ -10171,8 +10445,9 @@ export declare function setTagTransformer(transformer: TagTransformer): void;
10171
10445
  *
10172
10446
  * @param compilerCtx the current compiler context
10173
10447
  * @param typesDir the directory to write the standalone.d.ts file to
10448
+ * @param hasAssets whether any component declares assets, matching whether setAssetPath is actually exported
10174
10449
  */
10175
- const generateStandaloneApiTypes = async (compilerCtx, typesDir) => {
10450
+ const generateStandaloneApiTypes = async (compilerCtx, typesDir, hasAssets) => {
10176
10451
  const standaloneDtsContent = `/**
10177
10452
  * Used to specify a nonce value that corresponds with an application's CSP.
10178
10453
  * When set, the nonce will be added to all dynamically created script and style tags at runtime.
@@ -10205,7 +10480,16 @@ export interface SetPlatformOptions {
10205
10480
  rel?: (el: EventTarget, eventName: string, listener: EventListenerOrEventListenerObject, options: boolean | AddEventListenerOptions) => void;
10206
10481
  }
10207
10482
  export declare const setPlatformOptions: (opts: SetPlatformOptions) => void;
10208
- `;
10483
+ ${hasAssets ? `
10484
+ /**
10485
+ * Used to manually set the base path where component assets can be found. The
10486
+ * default is relative to this module's own location, which may not hold once a
10487
+ * consuming bundler relocates it - call this before any component module is imported to override.
10488
+ * @param path the asset path to set
10489
+ * @returns the set path
10490
+ */
10491
+ export declare const setAssetPath: (path: string) => string;
10492
+ ` : ""}`;
10209
10493
  const standaloneDtsPath = join$2(typesDir, "standalone.d.ts");
10210
10494
  await compilerCtx.fs.writeFile(standaloneDtsPath, standaloneDtsContent);
10211
10495
  };
@@ -12166,7 +12450,7 @@ const generateLoaderModule = (components, outputTarget, relativeAssetPath) => {
12166
12450
  const autoStart = typeof autoLoaderConfig === "object" ? autoLoaderConfig.autoStart !== false : true;
12167
12451
  const tagsList = components.map((cmp) => `'${cmp.tagName}'`).join(", ");
12168
12452
  const switchCases = components.map((cmp) => ` case '${cmp.tagName}': module = await import('./${cmp.tagName}.js'); break;`).join("\n");
12169
- const assetPathImport = relativeAssetPath ? `import { setAssetPath } from '${STENCIL_INTERNAL_STANDALONE_CLIENT_PLATFORM_ID}';\n` : "";
12453
+ const assetPathImport = relativeAssetPath ? `import { setAssetPath } from '${STENCIL_INTERNAL_STANDALONE_CLIENT_PLATFORM_ID}';\nexport { setAssetPath };\n` : "";
12170
12454
  const assetPathInit = relativeAssetPath ? `setAssetPath(new URL('${relativeAssetPath}', String(import.meta.url)).href);\n` : "";
12171
12455
  return `
12172
12456
  import { transformTag, getRegistry } from '${STENCIL_INTERNAL_STANDALONE_CLIENT_PLATFORM_ID}';
@@ -12527,12 +12811,25 @@ const addStandaloneInputs = (config, buildCtx, bundleOpts, outputTarget) => {
12527
12811
  const indexImports = [];
12528
12812
  const indexExports = [];
12529
12813
  const exportNames = [];
12814
+ let relativeAssetPath;
12815
+ if (components.some((cmp) => cmp.assetsDirs != null && cmp.assetsDirs.length > 0)) {
12816
+ const assetsTarget = config.outputTargets.find(isOutputTargetAssets);
12817
+ if (assetsTarget?.dir && outputTarget.dir) {
12818
+ const rel = relative$1(outputTarget.dir, assetsTarget.dir);
12819
+ relativeAssetPath = rel.endsWith("/") ? rel : rel + "/";
12820
+ }
12821
+ }
12530
12822
  components.forEach((cmp) => {
12531
12823
  const exp = [];
12532
12824
  const exportName = dashToPascalCase(cmp.tagName);
12533
12825
  const importName = cmp.componentClassName;
12534
12826
  const importAs = `$Cmp${exportName}`;
12535
12827
  const coreKey = `\0${exportName}`;
12828
+ if (relativeAssetPath) {
12829
+ exp.push(`import { setAssetPath } from '${STENCIL_INTERNAL_STANDALONE_CLIENT_PLATFORM_ID}';`);
12830
+ exp.push(`export { setAssetPath };`);
12831
+ exp.push(`setAssetPath(new URL('${relativeAssetPath}', import.meta.url).href);`);
12832
+ }
12536
12833
  if (cmp.isPlain) {
12537
12834
  exp.push(`export { ${importName} as ${exportName} } from '${cmp.sourceFilePath}';`);
12538
12835
  indexExports.push(`export { ${exportName} } from '${coreKey}';`);
@@ -12547,14 +12844,6 @@ const addStandaloneInputs = (config, buildCtx, bundleOpts, outputTarget) => {
12547
12844
  bundleOpts.inputs[cmp.tagName] = coreKey;
12548
12845
  bundleOpts.loader[coreKey] = exp.join("\n");
12549
12846
  });
12550
- let relativeAssetPath;
12551
- if (components.some((cmp) => cmp.assetsDirs != null && cmp.assetsDirs.length > 0)) {
12552
- const assetsTarget = config.outputTargets.find(isOutputTargetAssets);
12553
- if (assetsTarget?.dir && outputTarget.dir) {
12554
- const rel = relative$1(outputTarget.dir, assetsTarget.dir);
12555
- relativeAssetPath = rel.endsWith("/") ? rel : rel + "/";
12556
- }
12557
- }
12558
12847
  bundleOpts.loader["\0core"] = generateEntryPoint(outputTarget, indexImports, indexExports, exportNames, relativeAssetPath);
12559
12848
  if (outputTarget.autoLoader) {
12560
12849
  const loaderFileName = typeof outputTarget.autoLoader === "object" ? outputTarget.autoLoader.fileName || "loader" : "loader";
@@ -12578,6 +12867,7 @@ const generateEntryPoint = (outputTarget, cmpImports = [], cmpExports = [], cmpN
12578
12867
  exports.push(`export { setNonce, setRegistry, setTagTransformer, setPlatformOptions } from '${STENCIL_INTERNAL_STANDALONE_CLIENT_PLATFORM_ID}';`, `export * from '${USER_INDEX_ENTRY_ID}';`);
12579
12868
  if (relativeAssetPath) {
12580
12869
  imports.push(`import { setAssetPath } from '${STENCIL_INTERNAL_STANDALONE_CLIENT_PLATFORM_ID}';`);
12870
+ exports.push(`export { setAssetPath };`);
12581
12871
  body.push(`setAssetPath(new URL('${relativeAssetPath}', import.meta.url).href);`);
12582
12872
  }
12583
12873
  if (outputTarget.includeGlobalScripts !== false) {
@@ -12688,6 +12978,7 @@ const IS_CASE_SENSITIVE_FILE_NAMES = !(process.platform === "win32");
12688
12978
  //#endregion
12689
12979
  //#region src/compiler/sys/typescript/typescript-sys.ts
12690
12980
  const patchTsSystemFileSystem = (config, compilerSys, inMemoryFs, tsSys) => {
12981
+ if (!tsSys) return;
12691
12982
  const realpath = (path) => {
12692
12983
  const rp = compilerSys.realpathSync(path);
12693
12984
  if (isString$1(rp)) return rp;
@@ -12765,6 +13056,7 @@ const patchTsSystemFileSystem = (config, compilerSys, inMemoryFs, tsSys) => {
12765
13056
  return tsSys;
12766
13057
  };
12767
13058
  const patchTsSystemWatch = (compilerSystem, tsSys) => {
13059
+ if (!tsSys) return;
12768
13060
  tsSys.watchDirectory = (p, cb, recursive) => {
12769
13061
  const watcher = compilerSystem.watchDirectory(p, (filePath) => {
12770
13062
  cb(filePath);
@@ -12788,26 +13080,6 @@ const patchTypescript = (config, inMemoryFs) => {
12788
13080
  patchTsSystemFileSystem(config, config.sys, inMemoryFs, ts.sys);
12789
13081
  patchTsSystemWatch(config.sys, ts.sys);
12790
13082
  };
12791
- const patchTypeScriptSysMinimum = () => {
12792
- if (!ts.sys) ts.sys = {
12793
- args: [],
12794
- createDirectory: noop,
12795
- directoryExists: () => false,
12796
- exit: noop,
12797
- fileExists: () => false,
12798
- getCurrentDirectory: process.cwd,
12799
- getDirectories: () => [],
12800
- getExecutingFilePath: () => "./",
12801
- readDirectory: () => [],
12802
- readFile: noop,
12803
- newLine: "\n",
12804
- resolvePath: resolve$2,
12805
- useCaseSensitiveFileNames: false,
12806
- write: noop,
12807
- writeFile: noop
12808
- };
12809
- };
12810
- patchTypeScriptSysMinimum();
12811
13083
  const getTypescriptPathFromUrl = (config, tsExecutingUrl, url) => {
12812
13084
  const tsBaseUrl = new URL("..", tsExecutingUrl).href;
12813
13085
  if (url.startsWith(tsBaseUrl)) {
@@ -15003,14 +15275,16 @@ const parseWatchDecorator = (typeChecker, method, decoratorName) => {
15003
15275
  * @param diagnostics for surfacing errors and warnings
15004
15276
  * @param typeChecker a TypeScript typechecker instance
15005
15277
  * @param program a {@link ts.Program} object
15278
+ * @param includeClassExpressions also convert `ts.ClassExpression` nodes (e.g. a mixin factory's
15279
+ * `(Base) => class extends Base {}`), not just named `ts.ClassDeclaration`s
15006
15280
  * @returns a TypeScript transformer factory which can be passed to
15007
15281
  * TypeScript to transform source code during the compilation process
15008
15282
  */
15009
- const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) => {
15283
+ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program, includeClassExpressions = false) => {
15010
15284
  return (transformCtx) => {
15011
15285
  let sourceFile;
15012
15286
  const visit = (node) => {
15013
- if (ts.isClassDeclaration(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
15287
+ if (ts.isClassDeclaration(node) || includeClassExpressions && ts.isClassExpression(node)) return visitClassDeclaration(config, diagnostics, typeChecker, program, node, sourceFile);
15014
15288
  return ts.visitEachChild(node, visit, transformCtx);
15015
15289
  };
15016
15290
  return (tsSourceFile) => {
@@ -15020,10 +15294,10 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
15020
15294
  };
15021
15295
  };
15022
15296
  /**
15023
- * Visit {@link ts.ClassDeclaration} nodes as part of the tree-traversal
15297
+ * Visit {@link ts.ClassDeclaration}/{@link ts.ClassExpression} nodes as part of the tree-traversal
15024
15298
  * required for {@link convertDecoratorsToStatic} to work.
15025
15299
  *
15026
- * If a given class declaration node is not decorated with `@Component` this
15300
+ * If a given class node is not decorated with `@Component` this
15027
15301
  * function will simply return it as-is. If it _is_ decorated, then it will
15028
15302
  *
15029
15303
  * 1. Convert the arguments to the `@Component` decorator to static values.
@@ -15032,7 +15306,7 @@ const convertDecoratorsToStatic = (config, diagnostics, typeChecker, program) =>
15032
15306
  * to static values.
15033
15307
  * 3. Validate that the various options selected by the component author are
15034
15308
  * valid, both individually and in combination.
15035
- * 4. Return an updated class declaration node which is ready to be used in
15309
+ * 4. Return an updated class node which is ready to be used in
15036
15310
  * the rest of the Stencil compilation pipeline (e.g. in output target
15037
15311
  * generation).
15038
15312
  *
@@ -15051,7 +15325,7 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
15051
15325
  const decoratedMembers = classMembers.filter((member) => (retrieveTsDecorators(member)?.length ?? 0) > 0);
15052
15326
  if (!decoratedMembers.length && !componentDecorator) return classNode;
15053
15327
  const filteredMethodsAndFields = removeStencilMethodDecorators(Array.from(classMembers), diagnostics, importAliasMap);
15054
- if (componentDecorator) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
15328
+ if (componentDecorator && ts.isClassDeclaration(classNode)) componentDecoratorToStatic(config, typeChecker, diagnostics, classNode, filteredMethodsAndFields, componentDecorator);
15055
15329
  if (decoratedMembers.length > 0) {
15056
15330
  const serializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("PropSerialize"), "PropSerialize", importAliasMap.get("Prop"));
15057
15331
  const deserializers = serializeDecoratorsToStatic(typeChecker, decoratedMembers, filteredMethodsAndFields, importAliasMap.get("AttrDeserialize"), "AttrDeserialize", importAliasMap.get("Prop"));
@@ -15067,7 +15341,8 @@ const visitClassDeclaration = (config, diagnostics, typeChecker, program, classN
15067
15341
  validateMethods(diagnostics, classMembers);
15068
15342
  const currentDecorators = retrieveTsDecorators(classNode);
15069
15343
  const updatedClassFields = updateConstructor(classNode, filteredMethodsAndFields, []);
15070
- return ts.factory.updateClassDeclaration(classNode, [...filterDecorators(currentDecorators, CLASS_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator))) ?? [], ...retrieveTsModifiers(classNode) ?? []], classNode.name, classNode.typeParameters, classNode.heritageClauses, updatedClassFields);
15344
+ const updatedModifiers = [...filterDecorators(currentDecorators, CLASS_DECORATORS_TO_REMOVE.map((decorator) => importAliasMap.get(decorator))) ?? [], ...retrieveTsModifiers(classNode) ?? []];
15345
+ return ts.isClassDeclaration(classNode) ? ts.factory.updateClassDeclaration(classNode, updatedModifiers, classNode.name, classNode.typeParameters, classNode.heritageClauses, updatedClassFields) : ts.factory.updateClassExpression(classNode, updatedModifiers, classNode.name, classNode.typeParameters, classNode.heritageClauses, updatedClassFields);
15071
15346
  };
15072
15347
  /**
15073
15348
  * Take a list of `ClassElement` AST nodes and remove any decorators from
@@ -15251,23 +15526,44 @@ const parseStaticWatchers = (staticMembers) => {
15251
15526
  //#endregion
15252
15527
  //#region src/compiler/transformers/static-to-meta/class-extension/shared.ts
15253
15528
  /**
15254
- * Walks the AST looking for a class declaration, optionally by name - descends
15255
- * into a mixin factory's wrapping function (arrow function or `function`
15256
- * declaration) body too, since a mixin factory's class is always nested one
15257
- * level inside it (e.g. `const Foo = (Base) => class extends Base {}`).
15529
+ * Warns when an `extends`/`Mixin(...)` target resolved to *something* but no class literal
15530
+ * could be found inside it - e.g. a mixin factory that returns an existing class by reference
15531
+ * (`(Base) => SomeExistingClass`) rather than a class literal. Without this, the target is
15532
+ * silently dropped: any `@Prop`/`@State` etc. it declares just never appears on the extending
15533
+ * component, with no diagnostic explaining why.
15534
+ * @param buildCtx used to surface the warning - omit to warn silently (e.g. from tests)
15535
+ * @param targetName the identifier the target was reached through
15536
+ * @param anchor the node to attach the warning to
15537
+ */
15538
+ function warnMixinFactoryClassNotFound(buildCtx, targetName, anchor) {
15539
+ if (!buildCtx) return;
15540
+ const err = buildWarn(buildCtx.diagnostics);
15541
+ err.messageText = `Found "${targetName}", but couldn't find a class inside it. If it's meant to be a mixin factory, make sure it returns a class literal directly, e.g. \`(Base) => class extends Base {}\` or \`(Base) => { class ${targetName}Class extends Base {} return ${targetName}Class; }\` - returning an existing class by reference (\`(Base) => SomeExistingClass\`) isn't recognized, and any \`@Prop\`/\`@State\`/etc. it declares won't be applied.`;
15542
+ if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, anchor);
15543
+ }
15544
+ /**
15545
+ * Walks the AST looking for a class declaration or class expression, optionally by name -
15546
+ * descends into a mixin factory's wrapping function (arrow function or `function` declaration)
15547
+ * body too, since a mixin factory's class is always nested one level inside it. Recognizes all of:
15548
+ * `const Foo = (Base) => class extends Base {}` (concise arrow body), `const Foo = (Base) => {
15549
+ * return class extends Base {}; }` (block body, `return` of a class expression), and `const Foo =
15550
+ * (Base) => { class FooClass extends Base {} return FooClass; }` (block body, named declaration).
15258
15551
  * @param node the node to search from
15259
- * @param name if given, only matches a class declaration with this name
15260
- * @returns the found class declaration, or `undefined`
15552
+ * @param name if given, only matches a class with this name
15553
+ * @returns the found class, or `undefined`
15261
15554
  */
15262
15555
  function findClassWalk(node, name) {
15263
15556
  if (!node) return void 0;
15264
- if (ts.isClassDeclaration(node)) {
15557
+ if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
15265
15558
  if (!name || node.name?.text === name) return node;
15266
15559
  } else if (ts.isVariableDeclaration(node) && (!name || name === node.name?.text) && node.initializer && ts.isArrowFunction(node.initializer)) {
15560
+ const body = node.initializer.body;
15561
+ if (ts.isClassExpression(body)) return body;
15267
15562
  let found;
15268
- ts.forEachChild(node.initializer.body, (child) => {
15563
+ ts.forEachChild(body, (child) => {
15269
15564
  if (found) return;
15270
15565
  if (ts.isClassDeclaration(child)) found = child;
15566
+ else if (ts.isReturnStatement(child) && child.expression && ts.isClassExpression(child.expression)) found = child.expression;
15271
15567
  });
15272
15568
  return found;
15273
15569
  }
@@ -15280,6 +15576,22 @@ function findClassWalk(node, name) {
15280
15576
  return found;
15281
15577
  }
15282
15578
  /**
15579
+ * The declared name of a mixin-factory statement (`function Foo() {}`, or `const Foo = ...`) -
15580
+ * survives the decorator-to-static-getter transform even when the factory's inner class doesn't
15581
+ * have a name of its own, so it can anchor a post-transform re-lookup via `findClassWalk`.
15582
+ * @param node the factory statement (or its variable declaration) to read a name from
15583
+ * @returns the declared name, or `undefined` if it can't be determined
15584
+ */
15585
+ function factoryDeclaredName(node) {
15586
+ if (!node) return void 0;
15587
+ if (ts.isFunctionDeclaration(node)) return node.name?.text;
15588
+ if (ts.isVariableDeclaration(node)) return ts.isIdentifier(node.name) ? node.name.text : void 0;
15589
+ if (ts.isVariableStatement(node)) {
15590
+ const decl = node.declarationList.declarations[0];
15591
+ return decl && ts.isIdentifier(decl.name) ? decl.name.text : void 0;
15592
+ }
15593
+ }
15594
+ /**
15283
15595
  * Matches a top-level class/function/variable declaration by name - the three
15284
15596
  * shapes a mixin or base-class export can take (a plain class, a mixin
15285
15597
  * factory function declaration, or a mixin factory assigned to a `const`).
@@ -15401,7 +15713,7 @@ function convertDiskSourceFileDecorators(sourceFile, config, target = ts.ScriptT
15401
15713
  const program = ts.createProgram([sourceFile.fileName], compilerOptions, host);
15402
15714
  const typeChecker = program.getTypeChecker();
15403
15715
  const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
15404
- const result = ts.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
15716
+ const result = ts.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
15405
15717
  const printed = ts.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
15406
15718
  return ts.createSourceFile(sourceFile.fileName, printed, target, true);
15407
15719
  }
@@ -15453,6 +15765,7 @@ function resolveAndProcessExtendedClass(compilerCtx, buildCtx, classDeclaration,
15453
15765
  if (!foundClassDeclaration && matchedStatement) {
15454
15766
  foundClassDeclaration = findClassWalk(matchedStatement);
15455
15767
  keepLooking = false;
15768
+ if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, className, classDeclaration);
15456
15769
  }
15457
15770
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
15458
15771
  dependentClasses.push({
@@ -15487,6 +15800,7 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
15487
15800
  const targetScriptTarget = (ogModule?.staticSourceFile)?.languageVersion ?? ts.ScriptTarget.ESNext;
15488
15801
  let classIdentifiers = [];
15489
15802
  let foundClassDeclaration;
15803
+ let foundClassName;
15490
15804
  let keepLooking = true;
15491
15805
  extendsClause.types.forEach((type) => {
15492
15806
  if (ts.isExpressionWithTypeArguments(type) && ts.isCallExpression(type.expression) && type.expression.expression.getText() === "Mixin") classIdentifiers = type.expression.arguments.filter(ts.isIdentifier);
@@ -15503,17 +15817,20 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
15503
15817
  declarations = [...source.statements];
15504
15818
  }
15505
15819
  foundClassDeclaration = declarations?.find(ts.isClassDeclaration);
15820
+ foundClassName = foundClassDeclaration?.name?.getText();
15506
15821
  if (!foundClassDeclaration) {
15507
15822
  const node = declarations?.[0];
15508
15823
  foundClassDeclaration = findClassWalk(node);
15824
+ foundClassName = foundClassDeclaration?.name?.getText() ?? factoryDeclaredName(node);
15509
15825
  if (!node) throw "revert to sad path";
15510
15826
  keepLooking = false;
15827
+ if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
15511
15828
  }
15512
15829
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
15513
15830
  const foundModule = compilerCtx.moduleMap.get(foundClassDeclaration.getSourceFile().fileName);
15514
15831
  if (foundModule) {
15515
15832
  const moduleSourceFile = foundModule.staticSourceFile;
15516
- const sourceClass = findClassWalk(moduleSourceFile, foundClassDeclaration.name?.getText());
15833
+ const sourceClass = findClassWalk(moduleSourceFile, foundClassName);
15517
15834
  if (sourceClass) {
15518
15835
  dependentClasses.push({
15519
15836
  classNode: sourceClass,
@@ -15534,19 +15851,24 @@ function buildExtendsTree(compilerCtx, classDeclaration, dependentClasses, typeC
15534
15851
  if (!buildCtx.config._isTesting) augmentDiagnosticWithNode(err, classDeclaration);
15535
15852
  return;
15536
15853
  }
15537
- if (matchedStatement && ts.isClassDeclaration(matchedStatement)) foundClassDeclaration = matchedStatement;
15538
- else if (matchedStatement) {
15854
+ if (matchedStatement && ts.isClassDeclaration(matchedStatement)) {
15855
+ foundClassDeclaration = matchedStatement;
15856
+ foundClassName = foundClassDeclaration.name?.getText();
15857
+ } else if (matchedStatement) {
15539
15858
  foundClassDeclaration = findClassWalk(matchedStatement);
15859
+ foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
15540
15860
  keepLooking = false;
15861
+ if (!foundClassDeclaration) warnMixinFactoryClassNotFound(buildCtx, extendee.getText(), classDeclaration);
15541
15862
  } else {
15542
15863
  foundClassDeclaration = findClassWalk(currentSource, extendee.getText());
15864
+ foundClassName = foundClassDeclaration?.name?.getText() ?? extendee.getText();
15543
15865
  keepLooking = false;
15544
15866
  }
15545
15867
  if (foundClassDeclaration && !dependentClasses.some((dc) => dc.classNode === foundClassDeclaration)) {
15546
15868
  const foundModule = compilerCtx.moduleMap.get(currentSource.fileName);
15547
15869
  if (foundModule?.staticSourceFile) {
15548
15870
  const transformedSource = foundModule.staticSourceFile;
15549
- const transformedClass = findClassWalk(transformedSource, foundClassDeclaration.name?.getText());
15871
+ const transformedClass = findClassWalk(transformedSource, foundClassName);
15550
15872
  if (transformedClass) {
15551
15873
  dependentClasses.push({
15552
15874
  classNode: transformedClass,
@@ -15831,7 +16153,7 @@ function convertInMemorySourceDecorators(sourceFile, config) {
15831
16153
  const program = ts.createProgram([sourceFile.fileName], compilerOptions, compilerHost);
15832
16154
  const typeChecker = program.getTypeChecker();
15833
16155
  const ownSourceFile = program.getSourceFile(sourceFile.fileName) ?? sourceFile;
15834
- const result = ts.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program)]);
16156
+ const result = ts.transform(ownSourceFile, [convertDecoratorsToStatic(config, [], typeChecker, program, true)]);
15835
16157
  const printed = ts.createPrinter({ removeComments: false }).printFile(result.transformed[0]);
15836
16158
  const scriptKind = sourceFile.fileName.endsWith(".tsx") || sourceFile.fileName.endsWith(".ts") ? ts.ScriptKind.TSX : ts.ScriptKind.JS;
15837
16159
  return ts.createSourceFile(sourceFile.fileName, printed, sourceFile.languageVersion, true, scriptKind);
@@ -15971,6 +16293,7 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
15971
16293
  else {
15972
16294
  foundClass = findClassWalk(sameFileStatement);
15973
16295
  keepLooking = false;
16296
+ if (!foundClass) warnMixinFactoryClassNotFound(buildCtx, parentName, rootClassDeclaration);
15974
16297
  }
15975
16298
  } else {
15976
16299
  const specifier = findImportSpecifier(sf, parentName);
@@ -15998,13 +16321,15 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
15998
16321
  else {
15999
16322
  foundClass = findClassWalk(found.statement);
16000
16323
  keepLooking = false;
16324
+ if (!foundClass) warnMixinFactoryClassNotFound(buildCtx, parentName, rootClassDeclaration);
16001
16325
  }
16002
16326
  }
16003
16327
  if (!foundClass || ancestors.some((a) => a.classNode === foundClass)) continue;
16004
16328
  ancestors.push({
16005
16329
  classNode: foundClass,
16006
16330
  sourceFile: foundSf,
16007
- path: foundPath
16331
+ path: foundPath,
16332
+ factoryName: parentName
16008
16333
  });
16009
16334
  if (keepLooking) resolveAncestors(foundClass, foundSf, foundPath, resolveImport, visited, ancestors, rootClassDeclaration, buildCtx);
16010
16335
  }
@@ -16021,8 +16346,8 @@ function resolveAncestors(classNode, sf, path, resolveImport, visited, ancestors
16021
16346
  * @returns the ancestor's metadata
16022
16347
  */
16023
16348
  function extractAncestorMeta(ancestor, cmpSourceFile, resolveImport, config) {
16024
- const { classNode, sourceFile: parentSf, path: resolvedPath } = ancestor;
16025
- const className = classNode.name?.text;
16349
+ const { classNode, sourceFile: parentSf, path: resolvedPath, factoryName } = ancestor;
16350
+ const className = classNode.name?.text ?? factoryName;
16026
16351
  const parentStaticMembers = classNode.members.filter(isStaticGetter);
16027
16352
  let resolvedClassNode = classNode;
16028
16353
  let resolvedStaticMembers = parentStaticMembers;
@@ -16727,7 +17052,7 @@ const parseCollectionComponents = (config, compilerCtx, buildCtx, collectionDir,
16727
17052
  };
16728
17053
  const transpileCollectionModule = (config, compilerCtx, buildCtx, collection, inputFileName) => {
16729
17054
  const sourceText = compilerCtx.fs.readFileSync(inputFileName);
16730
- const sourceFile = ts.createSourceFile(inputFileName, sourceText, ts.ScriptTarget.ES2017, true, ts.ScriptKind.JS);
17055
+ const sourceFile = ts.createSourceFile(inputFileName, sourceText, ts.ScriptTarget.ES2022, true, ts.ScriptKind.JS);
16731
17056
  return updateModule(config, compilerCtx, buildCtx, sourceFile, sourceText, inputFileName, void 0, collection);
16732
17057
  };
16733
17058
  //#endregion
@@ -17878,13 +18203,17 @@ const getPackageJsonRecommendations = (config, compilerCtx) => {
17878
18203
  const loaderBundle = config.outputTargets.find(isOutputTargetLoaderBundle);
17879
18204
  const standalone = config.outputTargets.find(isOutputTargetStandalone);
17880
18205
  const types = config.outputTargets.find(isOutputTargetTypes);
18206
+ const srcIndexPath = join$2(config.srcDir, "index.ts");
18207
+ const hasSrcIndex = compilerCtx.fs.accessSync(srcIndexPath);
17881
18208
  const moduleOptions = [];
17882
- if (loaderBundle?.dir) moduleOptions.push(normalizePath(relative$1(config.rootDir, join$2(loaderBundle.dir, "index.js"))));
18209
+ if (loaderBundle?.dir) {
18210
+ const loaderEntry = hasSrcIndex ? join$2(loaderBundle.dir, "index.js") : join$2(loaderBundle.dir, "esm", "loader.js");
18211
+ moduleOptions.push(normalizePath(relative$1(config.rootDir, loaderEntry)));
18212
+ }
17883
18213
  if (standalone?.dir) moduleOptions.push(normalizePath(relative$1(config.rootDir, join$2(standalone.dir, "index.js"))));
17884
18214
  const typesOptions = [];
17885
18215
  if (types?.dir) {
17886
- const srcIndexPath = join$2(config.srcDir, "index.ts");
17887
- if (compilerCtx.fs.accessSync(srcIndexPath)) typesOptions.push(normalizePath(relative$1(config.rootDir, join$2(types.dir, "index.d.ts"))));
18216
+ if (hasSrcIndex) typesOptions.push(normalizePath(relative$1(config.rootDir, join$2(types.dir, "index.d.ts"))));
17888
18217
  else {
17889
18218
  if (loaderBundle) typesOptions.push(normalizePath(relative$1(config.rootDir, join$2(types.dir, "loader.d.ts"))));
17890
18219
  if (standalone) typesOptions.push(normalizePath(relative$1(config.rootDir, join$2(types.dir, "standalone.d.ts"))));
@@ -17902,6 +18231,31 @@ const getPackageJsonRecommendations = (config, compilerCtx) => {
17902
18231
  };
17903
18232
  };
17904
18233
  /**
18234
+ * Collect the rootDir-relative directories of every configured output target that must
18235
+ * ship in the published npm package for consumers (and their tooling) to be able to use
18236
+ * it - as opposed to dev-only artifacts like `www`.
18237
+ * @param config The validated Stencil configuration
18238
+ * @param buildCtx The build context (used to check whether there are actually component
18239
+ * assets to copy - the `assets` output target is otherwise a no-op and its directory is
18240
+ * never written)
18241
+ * @returns a de-duplicated list of rootDir-relative directory paths
18242
+ */
18243
+ const getDistributableOutputDirs = (config, buildCtx) => {
18244
+ const loaderBundle = config.outputTargets.find(isOutputTargetLoaderBundle);
18245
+ const standalone = config.outputTargets.find(isOutputTargetStandalone);
18246
+ const types = config.outputTargets.find(isOutputTargetTypes);
18247
+ const collections = config.outputTargets.filter(isOutputTargetCollection);
18248
+ const assets = buildCtx.components.some((cmp) => cmp.assetsDirs != null && cmp.assetsDirs.length > 0) ? config.outputTargets.find(isOutputTargetAssets) : void 0;
18249
+ const dirs = [
18250
+ loaderBundle?.dir,
18251
+ standalone?.dir,
18252
+ types?.dir,
18253
+ assets?.dir,
18254
+ ...collections.map((c) => c.dir)
18255
+ ].filter((dir) => !!dir).map((dir) => normalizePath(relative$1(config.rootDir, dir)));
18256
+ return Array.from(new Set(dirs));
18257
+ };
18258
+ /**
17905
18259
  * Validate the package.json file for a project, checking that various fields
17906
18260
  * are set correctly for the currently-configured output targets.
17907
18261
  *
@@ -17915,8 +18269,8 @@ const getPackageJsonRecommendations = (config, compilerCtx) => {
17915
18269
  const validateBuildPackageJson = async (config, compilerCtx, buildCtx) => {
17916
18270
  if (config.watch || config.devMode || buildCtx.packageJson == null) return;
17917
18271
  validatePackageJson(config, compilerCtx, buildCtx);
17918
- const stencilCollectionOutputTargets = config.outputTargets.filter(isOutputTargetCollection);
17919
- await Promise.all(stencilCollectionOutputTargets.map((stencilCollectionOT) => validateCollectionFields(config, compilerCtx, buildCtx, stencilCollectionOT)));
18272
+ await validateFilesField(config, compilerCtx, buildCtx);
18273
+ config.outputTargets.filter(isOutputTargetCollection).forEach((stencilCollectionOT) => validateCollectionField(config, compilerCtx, buildCtx, stencilCollectionOT));
17920
18274
  };
17921
18275
  /**
17922
18276
  * Validates a project's package.json fields against recommended values
@@ -18034,40 +18388,49 @@ const validateTypeField = (config, compilerCtx, buildCtx, recommendations) => {
18034
18388
  if (recommendations.moduleOptions.length > 0 && currentType !== "module") packageJsonWarn(config, compilerCtx, buildCtx, `package.json "type" property should be set to "module".`, "\"type\"");
18035
18389
  };
18036
18390
  /**
18037
- * Validate package.json contents specific to the `collection` output target,
18038
- * checking that the `files` array and `collection` field are set correctly.
18039
- * @param config the Stencil configuration associated with the project being compiled
18040
- * @param compilerCtx the current compiler context
18041
- * @param buildCtx the context associated with the current build
18042
- * @param outputTarget the collection output target to validate against
18391
+ * Check if a rootDir-relative directory is covered by a package.json `files` array,
18392
+ * either directly or via a parent directory entry (e.g. "dist/" covers "dist/types/").
18393
+ * @param files the package.json "files" array
18394
+ * @param dir the rootDir-relative directory to check for
18395
+ * @returns true if `dir` is covered by one of the `files` entries
18043
18396
  */
18044
- const validateCollectionFields = async (config, compilerCtx, buildCtx, outputTarget) => {
18045
- await Promise.all([validatePackageFiles(config, compilerCtx, buildCtx, outputTarget), validateCollectionField(config, compilerCtx, buildCtx, outputTarget)]);
18397
+ const isDirCoveredByFiles = (files, dir) => {
18398
+ const normalizedDir = dir.replace(/\/$/, "").replace(/^\.\//, "");
18399
+ return files.some((userPath) => {
18400
+ const normalizedUserPath = normalizePath(userPath).replace(/\/$/, "").replace(/^\.\//, "");
18401
+ if (normalizedUserPath === normalizedDir) return true;
18402
+ const userPathWithSlash = normalizedUserPath + "/";
18403
+ return normalizedDir.startsWith(userPathWithSlash);
18404
+ });
18046
18405
  };
18047
18406
  /**
18048
- * Validate that the `files` field in `package.json` contains directories and
18049
- * files that are necessary for the `collection` output target.
18407
+ * Validate that the `files` field in `package.json` covers every distributable output
18408
+ * directory (loader-bundle, standalone, types, collection) - not just one of them -
18409
+ * since `npm publish` needs all of them to produce a working package for consumers.
18050
18410
  * @param config the Stencil configuration associated with the project being compiled
18051
18411
  * @param compilerCtx the current compiler context
18052
18412
  * @param buildCtx the context associated with the current build
18053
- * @param outputTarget the collection output target to validate against
18054
18413
  */
18055
- const validatePackageFiles = async (config, compilerCtx, buildCtx, outputTarget) => {
18056
- if (!Array.isArray(buildCtx.packageJson.files)) return;
18057
- const actualDistDir = normalizePath(relative$1(config.rootDir, outputTarget.dir));
18058
- if (!buildCtx.packageJson.files.some((userPath) => {
18059
- const normalizedUserPath = normalizePath(userPath).replace(/\/$/, "").replace(/^\.\//, "");
18060
- const normalizedDistDir = actualDistDir.replace(/\/$/, "").replace(/^\.\//, "");
18061
- if (normalizedUserPath === normalizedDistDir) return true;
18062
- const userPathWithSlash = normalizedUserPath + "/";
18063
- if (normalizedDistDir.startsWith(userPathWithSlash)) return true;
18064
- return false;
18065
- })) {
18066
- const msg = `package.json "files" array must contain the distribution directory "${actualDistDir}/" when generating a distribution.`;
18414
+ const validateFilesField = async (config, compilerCtx, buildCtx) => {
18415
+ const distDirs = getDistributableOutputDirs(config, buildCtx);
18416
+ if (distDirs.length === 0) return;
18417
+ const formatDirs = (dirs) => dirs.map((dir) => `"${dir}/"`).join(", ");
18418
+ if (!Array.isArray(buildCtx.packageJson.files)) {
18419
+ const npmignorePath = join$2(dirname$1(config.packageJsonFilePath), ".npmignore");
18420
+ if (!await compilerCtx.fs.access(npmignorePath)) {
18421
+ const msg = `package.json is missing a "files" array. Without one, "npm publish" falls back to ".gitignore" to decide what to include, which will likely exclude ${distDirs.length > 1 ? "the distribution directories" : "the distribution directory"} ${formatDirs(distDirs)}. Add a "files" array covering ${distDirs.length > 1 ? "them" : "it"} to package.json (or add a ".npmignore").`;
18422
+ packageJsonWarn(config, compilerCtx, buildCtx, msg, `"files"`);
18423
+ }
18424
+ return;
18425
+ }
18426
+ const files = buildCtx.packageJson.files;
18427
+ const uncoveredDirs = distDirs.filter((dir) => !isDirCoveredByFiles(files, dir));
18428
+ if (uncoveredDirs.length > 0) {
18429
+ const msg = `package.json "files" array must contain the distribution ${uncoveredDirs.length > 1 ? "directories" : "directory"} ${formatDirs(uncoveredDirs)} when generating a distribution.`;
18067
18430
  packageJsonWarn(config, compilerCtx, buildCtx, msg, `"files"`);
18068
18431
  return;
18069
18432
  }
18070
- await Promise.all(buildCtx.packageJson.files.map(async (pkgFile) => {
18433
+ await Promise.all(files.map(async (pkgFile) => {
18071
18434
  if (!isGlob(pkgFile)) {
18072
18435
  const packageJsonDir = dirname$1(config.packageJsonFilePath);
18073
18436
  const absPath = join$2(packageJsonDir, pkgFile);
@@ -18182,6 +18545,24 @@ const validateBuildFiles = (config, compilerCtx, buildCtx) => {
18182
18545
  //#endregion
18183
18546
  //#region src/compiler/build/write-export-maps.ts
18184
18547
  /**
18548
+ * Create the shared {@link NpmPkgSet} used across a single `writeExportMaps` run.
18549
+ * @param buildCtx The build context to report a warning diagnostic on if `npm` can't be run
18550
+ * @returns A function that shells out to `npm pkg set`, swallowing failure after warning once
18551
+ */
18552
+ const createNpmPkgSet = (buildCtx) => {
18553
+ let npmAvailable = true;
18554
+ return (cmd) => {
18555
+ if (!npmAvailable) return;
18556
+ try {
18557
+ execSync(`npm pkg set ${cmd}`);
18558
+ } catch (e) {
18559
+ npmAvailable = false;
18560
+ const warn = buildWarn(buildCtx.diagnostics);
18561
+ warn.messageText = `Unable to generate "exports" map in package.json: the "npm" CLI could not be run (${e.message ?? e}). Set "generateExportMaps: false" in your Stencil config to silence this warning.`;
18562
+ }
18563
+ };
18564
+ };
18565
+ /**
18185
18566
  * Create export map entry point definitions for the `package.json` file using the npm CLI.
18186
18567
  *
18187
18568
  * In v5, this uses a "smart default" approach:
@@ -18192,15 +18573,17 @@ const validateBuildFiles = (config, compilerCtx, buildCtx) => {
18192
18573
  * - Generate per-component exports for standalone output
18193
18574
  *
18194
18575
  * @param config The validated Stencil config
18576
+ * @param compilerCtx The compiler context (used to detect a user-authored src/index.ts)
18195
18577
  * @param buildCtx The build context containing the components to generate export maps for
18196
18578
  */
18197
- const writeExportMaps = (config, buildCtx) => {
18579
+ const writeExportMaps = (config, compilerCtx, buildCtx) => {
18198
18580
  const loaderBundle = config.outputTargets.find(isOutputTargetLoaderBundle);
18199
18581
  const standalone = config.outputTargets.find(isOutputTargetStandalone);
18200
18582
  const types = config.outputTargets.find(isOutputTargetTypes);
18201
- generateRootExport(config, buildCtx, loaderBundle, standalone, types);
18202
- if (loaderBundle) generateLoaderExport(config, loaderBundle, types);
18203
- if (standalone) generateComponentExports(config, buildCtx, standalone);
18583
+ const npmPkgSet = createNpmPkgSet(buildCtx);
18584
+ generateRootExport(config, compilerCtx, buildCtx, loaderBundle, standalone, types, npmPkgSet);
18585
+ if (loaderBundle) generateLoaderExport(config, loaderBundle, types, npmPkgSet);
18586
+ if (standalone) generateComponentExports(config, buildCtx, standalone, npmPkgSet);
18204
18587
  };
18205
18588
  /**
18206
18589
  * Generate the root export `exports["."]`.
@@ -18210,28 +18593,32 @@ const writeExportMaps = (config, buildCtx) => {
18210
18593
  * - If valid, leave it alone
18211
18594
  * - If missing or invalid, set default (loader-bundle > standalone priority)
18212
18595
  * @param config The validated Stencil config
18596
+ * @param compilerCtx The compiler context (used to detect a user-authored src/index.ts)
18213
18597
  * @param buildCtx The build context containing the components to generate export maps for
18214
18598
  * @param loaderBundle The loader-bundle output target, if it exists
18215
18599
  * @param standalone The standalone output target, if it exists
18216
18600
  * @param types The types output target, if it exists
18601
+ * @param npmPkgSet Function used to run `npm pkg set`, tolerating an unavailable npm CLI
18217
18602
  */
18218
- const generateRootExport = (config, buildCtx, loaderBundle, standalone, types) => {
18603
+ const generateRootExport = (config, compilerCtx, buildCtx, loaderBundle, standalone, types, npmPkgSet) => {
18219
18604
  if (!loaderBundle && !standalone) return;
18605
+ const hasSrcIndex = compilerCtx.fs.accessSync(join$2(config.srcDir, "index.ts"));
18606
+ const rootUsesEmptyLoaderIndex = !!loaderBundle && !hasSrcIndex;
18220
18607
  const currentImport = ((buildCtx.packageJson?.exports)?.["."])?.import;
18221
18608
  if (!(currentImport && isValidRootExport(config, currentImport, loaderBundle, standalone))) {
18222
18609
  const primaryDir = loaderBundle?.dir ?? standalone?.dir;
18223
18610
  if (primaryDir) {
18224
- const importPath = normalizePath(relative$1(config.rootDir, join$2(primaryDir, "index.js")));
18225
- execSync(`npm pkg set "exports[.][import]"="${importPath}"`);
18611
+ const entryFile = rootUsesEmptyLoaderIndex ? join$2("esm", "loader.js") : "index.js";
18612
+ npmPkgSet(`"exports[.][import]"="${normalizePath(relative$1(config.rootDir, join$2(primaryDir, entryFile)))}"`);
18226
18613
  if (loaderBundle?.cjs) {
18227
- const requirePath = normalizePath(relative$1(config.rootDir, join$2(loaderBundle.dir, "index.cjs")));
18228
- execSync(`npm pkg set "exports[.][require]"="${requirePath}"`);
18614
+ const cjsEntryFile = rootUsesEmptyLoaderIndex ? join$2("cjs", "loader.cjs") : "index.cjs";
18615
+ npmPkgSet(`"exports[.][require]"="${normalizePath(relative$1(config.rootDir, join$2(loaderBundle.dir, cjsEntryFile)))}"`);
18229
18616
  }
18230
18617
  }
18231
18618
  }
18232
18619
  if (types?.dir) {
18233
- const typesPath = normalizePath(relative$1(config.rootDir, join$2(types.dir, "index.d.ts")));
18234
- execSync(`npm pkg set "exports[.][types]"="${typesPath}"`);
18620
+ const typesFile = rootUsesEmptyLoaderIndex ? "loader.d.ts" : "index.d.ts";
18621
+ npmPkgSet(`"exports[.][types]"="${normalizePath(relative$1(config.rootDir, join$2(types.dir, typesFile)))}"`);
18235
18622
  }
18236
18623
  };
18237
18624
  /**
@@ -18274,20 +18661,16 @@ const ensureRelativePrefix = (path) => {
18274
18661
  * @param config The validated Stencil config
18275
18662
  * @param loaderBundle The loader-bundle output target
18276
18663
  * @param types The types output target, if it exists
18664
+ * @param npmPkgSet Function used to run `npm pkg set`, tolerating an unavailable npm CLI
18277
18665
  */
18278
- const generateLoaderExport = (config, loaderBundle, types) => {
18666
+ const generateLoaderExport = (config, loaderBundle, types, npmPkgSet) => {
18279
18667
  const esmDir = join$2(loaderBundle.dir, "esm");
18280
- const esmLoaderPath = ensureRelativePrefix(normalizePath(relative$1(config.rootDir, join$2(esmDir, "loader.js"))));
18281
- execSync(`npm pkg set "exports[./loader][import]"="${esmLoaderPath}"`);
18668
+ npmPkgSet(`"exports[./loader][import]"="${ensureRelativePrefix(normalizePath(relative$1(config.rootDir, join$2(esmDir, "loader.js"))))}"`);
18282
18669
  if (loaderBundle.cjs) {
18283
18670
  const cjsDir = join$2(loaderBundle.dir, "cjs");
18284
- const cjsLoaderPath = ensureRelativePrefix(normalizePath(relative$1(config.rootDir, join$2(cjsDir, "loader.cjs"))));
18285
- execSync(`npm pkg set "exports[./loader][require]"="${cjsLoaderPath}"`);
18286
- }
18287
- if (types?.dir) {
18288
- const typesPath = ensureRelativePrefix(normalizePath(relative$1(config.rootDir, join$2(types.dir, "loader.d.ts"))));
18289
- execSync(`npm pkg set "exports[./loader][types]"="${typesPath}"`);
18671
+ npmPkgSet(`"exports[./loader][require]"="${ensureRelativePrefix(normalizePath(relative$1(config.rootDir, join$2(cjsDir, "loader.cjs"))))}"`);
18290
18672
  }
18673
+ if (types?.dir) npmPkgSet(`"exports[./loader][types]"="${ensureRelativePrefix(normalizePath(relative$1(config.rootDir, join$2(types.dir, "loader.d.ts"))))}"`);
18291
18674
  };
18292
18675
  /**
18293
18676
  * Generate per-component exports for standalone output.
@@ -18295,13 +18678,14 @@ const generateLoaderExport = (config, loaderBundle, types) => {
18295
18678
  * @param config The validated Stencil config
18296
18679
  * @param buildCtx The build context containing the components to generate export maps for
18297
18680
  * @param standalone The standalone output target
18681
+ * @param npmPkgSet Function used to run `npm pkg set`, tolerating an unavailable npm CLI
18298
18682
  */
18299
- const generateComponentExports = (config, buildCtx, standalone) => {
18683
+ const generateComponentExports = (config, buildCtx, standalone, npmPkgSet) => {
18300
18684
  let outDir = relative$1(config.rootDir, standalone.dir);
18301
18685
  if (!outDir.startsWith(".")) outDir = "./" + outDir;
18302
18686
  buildCtx.components.forEach((cmp) => {
18303
- execSync(`npm pkg set "exports[./${cmp.tagName}][import]"="${outDir}/${cmp.tagName}.js"`);
18304
- execSync(`npm pkg set "exports[./${cmp.tagName}][types]"="${outDir}/${cmp.tagName}.d.ts"`);
18687
+ npmPkgSet(`"exports[./${cmp.tagName}][import]"="${outDir}/${cmp.tagName}.js"`);
18688
+ npmPkgSet(`"exports[./${cmp.tagName}][types]"="${outDir}/${cmp.tagName}.d.ts"`);
18305
18689
  });
18306
18690
  };
18307
18691
  //#endregion
@@ -18325,7 +18709,7 @@ const writeBuild = async (config, compilerCtx, buildCtx) => {
18325
18709
  await compilerCtx.cache.commit();
18326
18710
  buildCtx.debug(`in-memory-fs: ${compilerCtx.fs.getMemoryStats()}`);
18327
18711
  buildCtx.debug(`cache: ${compilerCtx.cache.getMemoryStats()}`);
18328
- if (config.generateExportMaps) writeExportMaps(config, buildCtx);
18712
+ if (config.generateExportMaps && !config.devMode) writeExportMaps(config, compilerCtx, buildCtx);
18329
18713
  await outputServiceWorkers(config, buildCtx);
18330
18714
  await validateBuildFiles(config, compilerCtx, buildCtx);
18331
18715
  } catch (e) {
@@ -20360,10 +20744,11 @@ const validateConfig = (userConfig = {}, bootstrapConfig) => {
20360
20744
  const devMode = isBoolean$1(config.devMode) ? config.devMode : false;
20361
20745
  config._isTesting = !!(process.env.VITEST || process.env.PLAYWRIGHT_TEST || process.env.TEST_WORKER_INDEX || process.env.TEST_PARALLEL_INDEX || process.env.NODE_ENV === "test");
20362
20746
  const sys = config.sys ?? bootstrapConfig.sys ?? createNodeSys({ logger });
20747
+ const hasExplicitGlobalStyleWithInput = (config.outputTargets || []).some((o) => isOutputTargetGlobalStyle(o) && isString$1(o.input));
20363
20748
  if ((!isString$1(config.globalStyle) || !isString$1(config.globalScript)) && typeof sys.accessSync === "function") {
20364
20749
  const preRootDir = typeof config.rootDir !== "string" ? "/" : config.rootDir;
20365
20750
  const srcDir = typeof config.srcDir === "string" ? isAbsolute$1(config.srcDir) ? config.srcDir : join$1(preRootDir, config.srcDir) : join$1(preRootDir, "src");
20366
- if (!isString$1(config.globalStyle)) for (const ext of STYLE_EXT) {
20751
+ if (!isString$1(config.globalStyle) && !hasExplicitGlobalStyleWithInput) for (const ext of STYLE_EXT) {
20367
20752
  const candidate = join$1(srcDir, `global.${ext}`);
20368
20753
  if (sys.accessSync(candidate)) {
20369
20754
  config.globalStyle = candidate;
@@ -20383,12 +20768,13 @@ const validateConfig = (userConfig = {}, bootstrapConfig) => {
20383
20768
  ...config,
20384
20769
  devMode,
20385
20770
  compat: config.compat || {},
20386
- generateExportMaps: isBoolean$1(config.generateExportMaps) ? config.generateExportMaps : false,
20771
+ generateExportMaps: isBoolean$1(config.generateExportMaps) ? config.generateExportMaps : !isString$1(config.configPath),
20387
20772
  hydratedFlag: validateHydrated(config),
20388
20773
  logLevel,
20389
20774
  logger,
20390
20775
  minifyCss: config.minifyCss ?? !devMode,
20391
20776
  minifyJs: config.minifyJs ?? !devMode,
20777
+ jsMinifier: config.jsMinifier ?? "oxc",
20392
20778
  outputTargets: config.outputTargets ?? [],
20393
20779
  rolldownConfig: validateRolldownConfig(config),
20394
20780
  sourceMap: config.sourceMap === true || devMode && (config.sourceMap === "dev" || typeof config.sourceMap === "undefined"),
@@ -22897,29 +23283,36 @@ const generateTransformCssToEsm = (input, results) => {
22897
23283
  results.styleText = results.styleText.replace(/\\/g, "\\\\").replace(/\n/g, " ").replace(/\r/g, " ").replace(/\t/g, " ").replace(/\u000c/g, "\\\\f").replace(/\u0008/g, "\\\\b").replace(/\u000b/g, "\\\\v").replace(/\0/g, "\\\\0").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
22898
23284
  if (input.addTagTransformers) results.styleText = addTagTransformToCssString(results.styleText, input.tags);
22899
23285
  results.styleText = stripCssComments(results.styleText);
23286
+ const isComponentStyle = isString$1(input.tag);
23287
+ const defaultAssignment = `const ${results.defaultVarName} = ${isComponentStyle ? "() => " : ""}`;
22900
23288
  if (input.module === "cjs") {
22901
23289
  if (input.addTagTransformers) s.append(`const ${TRANSFORM_TAG} = require('${STENCIL_CORE_ID}').transformTag;\n`);
23290
+ if (!isComponentStyle) s.append(`const ${INJECT_SIDE_EFFECT_STYLE} = require('${STENCIL_CORE_ID}').injectSideEffectStyle;\n`);
22902
23291
  results.imports.forEach((cssImport) => {
22903
23292
  s.append(`const ${cssImport.varName} = require('${cssImport.importPath}');\n`);
22904
23293
  });
22905
- s.append(`const ${results.defaultVarName} = () => `);
23294
+ s.append(defaultAssignment);
22906
23295
  results.imports.forEach((cssImport) => {
22907
23296
  s.append(`${cssImport.varName} + `);
22908
23297
  });
22909
23298
  s.append(`\`${results.styleText}\`;\n`);
23299
+ if (!isComponentStyle) s.append(`${INJECT_SIDE_EFFECT_STYLE}(${results.defaultVarName});\n`);
22910
23300
  s.append(`module.exports = ${results.defaultVarName};`);
22911
23301
  } else {
22912
23302
  if (input.addTagTransformers) s.append(`import { transformTag as ${TRANSFORM_TAG} } from '${STENCIL_CORE_ID}';\n`);
23303
+ if (!isComponentStyle) s.append(`import { injectSideEffectStyle as ${INJECT_SIDE_EFFECT_STYLE} } from '${STENCIL_CORE_ID}';\n`);
22913
23304
  results.imports.forEach((cssImport) => {
22914
23305
  s.append(`import ${cssImport.varName} from '${cssImport.importPath}';\n`);
22915
23306
  });
22916
- s.append(`const ${results.defaultVarName} = () => `);
23307
+ s.append(defaultAssignment);
22917
23308
  results.imports.forEach((cssImport) => {
22918
23309
  s.append(`${cssImport.varName} + `);
22919
23310
  });
22920
23311
  s.append(`\`${results.styleText}\`;\n`);
23312
+ if (!isComponentStyle) s.append(`${INJECT_SIDE_EFFECT_STYLE}(${results.defaultVarName});\n`);
22921
23313
  s.append(`export default ${results.defaultVarName};`);
22922
23314
  }
23315
+ results.moduleSideEffects = !isComponentStyle;
22923
23316
  results.output = s.toString();
22924
23317
  return results;
22925
23318
  };
@@ -22947,6 +23340,7 @@ const getCssToEsmImports = (varNames, cssText, filePath, modeName) => {
22947
23340
  isNodeModule: false
22948
23341
  };
22949
23342
  if (!isLocalCssImport(cssImportData.srcImportText)) continue;
23343
+ else if (cssImportData.url === "stencil-globals" || cssImportData.url === "stencil-hydrate") continue;
22950
23344
  else if (isCssNodeModule(cssImportData.url)) {
22951
23345
  cssImportData.filePath = cssImportData.url.substring(1);
22952
23346
  cssImportData.isNodeModule = true;
@@ -24458,8 +24852,8 @@ const transpileModule = (config, input, transformOpts) => {
24458
24852
  getDefaultLibFileName: () => `lib.d.ts`,
24459
24853
  useCaseSensitiveFileNames: () => false,
24460
24854
  getCanonicalFileName: (fileName) => fileName,
24461
- getCurrentDirectory: () => transformOpts.currentDirectory || process.cwd(),
24462
- getNewLine: () => ts.sys.newLine || "\n",
24855
+ getCurrentDirectory: () => transformOpts.currentDirectory || (typeof process !== "undefined" ? process.cwd() : "/"),
24856
+ getNewLine: () => ts.sys && ts.sys.newLine || "\n",
24463
24857
  fileExists: (fileName) => normalizePath(fileName) === normalizePath(sourceFilePath),
24464
24858
  readFile: () => "",
24465
24859
  directoryExists: () => true,