@lwrjs/static 0.15.0-alpha.2 → 0.15.0-alpha.21

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.
@@ -30,9 +30,11 @@ 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 BUNDLE_SOURCE_NOT_FOUND = "Bundle Source Path Not Found";
34
36
  var StaticBundleProvider = class {
35
- constructor(_config, context) {
37
+ constructor(config, context) {
36
38
  this.name = "static-bundle-provider";
37
39
  if (!context.siteMetadata) {
38
40
  throw new Error(`[${this.name}] Site metadata was not found`);
@@ -41,6 +43,15 @@ var StaticBundleProvider = class {
41
43
  this.siteRootDir = context.siteMetadata.getSiteRootDir();
42
44
  this.bundleConfig = context.config.bundleConfig;
43
45
  this.i18n = context.config.i18n;
46
+ this.bundleCacheSize = config.bundleCacheSize ?? parseInt(process.env.BUNDLE_CACHE_SIZE ?? "500", 10);
47
+ if (this.bundleCacheSize > 0) {
48
+ this.codeCache = new import_lru_cache.LRUCache({
49
+ max: this.bundleCacheSize,
50
+ dispose: (_value, key) => {
51
+ import_diagnostics.logger.verbose(`Bundle Code evicted from cache ${key}`);
52
+ }
53
+ });
54
+ }
44
55
  }
45
56
  async bundle(moduleId, runtimeEnvironment, runtimeParams) {
46
57
  const {specifier, name, namespace, version} = moduleId;
@@ -49,25 +60,27 @@ var StaticBundleProvider = class {
49
60
  i18n: {defaultLocale}
50
61
  } = runtimeEnvironment;
51
62
  const localeId = runtimeParams?.locale || defaultLocale;
52
- const metadata = this.getBundleMetadata(moduleId, localeId, debug);
63
+ const metadata = this.getBundleMetadata({moduleId, localeId, debug, ssr: false});
53
64
  if (!metadata) {
54
65
  return void 0;
55
66
  }
56
67
  const bundlePath = import_path.default.join(this.siteRootDir, metadata.path);
57
- const code = await this.getCode(bundlePath, debug, specifier, version, localeId);
58
- const imports = metadata.imports.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug));
59
- const dynamicImports = metadata.dynamicImports?.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug));
68
+ const ssr = runtimeParams?.ssr;
69
+ const resolvedBundlePath = this.getCodePath(bundlePath, debug, specifier, version, localeId, ssr);
70
+ const codePromiser = this.getCodePromiser(resolvedBundlePath, specifier);
71
+ const imports = metadata.imports.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
72
+ const dynamicImports = metadata.dynamicImports?.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
60
73
  const id = (0, import_shared_utils.getSpecifier)(moduleId);
61
74
  const exploded = (0, import_shared_utils.explodeSpecifier)(id);
62
75
  const resolvedName = name ?? exploded.name;
63
76
  const resolvedNamespace = namespace ?? exploded.namespace;
64
77
  const resolvedVersion = (0, import_site_metadata.resolveStaticBundleVersion)(metadata.version, version);
65
78
  const includedModules = metadata.includedModules?.map((includedId) => {
66
- const includedModule = this.getModuleReference(includedId, localeId, debug);
79
+ const includedModule = this.getModuleReference(includedId, localeId, debug, ssr);
67
80
  return (0, import_shared_utils.getSpecifier)(includedModule);
68
81
  }) || [];
69
82
  return {
70
- code,
83
+ getCode: codePromiser,
71
84
  id: (0, import_shared_utils.getSpecifier)({
72
85
  specifier,
73
86
  version: resolvedVersion,
@@ -88,44 +101,83 @@ var StaticBundleProvider = class {
88
101
  src: bundlePath
89
102
  };
90
103
  }
91
- getBundleMetadata(moduleId, localeId, debug) {
92
- const siteBundleId = (0, import_site_metadata.getSiteBundleId)(moduleId, localeId, this.i18n);
104
+ getBundleMetadata({
105
+ moduleId,
106
+ localeId,
107
+ debug,
108
+ ssr
109
+ }) {
110
+ const siteBundleId = (0, import_site_metadata.getSiteBundleId)(moduleId, localeId, ssr, this.i18n);
93
111
  return this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleId, debug);
94
112
  }
95
- getModuleReference(siteBundleIdStr, localeId, debug) {
113
+ getModuleReference(siteBundleIdStr, localeId, debug, ssr) {
96
114
  const siteBundleId = (0, import_site_metadata.parseSiteId)(siteBundleIdStr);
97
115
  const includedModule = (0, import_shared_utils.explodeSpecifier)(siteBundleId.specifier);
98
116
  if (!siteBundleId.variants[import_shared_utils.VERSION_SIGIL]) {
99
- const importBundleMetadata = this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleIdStr, debug, localeId);
117
+ const importBundleMetadata = this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleIdStr, debug, ssr, localeId);
100
118
  includedModule.version = (0, import_site_metadata.resolveStaticBundleVersion)(importBundleMetadata?.version);
101
119
  } else {
102
120
  includedModule.version = siteBundleId.variants[import_shared_utils.VERSION_SIGIL];
103
121
  }
104
122
  return includedModule;
105
123
  }
106
- async getCode(bundlePath, debug, specifier, version, localeId) {
107
- const isLambda = (0, import_shared_utils.isLambdaEnv)();
108
- let bundleSourcePath = bundlePath;
109
- try {
110
- if (debug && isLambda) {
111
- const metadata = this.getBundleMetadata({specifier, version}, localeId, false);
112
- if (!metadata) {
124
+ getCodePromiser(bundleSourcePath, specifier) {
125
+ const cache = this.codeCache;
126
+ return async () => {
127
+ let code = cache?.get(bundleSourcePath);
128
+ if (!code) {
129
+ try {
130
+ if (bundleSourcePath === BUNDLE_SOURCE_NOT_FOUND) {
131
+ throw new Error(BUNDLE_SOURCE_NOT_FOUND);
132
+ }
133
+ code = await import_fs_extra.default.readFile(import_path.default.join(bundleSourcePath), "utf-8");
134
+ if (cache) {
135
+ cache.set(bundleSourcePath, code);
136
+ }
137
+ } catch (err) {
113
138
  import_diagnostics.logger.warn({
114
139
  label: "static-bundle-provider",
115
- message: `Unexpected code reference: ${specifier}`
116
- });
117
- return `throw new Error('Unexpected code reference: ${specifier}');`;
140
+ message: `Unexpected code reference: ${specifier} ${bundleSourcePath}`
141
+ }, err);
142
+ code = `throw new Error('Unexpected code reference: ${specifier} ${bundleSourcePath}');`;
143
+ if (cache) {
144
+ cache.set(bundleSourcePath, code);
145
+ }
118
146
  }
147
+ }
148
+ return code;
149
+ };
150
+ }
151
+ getCodePath(bundlePath, debug, specifier, version, localeId, ssr) {
152
+ const isLambda = (0, import_shared_utils.isLambdaEnv)();
153
+ let bundleSourcePath = bundlePath;
154
+ if (debug && isLambda) {
155
+ const metadata = this.getBundleMetadata({
156
+ moduleId: {specifier, version},
157
+ localeId,
158
+ debug: false,
159
+ ssr
160
+ });
161
+ if (!metadata) {
162
+ import_diagnostics.logger.error({
163
+ label: "static-bundle-provider",
164
+ message: `Unexpected code reference: ${specifier}`
165
+ });
166
+ return BUNDLE_SOURCE_NOT_FOUND;
167
+ }
168
+ bundleSourcePath = import_path.default.join(this.siteRootDir, metadata.path);
169
+ } else if (ssr) {
170
+ const metadata = this.getBundleMetadata({
171
+ moduleId: {specifier, version},
172
+ localeId,
173
+ debug,
174
+ ssr
175
+ });
176
+ if (metadata) {
119
177
  bundleSourcePath = import_path.default.join(this.siteRootDir, metadata.path);
120
178
  }
121
- return await import_fs_extra.default.readFile(bundleSourcePath, "utf-8");
122
- } catch (err) {
123
- import_diagnostics.logger.warn({
124
- label: "static-bundle-provider",
125
- message: `Unexpected code reference: ${specifier} ${bundleSourcePath}`
126
- }, err);
127
- return `throw new Error('Unexpected code reference: ${specifier} ${bundleSourcePath}');`;
128
179
  }
180
+ return bundleSourcePath;
129
181
  }
130
182
  };
131
183
  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 metadata = this.getBundleMetadata(moduleId, localeId, false);
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 metadata = this.getBundleMetadata(moduleId, localeId, false);
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(moduleId, localeId, debug) {
91
- const siteBundleId = (0, import_site_metadata.getSiteBundleId)(moduleId, localeId, this.i18n);
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
- return i18n?.defaultLocale === locale ? versionedSpecifier : `${versionedSpecifier}${SITE_LOCALE_PREFIX}${locale}`;
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
- return [specifier, envChoice, uriVersion, localeId || CHOICE_WILDCARD];
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 = ssrChoice ? [ssrChoice, CHOICE_WILDCARD] : [CHOICE_WILDCARD];
121
129
  const localeChoice = match.variants[import_shared_utils.LOCALE_SIGIL];
122
130
  const localeId = localeChoice && localeFallbacks ? localeFallbacks[localeChoice] : [CHOICE_WILDCARD];
123
- return [[specifier], envChoice, versions, localeId];
131
+ return this.getOrderedChoices([specifier], envChoice, ssr, versions, localeId);
124
132
  }
125
133
  };
126
134
  var decision_tree_default = DecisionTreeImpl;
@@ -1,19 +1,30 @@
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
- constructor(_config: {}, context: ProviderContext);
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: Partial<AbstractModuleId>, localeId: string, debug: boolean): SiteBundle | undefined;
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: string): () => Promise<string>;
15
26
  /**
16
- * Get the source code for the a static bundle
27
+ * Get the local source code path for the a static bundle
17
28
  * 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
29
  *
19
30
  * @param bundlePath The default path for the bundle for prod read from .metadata/bundle-metadata.json, for debug .metadata/bundle-metadata-debug.json
@@ -21,6 +32,6 @@ export default class StaticBundleProvider implements BundleProvider {
21
32
  * @param specifier Root specifier for the requested bundle
22
33
  * @param localeId Locale id (e.g. en-US) for the current request
23
34
  */
