@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.
- package/dist/app-data/index.d.ts +1 -1
- package/dist/{client-BRu0GtRn.mjs → client-Db2rdxUM.mjs} +34 -13
- package/dist/compiler/browser.d.ts +1534 -0
- package/dist/compiler/browser.js +16472 -0
- package/dist/compiler/index.d.mts +1 -1
- package/dist/compiler/index.mjs +2 -2
- package/dist/compiler/utils/index.d.mts +1 -1
- package/dist/{compiler-NrvbUOX1.mjs → compiler-PoywOlbq.mjs} +570 -176
- package/dist/declarations/stencil-public-compiler.d.ts +20 -4
- package/dist/declarations/stencil-public-runtime.d.ts +21 -5
- package/dist/{index-BOrz3rbJ.d.mts → index-BAP9T4CB.d.mts} +1 -1
- package/dist/{index-DnISpqrd.d.ts → index-BXAcVN2j.d.ts} +3 -11
- package/dist/{index-RrQfiPWK.d.mts → index-BvF31nqP.d.mts} +20 -4
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +82 -2
- package/dist/jsx-runtime.mjs +1 -1
- package/dist/{node-75gQKkFz.mjs → node-BKtLn2R9.mjs} +1 -1
- package/dist/runtime/client/lazy.js +137 -26
- package/dist/runtime/client/runtime.d.ts +30 -12
- package/dist/runtime/client/runtime.js +137 -26
- package/dist/runtime/index.d.ts +28 -2
- package/dist/runtime/index.js +137 -26
- package/dist/runtime/server/index.d.mts +27 -1
- package/dist/runtime/server/index.mjs +135 -24
- package/dist/sys/node/index.d.mts +1 -1
- package/dist/sys/node/index.mjs +1 -1
- package/dist/sys/node/worker.mjs +2 -2
- package/dist/testing/index.d.mts +19 -3
- package/dist/testing/index.mjs +58 -68
- package/package.json +9 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as __require } from "./rolldown-runtime-BhDjJH2R.mjs";
|
|
2
|
-
import { S as HYDRATED_CSS } from "./client-
|
|
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-
|
|
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 ??=
|
|
79
|
-
const getCssColonHostContextRe = () => _cssColonHostContextRe ??=
|
|
80
|
-
const getCssColonSlottedRe = () => _cssColonSlottedRe ??=
|
|
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 (
|
|
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
|
-
|
|
443
|
+
const commentSelectors = (input) => processRules(input, (rule) => {
|
|
441
444
|
if (rule.selector[0] !== "@") return processCommentedSelector(rule);
|
|
442
|
-
|
|
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.
|
|
464
|
-
const buildId = "
|
|
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 = "${
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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
|
-
|
|
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: "
|
|
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(
|
|
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(
|
|
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, "
|
|
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
|
-
|
|
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
|
|
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
|
-
...
|
|
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
|
-
|
|
10119
|
-
if (config.outputTargets.some(
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
15255
|
-
*
|
|
15256
|
-
*
|
|
15257
|
-
*
|
|
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
|
|
15260
|
-
* @returns the found class
|
|
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(
|
|
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,
|
|
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))
|
|
15538
|
-
|
|
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,
|
|
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.
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
17919
|
-
|
|
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
|
-
*
|
|
18038
|
-
*
|
|
18039
|
-
* @param
|
|
18040
|
-
* @param
|
|
18041
|
-
* @
|
|
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
|
|
18045
|
-
|
|
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`
|
|
18049
|
-
*
|
|
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
|
|
18056
|
-
|
|
18057
|
-
|
|
18058
|
-
|
|
18059
|
-
|
|
18060
|
-
const
|
|
18061
|
-
if (
|
|
18062
|
-
|
|
18063
|
-
|
|
18064
|
-
|
|
18065
|
-
|
|
18066
|
-
|
|
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(
|
|
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
|
-
|
|
18202
|
-
|
|
18203
|
-
if (
|
|
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
|
|
18225
|
-
|
|
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
|
|
18228
|
-
|
|
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
|
|
18234
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18304
|
-
|
|
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 :
|
|
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(
|
|
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(
|
|
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,
|