@lwrjs/static 0.15.0-alpha.9 → 0.15.0
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/build/cjs/providers/static-bundle-provider.cjs +102 -29
- package/build/cjs/providers/static-module-provider.cjs +11 -4
- package/build/cjs/site-metadata.cjs +7 -2
- package/build/cjs/tools/dedupe-bundles.cjs +1 -1
- package/build/cjs/utils/decision-tree.cjs +13 -5
- package/build/es/providers/static-bundle-provider.d.ts +23 -4
- package/build/es/providers/static-bundle-provider.js +105 -40
- package/build/es/providers/static-module-provider.js +6 -4
- package/build/es/site-metadata.d.ts +5 -3
- package/build/es/site-metadata.js +9 -5
- package/build/es/tools/dedupe-bundles.js +1 -1
- package/build/es/utils/decision-tree.d.ts +8 -2
- package/build/es/utils/decision-tree.js +31 -12
- package/package.json +8 -6
|
@@ -30,9 +30,13 @@ var import_diagnostics = __toModule(require("@lwrjs/diagnostics"));
|
|
|
30
30
|
var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
31
31
|
var import_path = __toModule(require("path"));
|
|
32
32
|
var import_fs_extra = __toModule(require("fs-extra"));
|
|
33
|
+
var import_lru_cache = __toModule(require("lru-cache"));
|
|
33
34
|
var import_site_metadata = __toModule(require("../site-metadata.cjs"));
|
|
35
|
+
var import_instrumentation = __toModule(require("@lwrjs/instrumentation"));
|
|
36
|
+
var import_instrumentation2 = __toModule(require("@lwrjs/instrumentation"));
|
|
37
|
+
var BUNDLE_SOURCE_NOT_FOUND = "Bundle Source Path Not Found";
|
|
34
38
|
var StaticBundleProvider = class {
|
|
35
|
-
constructor(
|
|
39
|
+
constructor(config, context) {
|
|
36
40
|
this.name = "static-bundle-provider";
|
|
37
41
|
if (!context.siteMetadata) {
|
|
38
42
|
throw new Error(`[${this.name}] Site metadata was not found`);
|
|
@@ -41,6 +45,19 @@ var StaticBundleProvider = class {
|
|
|
41
45
|
this.siteRootDir = context.siteMetadata.getSiteRootDir();
|
|
42
46
|
this.bundleConfig = context.config.bundleConfig;
|
|
43
47
|
this.i18n = context.config.i18n;
|
|
48
|
+
this.bundleCacheSize = config.bundleCacheSize ?? parseInt(process.env.BUNDLE_CACHE_SIZE ?? "500", 10);
|
|
49
|
+
if (this.bundleCacheSize > 0) {
|
|
50
|
+
this.codeCache = new import_lru_cache.LRUCache({
|
|
51
|
+
max: this.bundleCacheSize,
|
|
52
|
+
dispose: (_value, key) => {
|
|
53
|
+
if ((0, import_shared_utils.isLambdaEnv)()) {
|
|
54
|
+
import_diagnostics.logger.warn(`Bundle Code evicted from cache ${key}`);
|
|
55
|
+
} else {
|
|
56
|
+
import_diagnostics.logger.verbose(`Bundle Code evicted from cache ${key}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
44
61
|
}
|
|
45
62
|
async bundle(moduleId, runtimeEnvironment, runtimeParams) {
|
|
46
63
|
const {specifier, name, namespace, version} = moduleId;
|
|
@@ -49,25 +66,33 @@ var StaticBundleProvider = class {
|
|
|
49
66
|
i18n: {defaultLocale}
|
|
50
67
|
} = runtimeEnvironment;
|
|
51
68
|
const localeId = runtimeParams?.locale || defaultLocale;
|
|
52
|
-
const
|
|
69
|
+
const ssr = runtimeParams?.ssr;
|
|
70
|
+
const metadata = this.getBundleMetadata({moduleId, localeId, debug, ssr});
|
|
53
71
|
if (!metadata) {
|
|
54
72
|
return void 0;
|
|
55
73
|
}
|
|
56
74
|
const bundlePath = import_path.default.join(this.siteRootDir, metadata.path);
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
75
|
+
const resolvedBundlePath = this.getCodePath(bundlePath, debug, specifier, version, localeId, ssr);
|
|
76
|
+
const codePromiser = this.getCodePromiser(resolvedBundlePath, {
|
|
77
|
+
specifier,
|
|
78
|
+
version,
|
|
79
|
+
locale: localeId,
|
|
80
|
+
ssr,
|
|
81
|
+
debug
|
|
82
|
+
});
|
|
83
|
+
const imports = metadata.imports.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
|
|
84
|
+
const dynamicImports = metadata.dynamicImports?.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
|
|
60
85
|
const id = (0, import_shared_utils.getSpecifier)(moduleId);
|
|
61
86
|
const exploded = (0, import_shared_utils.explodeSpecifier)(id);
|
|
62
87
|
const resolvedName = name ?? exploded.name;
|
|
63
88
|
const resolvedNamespace = namespace ?? exploded.namespace;
|
|
64
89
|
const resolvedVersion = (0, import_site_metadata.resolveStaticBundleVersion)(metadata.version, version);
|
|
65
90
|
const includedModules = metadata.includedModules?.map((includedId) => {
|
|
66
|
-
const includedModule = this.getModuleReference(includedId, localeId, debug);
|
|
91
|
+
const includedModule = this.getModuleReference(includedId, localeId, debug, ssr);
|
|
67
92
|
return (0, import_shared_utils.getSpecifier)(includedModule);
|
|
68
93
|
}) || [];
|
|
69
94
|
return {
|
|
70
|
-
|
|
95
|
+
getCode: codePromiser,
|
|
71
96
|
id: (0, import_shared_utils.getSpecifier)({
|
|
72
97
|
specifier,
|
|
73
98
|
version: resolvedVersion,
|
|
@@ -88,44 +113,92 @@ var StaticBundleProvider = class {
|
|
|
88
113
|
src: bundlePath
|
|
89
114
|
};
|
|
90
115
|
}
|
|
91
|
-
getBundleMetadata(
|
|
92
|
-
|
|
116
|
+
getBundleMetadata({
|
|
117
|
+
moduleId,
|
|
118
|
+
localeId,
|
|
119
|
+
debug,
|
|
120
|
+
ssr
|
|
121
|
+
}) {
|
|
122
|
+
const siteBundleId = (0, import_site_metadata.getSiteBundleId)(moduleId, localeId, ssr, this.i18n);
|
|
93
123
|
return this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleId, debug);
|
|
94
124
|
}
|
|
95
|
-
getModuleReference(siteBundleIdStr, localeId, debug) {
|
|
125
|
+
getModuleReference(siteBundleIdStr, localeId, debug, ssr) {
|
|
96
126
|
const siteBundleId = (0, import_site_metadata.parseSiteId)(siteBundleIdStr);
|
|
97
127
|
const includedModule = (0, import_shared_utils.explodeSpecifier)(siteBundleId.specifier);
|
|
98
128
|
if (!siteBundleId.variants[import_shared_utils.VERSION_SIGIL]) {
|
|
99
|
-
const importBundleMetadata = this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleIdStr, debug, localeId);
|
|
129
|
+
const importBundleMetadata = this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleIdStr, debug, ssr, localeId);
|
|
100
130
|
includedModule.version = (0, import_site_metadata.resolveStaticBundleVersion)(importBundleMetadata?.version);
|
|
101
131
|
} else {
|
|
102
132
|
includedModule.version = siteBundleId.variants[import_shared_utils.VERSION_SIGIL];
|
|
103
133
|
}
|
|
104
134
|
return includedModule;
|
|
105
135
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
136
|
+
getCodePromiser(bundleSourcePath, {
|
|
137
|
+
specifier,
|
|
138
|
+
version,
|
|
139
|
+
locale,
|
|
140
|
+
ssr,
|
|
141
|
+
debug
|
|
142
|
+
}) {
|
|
143
|
+
const cache = this.codeCache;
|
|
144
|
+
return async () => {
|
|
145
|
+
let code = cache?.get(bundleSourcePath);
|
|
146
|
+
if (!code) {
|
|
147
|
+
try {
|
|
148
|
+
if (bundleSourcePath === BUNDLE_SOURCE_NOT_FOUND) {
|
|
149
|
+
throw new Error(BUNDLE_SOURCE_NOT_FOUND);
|
|
150
|
+
}
|
|
151
|
+
import_instrumentation.cacheCountStore.incrementCacheKey("missedReads");
|
|
152
|
+
await (0, import_instrumentation2.getTracer)().trace({
|
|
153
|
+
name: import_instrumentation2.BundleSpan.ReadBundle,
|
|
154
|
+
attributes: {
|
|
155
|
+
specifier,
|
|
156
|
+
version: version ?? "",
|
|
157
|
+
locale,
|
|
158
|
+
ssr: ssr ? "TRUE" : "FALSE",
|
|
159
|
+
debug: debug ? "TRUE" : "FALSE",
|
|
160
|
+
bundleSourcePath
|
|
161
|
+
}
|
|
162
|
+
}, async () => {
|
|
163
|
+
code = await import_fs_extra.default.readFile(import_path.default.join(bundleSourcePath), "utf-8");
|
|
164
|
+
if (cache) {
|
|
165
|
+
cache.set(bundleSourcePath, code);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
} catch (err) {
|
|
113
169
|
import_diagnostics.logger.warn({
|
|
114
170
|
label: "static-bundle-provider",
|
|
115
|
-
message: `Unexpected code reference: ${specifier}`
|
|
116
|
-
});
|
|
117
|
-
|
|
171
|
+
message: `Unexpected code reference: ${specifier} ${bundleSourcePath}`
|
|
172
|
+
}, err);
|
|
173
|
+
code = `throw new Error('Unexpected code reference: ${specifier} ${bundleSourcePath}');`;
|
|
174
|
+
if (cache) {
|
|
175
|
+
cache.set(bundleSourcePath, code);
|
|
176
|
+
}
|
|
118
177
|
}
|
|
119
|
-
bundleSourcePath = import_path.default.join(this.siteRootDir, metadata.path);
|
|
120
178
|
}
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
179
|
+
return code;
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
getCodePath(bundlePath, debug, specifier, version, localeId, ssr) {
|
|
183
|
+
const isLambda = (0, import_shared_utils.isLambdaEnv)();
|
|
184
|
+
let bundleSourcePath = bundlePath;
|
|
185
|
+
if (debug && isLambda) {
|
|
186
|
+
const metadata = this.getBundleMetadata({
|
|
187
|
+
moduleId: {specifier, version},
|
|
188
|
+
localeId,
|
|
189
|
+
debug: false,
|
|
190
|
+
ssr
|
|
191
|
+
});
|
|
192
|
+
if (!metadata) {
|
|
193
|
+
import_diagnostics.logger.error({
|
|
194
|
+
label: "static-bundle-provider",
|
|
195
|
+
message: `Unexpected code reference: ${specifier}`
|
|
196
|
+
});
|
|
197
|
+
return BUNDLE_SOURCE_NOT_FOUND;
|
|
198
|
+
}
|
|
199
|
+
bundleSourcePath = import_path.default.join(this.siteRootDir, metadata.path);
|
|
128
200
|
}
|
|
201
|
+
return bundleSourcePath;
|
|
129
202
|
}
|
|
130
203
|
};
|
|
131
204
|
var static_bundle_provider_default = StaticBundleProvider;
|
|
@@ -44,7 +44,8 @@ var StaticModuleProvider = class {
|
|
|
44
44
|
}
|
|
45
45
|
async getModule(moduleId, runtimeParams) {
|
|
46
46
|
const localeId = runtimeParams?.locale || this.i18n.defaultLocale;
|
|
47
|
-
const
|
|
47
|
+
const ssr = runtimeParams?.ssr;
|
|
48
|
+
const metadata = this.getBundleMetadata({moduleId, localeId, debug: false, ssr});
|
|
48
49
|
if (metadata && (0, import_shared_utils.isLambdaEnv)()) {
|
|
49
50
|
import_diagnostics.logger.warn({
|
|
50
51
|
label: `${this.name}`,
|
|
@@ -57,7 +58,8 @@ var StaticModuleProvider = class {
|
|
|
57
58
|
async getModuleEntry(moduleId, runtimeParams) {
|
|
58
59
|
const {specifier, version} = moduleId;
|
|
59
60
|
const localeId = runtimeParams?.locale || this.i18n.defaultLocale;
|
|
60
|
-
const
|
|
61
|
+
const ssr = runtimeParams?.ssr;
|
|
62
|
+
const metadata = this.getBundleMetadata({moduleId, localeId, ssr, debug: false});
|
|
61
63
|
if (metadata) {
|
|
62
64
|
import_diagnostics.logger.debug({
|
|
63
65
|
label: `${this.name}`,
|
|
@@ -87,8 +89,13 @@ var StaticModuleProvider = class {
|
|
|
87
89
|
const versionedSpecifier = (0, import_shared_utils.getSpecifier)(moduleId);
|
|
88
90
|
return this.fingerprintIndex[versionedSpecifier] || this.fingerprintIndex[moduleId.specifier];
|
|
89
91
|
}
|
|
90
|
-
getBundleMetadata(
|
|
91
|
-
|
|
92
|
+
getBundleMetadata({
|
|
93
|
+
moduleId,
|
|
94
|
+
localeId,
|
|
95
|
+
debug,
|
|
96
|
+
ssr
|
|
97
|
+
}) {
|
|
98
|
+
const siteBundleId = (0, import_site_metadata.getSiteBundleId)(moduleId, localeId, ssr, this.i18n);
|
|
92
99
|
return this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleId, debug);
|
|
93
100
|
}
|
|
94
101
|
};
|
|
@@ -25,6 +25,7 @@ var __toModule = (module2) => {
|
|
|
25
25
|
__markAsModule(exports);
|
|
26
26
|
__export(exports, {
|
|
27
27
|
SITE_LOCALE_PREFIX: () => SITE_LOCALE_PREFIX,
|
|
28
|
+
SITE_SSR_PREFIX: () => SITE_SSR_PREFIX,
|
|
28
29
|
SITE_VERSION_PREFIX: () => SITE_VERSION_PREFIX,
|
|
29
30
|
SiteMetadataImpl: () => SiteMetadataImpl,
|
|
30
31
|
getSiteBundleId: () => getSiteBundleId,
|
|
@@ -45,6 +46,7 @@ var DEBUG_STATIC_RESOURCE_METADATA_PATH = import_path.default.join(SITE_METADATA
|
|
|
45
46
|
var STATIC_ASSET_METADATA_PATH = import_path.default.join(SITE_METADATA_PATH, "/asset-metadata.json");
|
|
46
47
|
var SITE_VERSION_PREFIX = `|${import_shared_utils.VERSION_SIGIL}/`;
|
|
47
48
|
var SITE_LOCALE_PREFIX = `|${import_shared_utils.LOCALE_SIGIL}/`;
|
|
49
|
+
var SITE_SSR_PREFIX = `|${import_shared_utils.SSR_SIGIL}`;
|
|
48
50
|
var SiteMetadataImpl = class {
|
|
49
51
|
constructor(options) {
|
|
50
52
|
this.options = options;
|
|
@@ -190,6 +192,8 @@ function parseSiteId(input) {
|
|
|
190
192
|
const [sigil, value] = parts[i].split("/");
|
|
191
193
|
if (sigil && value) {
|
|
192
194
|
variants[sigil] = value;
|
|
195
|
+
} else if (sigil) {
|
|
196
|
+
variants[sigil] = "true";
|
|
193
197
|
}
|
|
194
198
|
}
|
|
195
199
|
return {
|
|
@@ -197,12 +201,13 @@ function parseSiteId(input) {
|
|
|
197
201
|
variants
|
|
198
202
|
};
|
|
199
203
|
}
|
|
200
|
-
function getSiteBundleId({specifier, namespace, name = "", version}, locale, i18n) {
|
|
204
|
+
function getSiteBundleId({specifier, namespace, name = "", version}, locale, ssr, i18n) {
|
|
201
205
|
if (!specifier) {
|
|
202
206
|
specifier = namespace ? `${namespace}/${name}` : name;
|
|
203
207
|
}
|
|
204
208
|
const versionedSpecifier = version && version !== import_shared_utils.VERSION_NOT_PROVIDED ? `${specifier}${SITE_VERSION_PREFIX}${(0, import_shared_utils.normalizeVersionToUri)(version)}` : specifier;
|
|
205
|
-
|
|
209
|
+
const ssrSpecifier = ssr ? `${versionedSpecifier}${SITE_SSR_PREFIX}` : versionedSpecifier;
|
|
210
|
+
return i18n?.defaultLocale === locale ? ssrSpecifier : `${ssrSpecifier}${SITE_LOCALE_PREFIX}${locale}`;
|
|
206
211
|
}
|
|
207
212
|
function getSiteResourceId({specifier, version}) {
|
|
208
213
|
const versionedSpecifier = version && version !== import_shared_utils.VERSION_NOT_PROVIDED ? `${specifier}${SITE_VERSION_PREFIX}${(0, import_shared_utils.normalizeVersionToUri)(version)}` : specifier;
|
|
@@ -56,7 +56,7 @@ async function dedupeBundles(rootDir, i18n) {
|
|
|
56
56
|
});
|
|
57
57
|
const locale = i18n.locales.find((l) => l.id === localeId);
|
|
58
58
|
const fallBackLocale = locale?.fallback ?? i18n.defaultLocale;
|
|
59
|
-
const fallbackMetadata = decisionTree.find(siteIdStr, false, fallBackLocale);
|
|
59
|
+
const fallbackMetadata = decisionTree.find(siteIdStr, false, false, fallBackLocale);
|
|
60
60
|
if (fallbackMetadata) {
|
|
61
61
|
const fallbackSrc = import_fs_extra.default.readFileSync(import_path.default.join(rootDir, fallbackMetadata.path));
|
|
62
62
|
import_diagnostics.logger.debug({
|
|
@@ -32,6 +32,7 @@ var import_shared_utils = __toModule(require("@lwrjs/shared-utils"));
|
|
|
32
32
|
var import_site_metadata = __toModule(require("../site-metadata.cjs"));
|
|
33
33
|
var CHOICE_WILDCARD = "*";
|
|
34
34
|
var CHOICE_EMPTY = "";
|
|
35
|
+
var CHOICE_TRUE = "true";
|
|
35
36
|
var CHOICE_PROD = "prod";
|
|
36
37
|
var CHOICE_DEBUG = "debug";
|
|
37
38
|
var DecisionTreeImpl = class {
|
|
@@ -77,11 +78,12 @@ var DecisionTreeImpl = class {
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
|
-
find(siteArtifactId, debug, localeId) {
|
|
81
|
+
find(siteArtifactId, debug, ssr, localeId) {
|
|
81
82
|
const parsedArtifactId = (0, import_site_metadata.parseSiteId)(siteArtifactId);
|
|
82
83
|
const decisionPath = this.createArtifactChoices({
|
|
83
84
|
specifier: parsedArtifactId.specifier,
|
|
84
85
|
version: parsedArtifactId.variants[import_shared_utils.VERSION_SIGIL],
|
|
86
|
+
ssr: ssr ?? import_shared_utils.SSR_SIGIL in parsedArtifactId.variants,
|
|
85
87
|
localeId: localeId ?? parsedArtifactId.variants[import_shared_utils.LOCALE_SIGIL],
|
|
86
88
|
debug
|
|
87
89
|
});
|
|
@@ -99,11 +101,15 @@ var DecisionTreeImpl = class {
|
|
|
99
101
|
}
|
|
100
102
|
return currentNode.artifact;
|
|
101
103
|
}
|
|
102
|
-
createArtifactChoices({specifier, version, localeId, debug}) {
|
|
104
|
+
createArtifactChoices({specifier, version, localeId, debug, ssr}) {
|
|
103
105
|
const envChoice = debug ? CHOICE_DEBUG : CHOICE_PROD;
|
|
104
106
|
const versionChoice = getVersionChoice(version);
|
|
105
107
|
const uriVersion = (0, import_shared_utils.normalizeVersionToUri)(versionChoice);
|
|
106
|
-
|
|
108
|
+
const ssrChoice = ssr ? CHOICE_TRUE : CHOICE_EMPTY;
|
|
109
|
+
return this.getOrderedChoices(specifier, envChoice, ssrChoice, uriVersion, localeId);
|
|
110
|
+
}
|
|
111
|
+
getOrderedChoices(specifier, envChoice, ssrChoice, uriVersion, localeId) {
|
|
112
|
+
return [specifier, envChoice, ssrChoice, uriVersion, localeId || CHOICE_WILDCARD];
|
|
107
113
|
}
|
|
108
114
|
createPossibleArtifactChoices({
|
|
109
115
|
id,
|
|
@@ -118,9 +124,11 @@ var DecisionTreeImpl = class {
|
|
|
118
124
|
const versionChoice = getVersionChoice(match.variants[import_shared_utils.VERSION_SIGIL]);
|
|
119
125
|
const versions = versionChoice === CHOICE_EMPTY ? [...new Set([CHOICE_EMPTY, CHOICE_WILDCARD])] : [...new Set([versionChoice, CHOICE_EMPTY])];
|
|
120
126
|
const envChoice = debug ? [CHOICE_DEBUG] : [CHOICE_PROD];
|
|
127
|
+
const ssrChoice = match.variants[import_shared_utils.SSR_SIGIL] || CHOICE_EMPTY;
|
|
128
|
+
const ssr = (0, import_shared_utils.getFeatureFlags)().SSR_COMPILER_ENABLED ? [ssrChoice] : ssrChoice ? [ssrChoice, CHOICE_WILDCARD] : [CHOICE_WILDCARD];
|
|
121
129
|
const localeChoice = match.variants[import_shared_utils.LOCALE_SIGIL];
|
|
122
|
-
const localeId =
|
|
123
|
-
return [
|
|
130
|
+
const localeId = localeFallbacks?.[localeChoice] ?? [CHOICE_WILDCARD];
|
|
131
|
+
return this.getOrderedChoices([specifier], envChoice, ssr, versions, localeId);
|
|
124
132
|
}
|
|
125
133
|
};
|
|
126
134
|
var decision_tree_default = DecisionTreeImpl;
|
|
@@ -1,26 +1,45 @@
|
|
|
1
1
|
import type { AbstractModuleId, BundleDefinition, BundleProvider, ProviderContext, RuntimeEnvironment, RuntimeParams, SiteBundle, SiteMetadata } from '@lwrjs/types';
|
|
2
|
+
import { LRUCache } from 'lru-cache';
|
|
2
3
|
export default class StaticBundleProvider implements BundleProvider {
|
|
3
4
|
name: string;
|
|
5
|
+
codeCache: LRUCache<string, string, unknown> | undefined;
|
|
4
6
|
siteRootDir: string;
|
|
5
7
|
bundleConfig: import("@lwrjs/types").BundleConfig;
|
|
6
8
|
i18n: import("@lwrjs/types").I18NConfig;
|
|
7
9
|
siteMetadata: SiteMetadata;
|
|
8
|
-
|
|
10
|
+
bundleCacheSize: number;
|
|
11
|
+
constructor(config: {
|
|
12
|
+
bundleCacheSize?: number;
|
|
13
|
+
}, context: ProviderContext);
|
|
9
14
|
bundle<BundleIdentifier extends AbstractModuleId, RE extends RuntimeEnvironment>(moduleId: BundleIdentifier, runtimeEnvironment: RE, runtimeParams: RuntimeParams): Promise<BundleDefinition | undefined>;
|
|
10
|
-
getBundleMetadata(moduleId
|
|
15
|
+
getBundleMetadata({ moduleId, localeId, debug, ssr, }: {
|
|
16
|
+
moduleId: Partial<AbstractModuleId>;
|
|
17
|
+
localeId: string;
|
|
18
|
+
debug: boolean;
|
|
19
|
+
ssr: boolean;
|
|
20
|
+
}): SiteBundle | undefined;
|
|
11
21
|
/**
|
|
12
22
|
* Takes a key from the site bundle metadata and creates an appropriate runtime BaseModuleReference to use in the LWR runtime.
|
|
13
23
|
*/
|
|
14
24
|
private getModuleReference;
|
|
25
|
+
getCodePromiser(bundleSourcePath: string, { specifier, version, locale, ssr, debug, }: {
|
|
26
|
+
specifier: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
locale: string;
|
|
29
|
+
ssr: boolean;
|
|
30
|
+
debug: boolean;
|
|
31
|
+
}): () => Promise<string>;
|
|
15
32
|
/**
|
|
16
|
-
* Get the source code for the a static bundle
|
|
33
|
+
* Get the local source code path for the a static bundle
|
|
17
34
|
* If we are running in a lambda and the mode is debug we will return the prod source code instead of the debug source code
|
|
18
35
|
*
|
|
19
36
|
* @param bundlePath The default path for the bundle for prod read from .metadata/bundle-metadata.json, for debug .metadata/bundle-metadata-debug.json
|
|
20
37
|
* @param debug Is the request in debug mode?
|
|
21
38
|
* @param specifier Root specifier for the requested bundle
|
|
39
|
+
* @param version Root specifier version
|
|
22
40
|
* @param localeId Locale id (e.g. en-US) for the current request
|
|
41
|
+
* @param ssr True if this is a server bundle
|
|
23
42
|
*/
|
|
24
|
-
|
|
43
|
+
getCodePath(bundlePath: string, debug: boolean, specifier: string, version: string | undefined, localeId: string, ssr: boolean): string;
|
|
25
44
|
}
|
|
26
45
|
//# sourceMappingURL=static-bundle-provider.d.ts.map
|
|
@@ -2,9 +2,13 @@ import { logger } from '@lwrjs/diagnostics';
|
|
|
2
2
|
import { VERSION_SIGIL, explodeSpecifier, getSpecifier, isLambdaEnv } from '@lwrjs/shared-utils';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
|
+
import { LRUCache } from 'lru-cache';
|
|
5
6
|
import { getSiteBundleId, parseSiteId, resolveStaticBundleVersion } from '../site-metadata.js';
|
|
7
|
+
import { cacheCountStore } from '@lwrjs/instrumentation';
|
|
8
|
+
import { getTracer, BundleSpan } from '@lwrjs/instrumentation';
|
|
9
|
+
const BUNDLE_SOURCE_NOT_FOUND = 'Bundle Source Path Not Found';
|
|
6
10
|
export default class StaticBundleProvider {
|
|
7
|
-
constructor(
|
|
11
|
+
constructor(config, context) {
|
|
8
12
|
this.name = 'static-bundle-provider';
|
|
9
13
|
if (!context.siteMetadata) {
|
|
10
14
|
throw new Error(`[${this.name}] Site metadata was not found`);
|
|
@@ -13,21 +17,43 @@ export default class StaticBundleProvider {
|
|
|
13
17
|
this.siteRootDir = context.siteMetadata.getSiteRootDir();
|
|
14
18
|
this.bundleConfig = context.config.bundleConfig;
|
|
15
19
|
this.i18n = context.config.i18n;
|
|
20
|
+
this.bundleCacheSize = config.bundleCacheSize ?? parseInt(process.env.BUNDLE_CACHE_SIZE ?? '500', 10);
|
|
21
|
+
if (this.bundleCacheSize > 0) {
|
|
22
|
+
this.codeCache = new LRUCache({
|
|
23
|
+
max: this.bundleCacheSize,
|
|
24
|
+
dispose: (_value, key) => {
|
|
25
|
+
if (isLambdaEnv()) {
|
|
26
|
+
logger.warn(`Bundle Code evicted from cache ${key}`);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
logger.verbose(`Bundle Code evicted from cache ${key}`);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
16
34
|
}
|
|
17
35
|
async bundle(moduleId, runtimeEnvironment, runtimeParams) {
|
|
18
36
|
const { specifier, name, namespace, version } = moduleId;
|
|
19
37
|
const { debug, i18n: { defaultLocale }, } = runtimeEnvironment;
|
|
20
38
|
const localeId = (runtimeParams?.locale || defaultLocale);
|
|
21
|
-
const
|
|
39
|
+
const ssr = runtimeParams?.ssr;
|
|
40
|
+
const metadata = this.getBundleMetadata({ moduleId, localeId, debug, ssr });
|
|
22
41
|
if (!metadata) {
|
|
23
42
|
return undefined;
|
|
24
43
|
}
|
|
25
44
|
// Default bundle source path
|
|
26
45
|
const bundlePath = path.join(this.siteRootDir, metadata.path);
|
|
27
46
|
// Get the associated bundle source code
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
47
|
+
const resolvedBundlePath = this.getCodePath(bundlePath, debug, specifier, version, localeId, ssr);
|
|
48
|
+
const codePromiser = this.getCodePromiser(resolvedBundlePath, {
|
|
49
|
+
specifier,
|
|
50
|
+
version,
|
|
51
|
+
locale: localeId,
|
|
52
|
+
ssr,
|
|
53
|
+
debug,
|
|
54
|
+
});
|
|
55
|
+
const imports = metadata.imports.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
|
|
56
|
+
const dynamicImports = metadata.dynamicImports?.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
|
|
31
57
|
const id = getSpecifier(moduleId);
|
|
32
58
|
const exploded = explodeSpecifier(id);
|
|
33
59
|
// Seem unlikely name was not in the moduleId but just incase set it form the exploded id
|
|
@@ -35,11 +61,11 @@ export default class StaticBundleProvider {
|
|
|
35
61
|
const resolvedNamespace = namespace ?? exploded.namespace;
|
|
36
62
|
const resolvedVersion = resolveStaticBundleVersion(metadata.version, version);
|
|
37
63
|
const includedModules = metadata.includedModules?.map((includedId) => {
|
|
38
|
-
const includedModule = this.getModuleReference(includedId, localeId, debug);
|
|
64
|
+
const includedModule = this.getModuleReference(includedId, localeId, debug, ssr);
|
|
39
65
|
return getSpecifier(includedModule);
|
|
40
66
|
}) || [];
|
|
41
67
|
return {
|
|
42
|
-
|
|
68
|
+
getCode: codePromiser,
|
|
43
69
|
id: getSpecifier({
|
|
44
70
|
specifier: specifier,
|
|
45
71
|
version: resolvedVersion,
|
|
@@ -61,20 +87,20 @@ export default class StaticBundleProvider {
|
|
|
61
87
|
src: bundlePath,
|
|
62
88
|
};
|
|
63
89
|
}
|
|
64
|
-
getBundleMetadata(moduleId, localeId, debug) {
|
|
65
|
-
const siteBundleId = getSiteBundleId(moduleId, localeId, this.i18n);
|
|
90
|
+
getBundleMetadata({ moduleId, localeId, debug, ssr, }) {
|
|
91
|
+
const siteBundleId = getSiteBundleId(moduleId, localeId, ssr, this.i18n);
|
|
66
92
|
return this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleId, debug);
|
|
67
93
|
}
|
|
68
94
|
/**
|
|
69
95
|
* Takes a key from the site bundle metadata and creates an appropriate runtime BaseModuleReference to use in the LWR runtime.
|
|
70
96
|
*/
|
|
71
|
-
getModuleReference(siteBundleIdStr, localeId, debug) {
|
|
97
|
+
getModuleReference(siteBundleIdStr, localeId, debug, ssr) {
|
|
72
98
|
const siteBundleId = parseSiteId(siteBundleIdStr);
|
|
73
99
|
const includedModule = explodeSpecifier(siteBundleId.specifier);
|
|
74
100
|
if (!siteBundleId.variants[VERSION_SIGIL]) {
|
|
75
101
|
const importBundleMetadata = this.siteMetadata
|
|
76
102
|
.getSiteBundlesDecisionTree()
|
|
77
|
-
.find(siteBundleIdStr, debug, localeId);
|
|
103
|
+
.find(siteBundleIdStr, debug, ssr, localeId);
|
|
78
104
|
includedModule.version = resolveStaticBundleVersion(importBundleMetadata?.version);
|
|
79
105
|
}
|
|
80
106
|
else {
|
|
@@ -82,49 +108,88 @@ export default class StaticBundleProvider {
|
|
|
82
108
|
}
|
|
83
109
|
return includedModule;
|
|
84
110
|
}
|
|
111
|
+
getCodePromiser(bundleSourcePath, { specifier, version, locale, ssr, debug, }) {
|
|
112
|
+
const cache = this.codeCache;
|
|
113
|
+
return async () => {
|
|
114
|
+
let code = cache?.get(bundleSourcePath);
|
|
115
|
+
if (!code) {
|
|
116
|
+
try {
|
|
117
|
+
// Debug metadata was not found
|
|
118
|
+
if (bundleSourcePath === BUNDLE_SOURCE_NOT_FOUND) {
|
|
119
|
+
throw new Error(BUNDLE_SOURCE_NOT_FOUND);
|
|
120
|
+
}
|
|
121
|
+
// Increment the cache count store
|
|
122
|
+
cacheCountStore.incrementCacheKey('missedReads');
|
|
123
|
+
await getTracer().trace({
|
|
124
|
+
name: BundleSpan.ReadBundle,
|
|
125
|
+
attributes: {
|
|
126
|
+
specifier,
|
|
127
|
+
version: version ?? '',
|
|
128
|
+
locale,
|
|
129
|
+
ssr: ssr ? 'TRUE' : 'FALSE',
|
|
130
|
+
debug: debug ? 'TRUE' : 'FALSE',
|
|
131
|
+
bundleSourcePath,
|
|
132
|
+
},
|
|
133
|
+
}, async () => {
|
|
134
|
+
code = await fs.readFile(path.join(bundleSourcePath), 'utf-8');
|
|
135
|
+
if (cache) {
|
|
136
|
+
cache.set(bundleSourcePath, code);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
// Ran it an un-expected error reading the bundle source code
|
|
142
|
+
logger.warn({
|
|
143
|
+
label: 'static-bundle-provider',
|
|
144
|
+
message: `Unexpected code reference: ${specifier} ${bundleSourcePath}`,
|
|
145
|
+
}, err);
|
|
146
|
+
// Returning source code that throws and error is someone tries to evaluate it
|
|
147
|
+
code = `throw new Error('Unexpected code reference: ${specifier} ${bundleSourcePath}');`;
|
|
148
|
+
if (cache) {
|
|
149
|
+
cache.set(bundleSourcePath, code);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return code;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
85
156
|
/**
|
|
86
|
-
* Get the source code for the a static bundle
|
|
157
|
+
* Get the local source code path for the a static bundle
|
|
87
158
|
* If we are running in a lambda and the mode is debug we will return the prod source code instead of the debug source code
|
|
88
159
|
*
|
|
89
160
|
* @param bundlePath The default path for the bundle for prod read from .metadata/bundle-metadata.json, for debug .metadata/bundle-metadata-debug.json
|
|
90
161
|
* @param debug Is the request in debug mode?
|
|
91
162
|
* @param specifier Root specifier for the requested bundle
|
|
163
|
+
* @param version Root specifier version
|
|
92
164
|
* @param localeId Locale id (e.g. en-US) for the current request
|
|
165
|
+
* @param ssr True if this is a server bundle
|
|
93
166
|
*/
|
|
94
|
-
|
|
167
|
+
getCodePath(bundlePath, debug, specifier, version, localeId, ssr) {
|
|
95
168
|
// Flag is used to indicate that we are running on a lambda
|
|
96
169
|
const isLambda = isLambdaEnv();
|
|
97
170
|
// Default source code path determined from metadata based on debug mode
|
|
98
171
|
let bundleSourcePath = bundlePath;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
172
|
+
// This is the special case where the request is in debug mode and we are on the lambda
|
|
173
|
+
// So we will look up the prod source code instead of the debug source code
|
|
174
|
+
if (debug && isLambda) {
|
|
175
|
+
const metadata = this.getBundleMetadata({
|
|
176
|
+
moduleId: { specifier, version },
|
|
177
|
+
localeId,
|
|
178
|
+
debug: false,
|
|
179
|
+
ssr,
|
|
180
|
+
});
|
|
181
|
+
if (!metadata) {
|
|
182
|
+
// We did not find the bundle prod bundle even though we did find it in the debug metadata before
|
|
183
|
+
logger.error({
|
|
184
|
+
label: 'static-bundle-provider',
|
|
185
|
+
message: `Unexpected code reference: ${specifier}`,
|
|
186
|
+
});
|
|
187
|
+
return BUNDLE_SOURCE_NOT_FOUND;
|
|
115
188
|
}
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
// Ran it an un-expected error reading the bundle source code
|
|
121
|
-
logger.warn({
|
|
122
|
-
label: 'static-bundle-provider',
|
|
123
|
-
message: `Unexpected code reference: ${specifier} ${bundleSourcePath}`,
|
|
124
|
-
}, err);
|
|
125
|
-
// Returning source code that throws and error is someone tries to evaluate it
|
|
126
|
-
return `throw new Error('Unexpected code reference: ${specifier} ${bundleSourcePath}');`;
|
|
189
|
+
// Overwrite the default source code path the prod source code path
|
|
190
|
+
bundleSourcePath = path.join(this.siteRootDir, metadata.path);
|
|
127
191
|
}
|
|
192
|
+
return bundleSourcePath;
|
|
128
193
|
}
|
|
129
194
|
}
|
|
130
195
|
//# sourceMappingURL=static-bundle-provider.js.map
|
|
@@ -17,7 +17,8 @@ export default class StaticModuleProvider {
|
|
|
17
17
|
}
|
|
18
18
|
async getModule(moduleId, runtimeParams) {
|
|
19
19
|
const localeId = (runtimeParams?.locale || this.i18n.defaultLocale);
|
|
20
|
-
const
|
|
20
|
+
const ssr = runtimeParams?.ssr;
|
|
21
|
+
const metadata = this.getBundleMetadata({ moduleId, localeId, debug: false, ssr });
|
|
21
22
|
if (metadata && isLambdaEnv()) {
|
|
22
23
|
logger.warn({
|
|
23
24
|
label: `${this.name}`,
|
|
@@ -33,7 +34,8 @@ export default class StaticModuleProvider {
|
|
|
33
34
|
// TODO shouldn't we be passing the runtime environment here to test?
|
|
34
35
|
const { specifier, version } = moduleId;
|
|
35
36
|
const localeId = (runtimeParams?.locale || this.i18n.defaultLocale);
|
|
36
|
-
const
|
|
37
|
+
const ssr = runtimeParams?.ssr;
|
|
38
|
+
const metadata = this.getBundleMetadata({ moduleId, localeId, ssr, debug: false });
|
|
37
39
|
if (metadata) {
|
|
38
40
|
logger.debug({
|
|
39
41
|
label: `${this.name}`,
|
|
@@ -67,8 +69,8 @@ export default class StaticModuleProvider {
|
|
|
67
69
|
const versionedSpecifier = getSpecifier(moduleId);
|
|
68
70
|
return this.fingerprintIndex[versionedSpecifier] || this.fingerprintIndex[moduleId.specifier];
|
|
69
71
|
}
|
|
70
|
-
getBundleMetadata(moduleId, localeId, debug) {
|
|
71
|
-
const siteBundleId = getSiteBundleId(moduleId, localeId, this.i18n);
|
|
72
|
+
getBundleMetadata({ moduleId, localeId, debug, ssr, }) {
|
|
73
|
+
const siteBundleId = getSiteBundleId(moduleId, localeId, ssr, this.i18n);
|
|
72
74
|
return this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleId, debug);
|
|
73
75
|
}
|
|
74
76
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { AbstractModuleId, I18NConfig, ResourceIdentifier, SiteAssets, SiteBundle, SiteBundles, SiteMetadata, SiteResource, SiteResources } from '@lwrjs/types';
|
|
2
2
|
import DecisionTree from './utils/decision-tree.js';
|
|
3
|
-
import { LOCALE_SIGIL, VERSION_SIGIL } from '@lwrjs/shared-utils';
|
|
3
|
+
import { LOCALE_SIGIL, SSR_SIGIL, VERSION_SIGIL } from '@lwrjs/shared-utils';
|
|
4
4
|
type Options = {
|
|
5
5
|
rootDir: string;
|
|
6
6
|
i18n: I18NConfig;
|
|
7
7
|
};
|
|
8
8
|
export declare const SITE_VERSION_PREFIX: string;
|
|
9
9
|
export declare const SITE_LOCALE_PREFIX: string;
|
|
10
|
-
|
|
10
|
+
export declare const SITE_SSR_PREFIX: string;
|
|
11
|
+
type SIGIL = typeof VERSION_SIGIL | typeof SSR_SIGIL | typeof LOCALE_SIGIL;
|
|
11
12
|
interface SiteArtifactId {
|
|
12
13
|
specifier: string;
|
|
13
14
|
variants: Record<SIGIL, string>;
|
|
@@ -64,9 +65,10 @@ export declare function parseSiteId(input: string): SiteArtifactId;
|
|
|
64
65
|
*
|
|
65
66
|
* @param moduleId - Root Module Id
|
|
66
67
|
* @param locale - Current locale
|
|
68
|
+
* @param ssr - Component variant is required for SSR
|
|
67
69
|
* @returns Site Bundle Identifier
|
|
68
70
|
*/
|
|
69
|
-
export declare function getSiteBundleId({ specifier, namespace, name, version }: Partial<AbstractModuleId>, locale?: string, i18n?: I18NConfig): string;
|
|
71
|
+
export declare function getSiteBundleId({ specifier, namespace, name, version }: Partial<AbstractModuleId>, locale?: string, ssr?: boolean, i18n?: I18NConfig): string;
|
|
70
72
|
/**
|
|
71
73
|
* Get a Site Resource Identifier from a Resource Identifier
|
|
72
74
|
*
|
|
@@ -2,7 +2,7 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import { logger } from '@lwrjs/diagnostics';
|
|
4
4
|
import DecisionTree, { createFallbackMap } from './utils/decision-tree.js';
|
|
5
|
-
import { LOCALE_SIGIL, VERSION_NOT_PROVIDED, VERSION_SIGIL, normalizeVersionToUri, } from '@lwrjs/shared-utils';
|
|
5
|
+
import { LOCALE_SIGIL, SSR_SIGIL, VERSION_NOT_PROVIDED, VERSION_SIGIL, normalizeVersionToUri, } from '@lwrjs/shared-utils';
|
|
6
6
|
const SITE_METADATA_PATH = '.metadata';
|
|
7
7
|
const STATIC_BUNDLE_METADATA_PATH = path.join(SITE_METADATA_PATH, '/bundle-metadata.json');
|
|
8
8
|
const DEBUG_STATIC_BUNDLE_METADATA_PATH = path.join(SITE_METADATA_PATH, '/bundle-metadata-debug.json');
|
|
@@ -11,6 +11,7 @@ const DEBUG_STATIC_RESOURCE_METADATA_PATH = path.join(SITE_METADATA_PATH, '/reso
|
|
|
11
11
|
const STATIC_ASSET_METADATA_PATH = path.join(SITE_METADATA_PATH, '/asset-metadata.json');
|
|
12
12
|
export const SITE_VERSION_PREFIX = `|${VERSION_SIGIL}/`;
|
|
13
13
|
export const SITE_LOCALE_PREFIX = `|${LOCALE_SIGIL}/`;
|
|
14
|
+
export const SITE_SSR_PREFIX = `|${SSR_SIGIL}`;
|
|
14
15
|
export class SiteMetadataImpl {
|
|
15
16
|
constructor(options) {
|
|
16
17
|
this.options = options;
|
|
@@ -198,6 +199,9 @@ export function parseSiteId(input) {
|
|
|
198
199
|
if (sigil && value) {
|
|
199
200
|
variants[sigil] = value;
|
|
200
201
|
}
|
|
202
|
+
else if (sigil) {
|
|
203
|
+
variants[sigil] = 'true';
|
|
204
|
+
}
|
|
201
205
|
}
|
|
202
206
|
return {
|
|
203
207
|
specifier: specifier,
|
|
@@ -209,9 +213,10 @@ export function parseSiteId(input) {
|
|
|
209
213
|
*
|
|
210
214
|
* @param moduleId - Root Module Id
|
|
211
215
|
* @param locale - Current locale
|
|
216
|
+
* @param ssr - Component variant is required for SSR
|
|
212
217
|
* @returns Site Bundle Identifier
|
|
213
218
|
*/
|
|
214
|
-
export function getSiteBundleId({ specifier, namespace, name = '', version }, locale, i18n) {
|
|
219
|
+
export function getSiteBundleId({ specifier, namespace, name = '', version }, locale, ssr, i18n) {
|
|
215
220
|
if (!specifier) {
|
|
216
221
|
specifier = namespace ? `${namespace}/${name}` : name;
|
|
217
222
|
}
|
|
@@ -219,9 +224,8 @@ export function getSiteBundleId({ specifier, namespace, name = '', version }, lo
|
|
|
219
224
|
const versionedSpecifier = version && version !== VERSION_NOT_PROVIDED
|
|
220
225
|
? `${specifier}${SITE_VERSION_PREFIX}${normalizeVersionToUri(version)}`
|
|
221
226
|
: specifier;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
: `${versionedSpecifier}${SITE_LOCALE_PREFIX}${locale}`;
|
|
227
|
+
const ssrSpecifier = ssr ? `${versionedSpecifier}${SITE_SSR_PREFIX}` : versionedSpecifier;
|
|
228
|
+
return i18n?.defaultLocale === locale ? ssrSpecifier : `${ssrSpecifier}${SITE_LOCALE_PREFIX}${locale}`;
|
|
225
229
|
}
|
|
226
230
|
/**
|
|
227
231
|
* Get a Site Resource Identifier from a Resource Identifier
|
|
@@ -31,7 +31,7 @@ export async function dedupeBundles(rootDir, i18n) {
|
|
|
31
31
|
// Find the current locale
|
|
32
32
|
const locale = i18n.locales.find((l) => l.id === localeId);
|
|
33
33
|
const fallBackLocale = locale?.fallback ?? i18n.defaultLocale;
|
|
34
|
-
const fallbackMetadata = decisionTree.find(siteIdStr, false, fallBackLocale);
|
|
34
|
+
const fallbackMetadata = decisionTree.find(siteIdStr, false, false, fallBackLocale);
|
|
35
35
|
if (fallbackMetadata) {
|
|
36
36
|
// Read the content of the fallback metadata
|
|
37
37
|
const fallbackSrc = fs.readFileSync(path.join(rootDir, fallbackMetadata.path));
|
|
@@ -4,16 +4,17 @@ export interface ArtifactVariantId {
|
|
|
4
4
|
version?: string;
|
|
5
5
|
localeId?: string;
|
|
6
6
|
debug?: boolean;
|
|
7
|
+
ssr?: boolean;
|
|
7
8
|
}
|
|
8
9
|
export default class DecisionTreeImpl<Artifact extends SiteArtifact> implements DecisionTree<Artifact> {
|
|
9
|
-
private root;
|
|
10
|
+
private readonly root;
|
|
10
11
|
insert(siteArtifactId: string, artifact: Artifact, debug?: boolean, localeFallbacks?: Record<string, string[]>): void;
|
|
11
12
|
/**
|
|
12
13
|
* A method to handle deeper insertions, preserving the unique paths.
|
|
13
14
|
* This will be called for each node in the decision path.
|
|
14
15
|
*/
|
|
15
16
|
private deepInsert;
|
|
16
|
-
find(siteArtifactId: string, debug?: boolean, localeId?: string): Artifact | undefined;
|
|
17
|
+
find(siteArtifactId: string, debug?: boolean, ssr?: boolean, localeId?: string): Artifact | undefined;
|
|
17
18
|
/**
|
|
18
19
|
* Create a decision tree patch to look up the most appropriate bundle
|
|
19
20
|
*
|
|
@@ -21,8 +22,13 @@ export default class DecisionTreeImpl<Artifact extends SiteArtifact> implements
|
|
|
21
22
|
* @param version known version or will add the choice ''
|
|
22
23
|
* @param localeId preferred bundle locale or will add '' for default locale
|
|
23
24
|
* @param debug flag if debug bundle is preferred
|
|
25
|
+
* @param ssr flag if server bundle is requested
|
|
24
26
|
*/
|
|
25
27
|
private createArtifactChoices;
|
|
28
|
+
/**
|
|
29
|
+
* Get the choices in a consistent order for possible choices or choices for lookup
|
|
30
|
+
*/
|
|
31
|
+
private getOrderedChoices;
|
|
26
32
|
private createPossibleArtifactChoices;
|
|
27
33
|
}
|
|
28
34
|
export declare function createFallbackMap(config: I18NConfig): Record<string, string[]>;
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
*
|
|
8
8
|
* The tree is populated once by providing a set of possible matching conditions.
|
|
9
9
|
*
|
|
10
|
-
* tree.insert('bundle/foo|v/7_0|l/en', {metadata}, isDebug, {en-MX: [en-MX, en-US, en], en: [en], ...})
|
|
10
|
+
* tree.insert('bundle/foo|v/7_0|ssr|l/en', {metadata}, isDebug, forSsr, {en-MX: [en-MX, en-US, en], en: [en], ...})
|
|
11
11
|
*
|
|
12
|
-
* The tree currently makes decisions in the following order: specifier, isDebug, version, and then locale.
|
|
12
|
+
* The tree currently makes decisions in the following order: specifier, isDebug, version, forSsr and then locale.
|
|
13
13
|
*
|
|
14
14
|
* To find matching metadata, use the following commands:
|
|
15
15
|
*
|
|
16
|
-
* tree.find('bundle/foo|v/7_0|l/en-MX')
|
|
16
|
+
* tree.find('bundle/foo|v/7_0|ssr|l/en-MX')
|
|
17
17
|
*
|
|
18
|
-
* tree.find('bundle/foo', isDebug, 'en-US')
|
|
18
|
+
* tree.find('bundle/foo', isDebug, forSsr, 'en-US')
|
|
19
19
|
*/
|
|
20
20
|
import { logger } from '@lwrjs/diagnostics';
|
|
21
|
-
import { LOCALE_SIGIL, VERSION_NOT_PROVIDED, VERSION_SIGIL, normalizeVersionToUri, } from '@lwrjs/shared-utils';
|
|
21
|
+
import { LOCALE_SIGIL, SSR_SIGIL, VERSION_NOT_PROVIDED, VERSION_SIGIL, getFeatureFlags, normalizeVersionToUri, } from '@lwrjs/shared-utils';
|
|
22
22
|
import { parseSiteId } from '../site-metadata.js';
|
|
23
23
|
// Choice wildcard means I want to match anything
|
|
24
24
|
// Examples are any locale and match the default locale
|
|
@@ -27,6 +27,8 @@ const CHOICE_WILDCARD = '*';
|
|
|
27
27
|
// This is useful for scenarios like an empty version can match any version
|
|
28
28
|
// This cannot be wildcard since we want an explicit version to also not match this choice.
|
|
29
29
|
const CHOICE_EMPTY = '';
|
|
30
|
+
// Boolean choice set available it marked true without requiring a value
|
|
31
|
+
const CHOICE_TRUE = 'true';
|
|
30
32
|
const CHOICE_PROD = 'prod';
|
|
31
33
|
const CHOICE_DEBUG = 'debug';
|
|
32
34
|
// Tree of decisions to lead you to the right artifact
|
|
@@ -36,8 +38,8 @@ export default class DecisionTreeImpl {
|
|
|
36
38
|
}
|
|
37
39
|
// Insert an artifact into the tree based on a path of decisions
|
|
38
40
|
insert(siteArtifactId, artifact, debug, localeFallbacks) {
|
|
39
|
-
//
|
|
40
|
-
// Currently this is hard coded to [specifier, isDebug, version, locale]
|
|
41
|
+
// The decision path is the set of choices needed to get to the right metadata
|
|
42
|
+
// Currently this is hard coded to [specifier, isDebug, version, ssr, locale]
|
|
41
43
|
const decisionPath = this.createPossibleArtifactChoices({
|
|
42
44
|
id: siteArtifactId,
|
|
43
45
|
localeFallbacks,
|
|
@@ -95,11 +97,12 @@ export default class DecisionTreeImpl {
|
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
// Retrieve an artifact from the tree based on a path of decisions
|
|
98
|
-
find(siteArtifactId, debug, localeId) {
|
|
100
|
+
find(siteArtifactId, debug, ssr, localeId) {
|
|
99
101
|
const parsedArtifactId = parseSiteId(siteArtifactId);
|
|
100
102
|
const decisionPath = this.createArtifactChoices({
|
|
101
103
|
specifier: parsedArtifactId.specifier,
|
|
102
104
|
version: parsedArtifactId.variants[VERSION_SIGIL],
|
|
105
|
+
ssr: ssr ?? SSR_SIGIL in parsedArtifactId.variants,
|
|
103
106
|
localeId: localeId ?? parsedArtifactId.variants[LOCALE_SIGIL],
|
|
104
107
|
debug,
|
|
105
108
|
});
|
|
@@ -124,13 +127,21 @@ export default class DecisionTreeImpl {
|
|
|
124
127
|
* @param version known version or will add the choice ''
|
|
125
128
|
* @param localeId preferred bundle locale or will add '' for default locale
|
|
126
129
|
* @param debug flag if debug bundle is preferred
|
|
130
|
+
* @param ssr flag if server bundle is requested
|
|
127
131
|
*/
|
|
128
|
-
createArtifactChoices({ specifier, version, localeId, debug }) {
|
|
132
|
+
createArtifactChoices({ specifier, version, localeId, debug, ssr }) {
|
|
129
133
|
const envChoice = debug ? CHOICE_DEBUG : CHOICE_PROD;
|
|
130
134
|
// Versions are stored in the bundle id in URL normalized form
|
|
131
135
|
const versionChoice = getVersionChoice(version);
|
|
132
136
|
const uriVersion = normalizeVersionToUri(versionChoice);
|
|
133
|
-
|
|
137
|
+
const ssrChoice = ssr ? CHOICE_TRUE : CHOICE_EMPTY;
|
|
138
|
+
return this.getOrderedChoices(specifier, envChoice, ssrChoice, uriVersion, localeId);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get the choices in a consistent order for possible choices or choices for lookup
|
|
142
|
+
*/
|
|
143
|
+
getOrderedChoices(specifier, envChoice, ssrChoice, uriVersion, localeId) {
|
|
144
|
+
return [specifier, envChoice, ssrChoice, uriVersion, localeId || CHOICE_WILDCARD];
|
|
134
145
|
}
|
|
135
146
|
createPossibleArtifactChoices({ id, localeFallbacks, debug, }) {
|
|
136
147
|
const match = parseSiteId(id);
|
|
@@ -149,9 +160,17 @@ export default class DecisionTreeImpl {
|
|
|
149
160
|
? [...new Set([CHOICE_EMPTY, CHOICE_WILDCARD])]
|
|
150
161
|
: [...new Set([versionChoice, CHOICE_EMPTY])];
|
|
151
162
|
const envChoice = debug ? [CHOICE_DEBUG] : [CHOICE_PROD];
|
|
163
|
+
// If there is an ssr sigil always prefer it during SSR
|
|
164
|
+
const ssrChoice = match.variants[SSR_SIGIL] || CHOICE_EMPTY;
|
|
165
|
+
const ssr = getFeatureFlags().SSR_COMPILER_ENABLED
|
|
166
|
+
? [ssrChoice]
|
|
167
|
+
: ssrChoice
|
|
168
|
+
? [ssrChoice, CHOICE_WILDCARD]
|
|
169
|
+
: [CHOICE_WILDCARD];
|
|
152
170
|
const localeChoice = match.variants[LOCALE_SIGIL];
|
|
153
|
-
|
|
154
|
-
|
|
171
|
+
// If there are no fallbacks, or localeChoice is not in fallbacks use the ['*'] wildcard choice
|
|
172
|
+
const localeId = localeFallbacks?.[localeChoice] ?? [CHOICE_WILDCARD];
|
|
173
|
+
return this.getOrderedChoices([specifier], envChoice, ssr, versions, localeId);
|
|
155
174
|
}
|
|
156
175
|
}
|
|
157
176
|
/**
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.15.0
|
|
7
|
+
"version": "0.15.0",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -52,15 +52,17 @@
|
|
|
52
52
|
"build/**/*.d.ts"
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@lwrjs/diagnostics": "0.15.0
|
|
56
|
-
"@lwrjs/
|
|
55
|
+
"@lwrjs/diagnostics": "0.15.0",
|
|
56
|
+
"@lwrjs/instrumentation": "0.15.0",
|
|
57
|
+
"@lwrjs/shared-utils": "0.15.0",
|
|
58
|
+
"lru-cache": "^10.4.3"
|
|
57
59
|
},
|
|
58
60
|
"devDependencies": {
|
|
59
|
-
"@lwrjs/types": "0.15.0
|
|
61
|
+
"@lwrjs/types": "0.15.0",
|
|
60
62
|
"@types/express": "^4.17.21",
|
|
61
63
|
"jest": "^26.6.3",
|
|
62
64
|
"jest-express": "^1.12.0",
|
|
63
|
-
"memfs": "^4.
|
|
65
|
+
"memfs": "^4.13.0",
|
|
64
66
|
"mock-res": "^0.6.0",
|
|
65
67
|
"ts-jest": "^26.5.6"
|
|
66
68
|
},
|
|
@@ -70,5 +72,5 @@
|
|
|
70
72
|
"volta": {
|
|
71
73
|
"extends": "../../../package.json"
|
|
72
74
|
},
|
|
73
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "ee374df435d5342f63e4da126a09461e761837f3"
|
|
74
76
|
}
|