24
- getCode(bundlePath: string, debug: boolean, specifier: string, version: string | undefined, localeId: string): Promise<string>;
35
+ getCodePath(bundlePath: string, debug: boolean, specifier: string, version: string | undefined, localeId: string, ssr: boolean): string;
25
36
  }
26
37
  //# sourceMappingURL=static-bundle-provider.d.ts.map
@@ -2,9 +2,11 @@ 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
+ const BUNDLE_SOURCE_NOT_FOUND = 'Bundle Source Path Not Found';
6
8
  export default class StaticBundleProvider {
7
- constructor(_config, context) {
9
+ constructor(config, context) {
8
10
  this.name = 'static-bundle-provider';
9
11
  if (!context.siteMetadata) {
10
12
  throw new Error(`[${this.name}] Site metadata was not found`);
@@ -13,21 +15,34 @@ export default class StaticBundleProvider {
13
15
  this.siteRootDir = context.siteMetadata.getSiteRootDir();
14
16
  this.bundleConfig = context.config.bundleConfig;
15
17
  this.i18n = context.config.i18n;
18
+ this.bundleCacheSize = config.bundleCacheSize ?? parseInt(process.env.BUNDLE_CACHE_SIZE ?? '500', 10);
19
+ if (this.bundleCacheSize > 0) {
20
+ this.codeCache = new LRUCache({
21
+ max: this.bundleCacheSize,
22
+ dispose: (_value, key) => {
23
+ logger.verbose(`Bundle Code evicted from cache ${key}`);
24
+ },
25
+ });
26
+ }
16
27
  }
17
28
  async bundle(moduleId, runtimeEnvironment, runtimeParams) {
18
29
  const { specifier, name, namespace, version } = moduleId;
19
30
  const { debug, i18n: { defaultLocale }, } = runtimeEnvironment;
20
31
  const localeId = (runtimeParams?.locale || defaultLocale);
21
- const metadata = this.getBundleMetadata(moduleId, localeId, debug);
32
+ // For Bifurcated SSR modules we are getting the CSRed bundle def here to be used for linking (s3)
33
+ // When we get the code we will explicity look for ssr bifurcated cmp tp get the source.
34
+ const metadata = this.getBundleMetadata({ moduleId, localeId, debug, ssr: false });
22
35
  if (!metadata) {
23
36
  return undefined;
24
37
  }
25
38
  // Default bundle source path
26
39
  const bundlePath = path.join(this.siteRootDir, metadata.path);
27
40
  // Get the associated bundle source code
28
- const code = await this.getCode(bundlePath, debug, specifier, version, localeId);
29
- const imports = metadata.imports.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug));
30
- const dynamicImports = metadata.dynamicImports?.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug));
41
+ const ssr = runtimeParams?.ssr;
42
+ const resolvedBundlePath = this.getCodePath(bundlePath, debug, specifier, version, localeId, ssr);
43
+ const codePromiser = this.getCodePromiser(resolvedBundlePath, specifier);
44
+ const imports = metadata.imports.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
45
+ const dynamicImports = metadata.dynamicImports?.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
31
46
  const id = getSpecifier(moduleId);
32
47
  const exploded = explodeSpecifier(id);
33
48
  // Seem unlikely name was not in the moduleId but just incase set it form the exploded id
@@ -35,11 +50,11 @@ export default class StaticBundleProvider {
35
50
  const resolvedNamespace = namespace ?? exploded.namespace;
36
51
  const resolvedVersion = resolveStaticBundleVersion(metadata.version, version);
37
52
  const includedModules = metadata.includedModules?.map((includedId) => {
38
- const includedModule = this.getModuleReference(includedId, localeId, debug);
53
+ const includedModule = this.getModuleReference(includedId, localeId, debug, ssr);
39
54
  return getSpecifier(includedModule);
40
55
  }) || [];
41
56
  return {
42
- code,
57
+ getCode: codePromiser,
43
58
  id: getSpecifier({
44
59
  specifier: specifier,
45
60
  version: resolvedVersion,
@@ -61,20 +76,20 @@ export default class StaticBundleProvider {
61
76
  src: bundlePath,
62
77
  };
63
78
  }
64
- getBundleMetadata(moduleId, localeId, debug) {
65
- const siteBundleId = getSiteBundleId(moduleId, localeId, this.i18n);
79
+ getBundleMetadata({ moduleId, localeId, debug, ssr, }) {
80
+ const siteBundleId = getSiteBundleId(moduleId, localeId, ssr, this.i18n);
66
81
  return this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleId, debug);
67
82
  }
68
83
  /**
69
84
  * Takes a key from the site bundle metadata and creates an appropriate runtime BaseModuleReference to use in the LWR runtime.
70
85
  */
71
- getModuleReference(siteBundleIdStr, localeId, debug) {
86
+ getModuleReference(siteBundleIdStr, localeId, debug, ssr) {
72
87
  const siteBundleId = parseSiteId(siteBundleIdStr);
73
88
  const includedModule = explodeSpecifier(siteBundleId.specifier);
74
89
  if (!siteBundleId.variants[VERSION_SIGIL]) {
75
90
  const importBundleMetadata = this.siteMetadata
76
91
  .getSiteBundlesDecisionTree()
77
- .find(siteBundleIdStr, debug, localeId);
92
+ .find(siteBundleIdStr, debug, ssr, localeId);
78
93
  includedModule.version = resolveStaticBundleVersion(importBundleMetadata?.version);
79
94
  }
80
95
  else {
@@ -82,8 +97,39 @@ export default class StaticBundleProvider {
82
97
  }
83
98
  return includedModule;
84
99
  }
100
+ getCodePromiser(bundleSourcePath, specifier) {
101
+ const cache = this.codeCache;
102
+ return async () => {
103
+ let code = cache?.get(bundleSourcePath);
104
+ if (!code) {
105
+ try {
106
+ // Debug metadata was not found
107
+ if (bundleSourcePath === BUNDLE_SOURCE_NOT_FOUND) {
108
+ throw new Error(BUNDLE_SOURCE_NOT_FOUND);
109
+ }
110
+ code = await fs.readFile(path.join(bundleSourcePath), 'utf-8');
111
+ if (cache) {
112
+ cache.set(bundleSourcePath, code);
113
+ }
114
+ }
115
+ catch (err) {
116
+ // Ran it an un-expected error reading the bundle source code
117
+ logger.warn({
118
+ label: 'static-bundle-provider',
119
+ message: `Unexpected code reference: ${specifier} ${bundleSourcePath}`,
120
+ }, err);
121
+ // Returning source code that throws and error is someone tries to evaluate it
122
+ code = `throw new Error('Unexpected code reference: ${specifier} ${bundleSourcePath}');`;
123
+ if (cache) {
124
+ cache.set(bundleSourcePath, code);
125
+ }
126
+ }
127
+ }
128
+ return code;
129
+ };
130
+ }
85
131
  /**
86
- * Get the source code for the a static bundle
132
+ * Get the local source code path for the a static bundle
87
133
  * 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
134
  *
89
135
  * @param bundlePath The default path for the bundle for prod read from .metadata/bundle-metadata.json, for debug .metadata/bundle-metadata-debug.json
@@ -91,40 +137,45 @@ export default class StaticBundleProvider {
91
137
  * @param specifier Root specifier for the requested bundle
92
138
  * @param localeId Locale id (e.g. en-US) for the current request
93
139
  */
94
- async getCode(bundlePath, debug, specifier, version, localeId) {
140
+ getCodePath(bundlePath, debug, specifier, version, localeId, ssr) {
95
141
  // Flag is used to indicate that we are running on a lambda
96
142
  const isLambda = isLambdaEnv();
97
143
  // Default source code path determined from metadata based on debug mode
98
144
  let bundleSourcePath = bundlePath;
99
- try {
100
- // This is the special case where the request is in debug mode and we are on the lambda
101
- // So we will look up the prod source code instead of the debug source code
102
- if (debug && isLambda) {
103
- const metadata = this.getBundleMetadata({ specifier, version }, localeId, false);
104
- if (!metadata) {
105
- // We did not find the bundle prod bundle even though we did find it in the debug metadata before
106
- logger.warn({
107
- label: 'static-bundle-provider',
108
- message: `Unexpected code reference: ${specifier}`,
109
- });
110
- // Returning source code that throws and error is someone tries to evaluate it
111
- return `throw new Error('Unexpected code reference: ${specifier}');`;
112
- }
113
- // Overwrite the default source code path the prod source code path
114
- bundleSourcePath = path.join(this.siteRootDir, metadata.path);
145
+ // This is the special case where the request is in debug mode and we are on the lambda
146
+ // So we will look up the prod source code instead of the debug source code
147
+ if (debug && isLambda) {
148
+ const metadata = this.getBundleMetadata({
149
+ moduleId: { specifier, version },
150
+ localeId,
151
+ debug: false,
152
+ ssr,
153
+ });
154
+ if (!metadata) {
155
+ // We did not find the bundle prod bundle even though we did find it in the debug metadata before
156
+ logger.error({
157
+ label: 'static-bundle-provider',
158
+ message: `Unexpected code reference: ${specifier}`,
159
+ });
160
+ return BUNDLE_SOURCE_NOT_FOUND;
115
161
  }
116
- // Read the bundle source code.
117
- return await fs.readFile(bundleSourcePath, 'utf-8');
162
+ // Overwrite the default source code path the prod source code path
163
+ bundleSourcePath = path.join(this.siteRootDir, metadata.path);
118
164
  }
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}');`;
165
+ else if (ssr) {
166
+ // If this is an ssr request get the code preferring bifurcated ssr modules
167
+ const metadata = this.getBundleMetadata({
168
+ moduleId: { specifier, version },
169
+ localeId,
170
+ debug,
171
+ ssr,
172
+ });
173
+ if (metadata) {
174
+ // Overwrite the default source code path the ssr source code path
175
+ bundleSourcePath = path.join(this.siteRootDir, metadata.path);
176
+ }
127
177
  }
178
+ return bundleSourcePath;
128
179
  }
129
180
  }
130
181
  //# 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 metadata = this.getBundleMetadata(moduleId, localeId, false);
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 metadata = this.getBundleMetadata(moduleId, localeId, false);
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
- type SIGIL = typeof VERSION_SIGIL | typeof LOCALE_SIGIL;
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 preferred 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 preferred 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
- return i18n?.defaultLocale === locale
223
- ? versionedSpecifier
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,6 +4,7 @@ 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
10
  private root;
@@ -13,7 +14,7 @@ export default class DecisionTreeImpl<Artifact extends SiteArtifact> implements
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
  *
@@ -23,6 +24,10 @@ export default class DecisionTreeImpl<Artifact extends SiteArtifact> implements
23
24
  * @param debug flag if debug bundle is preferred
24
25
  */
25
26
  private createArtifactChoices;
27
+ /**
28
+ * Get the choices in a consistent order for possible choices or choices for lookup
29
+ */
30
+ private getOrderedChoices;
26
31
  private createPossibleArtifactChoices;
27
32
  }
28
33
  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, 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
@@ -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
  });
@@ -125,12 +128,19 @@ export default class DecisionTreeImpl {
125
128
  * @param localeId preferred bundle locale or will add '' for default locale
126
129
  * @param debug flag if debug bundle is preferred
127
130
  */
128
- createArtifactChoices({ specifier, version, localeId, debug }) {
131
+ createArtifactChoices({ specifier, version, localeId, debug, ssr }) {
129
132
  const envChoice = debug ? CHOICE_DEBUG : CHOICE_PROD;
130
133
  // Versions are stored in the bundle id in URL normalized form
131
134
  const versionChoice = getVersionChoice(version);
132
135
  const uriVersion = normalizeVersionToUri(versionChoice);
133
- return [specifier, envChoice, uriVersion, localeId || CHOICE_WILDCARD];
136
+ const ssrChoice = ssr ? CHOICE_TRUE : CHOICE_EMPTY;
137
+ return this.getOrderedChoices(specifier, envChoice, ssrChoice, uriVersion, localeId);
138
+ }
139
+ /**
140
+ * Get the choices in a consistent order for possible choices or choices for lookup
141
+ */
142
+ getOrderedChoices(specifier, envChoice, ssrChoice, uriVersion, localeId) {
143
+ return [specifier, envChoice, ssrChoice, uriVersion, localeId || CHOICE_WILDCARD];
134
144
  }
135
145
  createPossibleArtifactChoices({ id, localeFallbacks, debug, }) {
136
146
  const match = parseSiteId(id);
@@ -149,9 +159,12 @@ export default class DecisionTreeImpl {
149
159
  ? [...new Set([CHOICE_EMPTY, CHOICE_WILDCARD])]
150
160
  : [...new Set([versionChoice, CHOICE_EMPTY])];
151
161
  const envChoice = debug ? [CHOICE_DEBUG] : [CHOICE_PROD];
162
+ // If there is an ssr sigil always prefer it during SSR
163
+ const ssrChoice = match.variants[SSR_SIGIL] || CHOICE_EMPTY;
164
+ const ssr = ssrChoice ? [ssrChoice, CHOICE_WILDCARD] : [CHOICE_WILDCARD];
152
165
  const localeChoice = match.variants[LOCALE_SIGIL];
153
166
  const localeId = localeChoice && localeFallbacks ? localeFallbacks[localeChoice] : [CHOICE_WILDCARD];
154
- return [[specifier], envChoice, versions, localeId];
167
+ return this.getOrderedChoices([specifier], envChoice, ssr, versions, localeId);
155
168
  }
156
169
  }
157
170
  /**
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.15.0-alpha.2",
7
+ "version": "0.15.0-alpha.21",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -52,11 +52,12 @@
52
52
  "build/**/*.d.ts"
53
53
  ],
54
54
  "dependencies": {
55
- "@lwrjs/diagnostics": "0.15.0-alpha.2",
56
- "@lwrjs/shared-utils": "0.15.0-alpha.2"
55
+ "@lwrjs/diagnostics": "0.15.0-alpha.21",
56
+ "@lwrjs/shared-utils": "0.15.0-alpha.21",
57
+ "lru-cache": "^10.4.3"
57
58
  },
58
59
  "devDependencies": {
59
- "@lwrjs/types": "0.15.0-alpha.2",
60
+ "@lwrjs/types": "0.15.0-alpha.21",
60
61
  "@types/express": "^4.17.21",
61
62
  "jest": "^26.6.3",
62
63
  "jest-express": "^1.12.0",
@@ -70,5 +71,5 @@
70
71
  "volta": {
71
72
  "extends": "../../../package.json"
72
73
  },
73
- "gitHead": "58fda4341e2aa0f571a63d83f4aa59865e6a54bd"
74
+ "gitHead": "4c09ff654569ab490fc77f196d3230b31404940e"
74
75
  }