@ohos-ports/lwrjs-static 0.24.0-beta.1

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.
Files changed (29) hide show
  1. package/LICENSE +10 -0
  2. package/build/cjs/index.cjs +22 -0
  3. package/build/cjs/providers/static-asset-provider.cjs +103 -0
  4. package/build/cjs/providers/static-bundle-provider.cjs +246 -0
  5. package/build/cjs/providers/static-module-provider.cjs +138 -0
  6. package/build/cjs/providers/static-resource-provider.cjs +73 -0
  7. package/build/cjs/site-metadata.cjs +215 -0
  8. package/build/cjs/tools/dedupe-bundles.cjs +108 -0
  9. package/build/cjs/transformers/mrt-static-uri-transformer.cjs +62 -0
  10. package/build/cjs/utils/decision-tree.cjs +209 -0
  11. package/build/es/index.d.ts +2 -0
  12. package/build/es/index.js +2 -0
  13. package/build/es/providers/static-asset-provider.d.ts +16 -0
  14. package/build/es/providers/static-asset-provider.js +90 -0
  15. package/build/es/providers/static-bundle-provider.d.ts +59 -0
  16. package/build/es/providers/static-bundle-provider.js +257 -0
  17. package/build/es/providers/static-module-provider.d.ts +15 -0
  18. package/build/es/providers/static-module-provider.js +118 -0
  19. package/build/es/providers/static-resource-provider.d.ts +10 -0
  20. package/build/es/providers/static-resource-provider.js +53 -0
  21. package/build/es/site-metadata.d.ts +80 -0
  22. package/build/es/site-metadata.js +243 -0
  23. package/build/es/tools/dedupe-bundles.d.ts +3 -0
  24. package/build/es/tools/dedupe-bundles.js +89 -0
  25. package/build/es/transformers/mrt-static-uri-transformer.d.ts +3 -0
  26. package/build/es/transformers/mrt-static-uri-transformer.js +40 -0
  27. package/build/es/utils/decision-tree.d.ts +35 -0
  28. package/build/es/utils/decision-tree.js +287 -0
  29. package/package.json +77 -0
@@ -0,0 +1,90 @@
1
+ import { logger } from '@lwrjs/diagnostics';
2
+ import { hashContent, joinUrlPath, mimeLookup, normalizeResourcePath } from '@lwrjs/shared-utils';
3
+ import path from 'path';
4
+ import fs from 'fs-extra';
5
+ export default class StaticAssetProvider {
6
+ constructor(_config, context) {
7
+ this.name = 'static-asset-provider';
8
+ if (!context.siteMetadata) {
9
+ throw new Error(`[${this.name}] Site metadata was not found`);
10
+ }
11
+ const { assets, rootDir, layoutsDir, contentDir } = context.config;
12
+ this.siteAssets = context.siteMetadata.getSiteAssets();
13
+ this.siteRootDir = context.siteMetadata.getSiteRootDir();
14
+ this.basePath = context.runtimeEnvironment.basePath;
15
+ this.assetsOnLambda = !!context.runtimeEnvironment.featureFlags?.ASSETS_ON_LAMBDA;
16
+ // Adjust the assets directories to be rooted in ssg folder.
17
+ const ssgAssets = Array.from(assets, (asset) => {
18
+ if (asset.dir) {
19
+ // Return the URI as the dir where it will be relative to the ssg root
20
+ return {
21
+ ...asset,
22
+ dir: asset.urlPath,
23
+ };
24
+ }
25
+ return asset;
26
+ });
27
+ this.resourcePaths = { assets: ssgAssets, rootDir, layoutsDir, contentDir };
28
+ }
29
+ async getAsset(assetIdentifier) {
30
+ // Set all the asset path to resolve to the ssg root
31
+ const fileAssetPath = this.normalizeSpecifier(assetIdentifier, this.resourcePaths);
32
+ const metadata = this.siteAssets.assets[fileAssetPath];
33
+ if (!metadata) {
34
+ // Ignore root asset misses (may be views)
35
+ if (path.dirname(fileAssetPath) !== (this.basePath ? this.basePath : '/')) {
36
+ logger.warn({
37
+ label: `${this.name}`,
38
+ message: `Did not find requested specifier ${fileAssetPath}`,
39
+ });
40
+ }
41
+ return undefined;
42
+ }
43
+ // FS path including ssg root
44
+ const siteAssetPath = joinUrlPath(this.siteRootDir, metadata.path);
45
+ // Figure out mime type
46
+ const mime = metadata.mimeType || mimeLookup(siteAssetPath);
47
+ // Normalize extension
48
+ const ext = path.extname(`x.${siteAssetPath}`).toLowerCase().substring(1);
49
+ // Unless assets on lambda feature flag is set indicate the asset source is external
50
+ const type = this.assetsOnLambda ? 'asset' : 'external';
51
+ const content = function (encoding) {
52
+ return fs.readFileSync(siteAssetPath, encoding);
53
+ };
54
+ // Create URI
55
+ const uri = this.assetsOnLambda ? fileAssetPath : joinUrlPath(this.siteRootDir, fileAssetPath);
56
+ logger.debug({ label: `${this.name}`, message: `uri ${assetIdentifier.specifier} -> ${uri}` });
57
+ return {
58
+ entry: siteAssetPath,
59
+ ext,
60
+ mime,
61
+ ownHash: hashContent(metadata.path),
62
+ content,
63
+ uri,
64
+ // Type: external triggers a 302 when requested form the asset middleware.
65
+ type,
66
+ noTransform: true,
67
+ };
68
+ }
69
+ /**
70
+ * Replaces and aliased resource paths (i.e. $assetDir with a qualified specifier)
71
+ */
72
+ normalizeSpecifier(assetId, resourcePaths) {
73
+ const { specifier } = assetId;
74
+ // Remove query params from specifiers (i.e. /assets/styles/styles.css?e368d71b59)
75
+ let normalizedSpecifier = specifier;
76
+ if (normalizedSpecifier.includes('?')) {
77
+ logger.debug({
78
+ label: `${this.name}`,
79
+ message: `Removed query param from asset specifier: ${specifier}`,
80
+ });
81
+ normalizedSpecifier = normalizedSpecifier.split('?')[0];
82
+ }
83
+ if (normalizedSpecifier[0] === '$') {
84
+ // This is a fs path containing an asset alias
85
+ return normalizeResourcePath(normalizedSpecifier, resourcePaths);
86
+ }
87
+ return normalizedSpecifier;
88
+ }
89
+ }
90
+ //# sourceMappingURL=static-asset-provider.js.map
@@ -0,0 +1,59 @@
1
+ import type { AbstractModuleId, BundleDefinition, BundleProvider, ProviderContext, RuntimeEnvironment, RuntimeParams, SiteBundle, SiteMetadata } from '@lwrjs/types';
2
+ import { LRUCache } from 'lru-cache';
3
+ export default class StaticBundleProvider implements BundleProvider {
4
+ name: string;
5
+ codeCache: LRUCache<string, string, unknown> | undefined;
6
+ siteRootDir: string;
7
+ bundleConfig: import("@lwrjs/types").BundleConfig;
8
+ i18n: import("@lwrjs/types").I18NConfig;
9
+ siteMetadata: SiteMetadata;
10
+ bundleCacheSize: number;
11
+ constructor(config: {
12
+ bundleCacheSize?: number;
13
+ }, context: ProviderContext);
14
+ bundle<BundleIdentifier extends AbstractModuleId, RE extends RuntimeEnvironment>(moduleId: BundleIdentifier, runtimeEnvironment: RE, runtimeParams: RuntimeParams): Promise<BundleDefinition | undefined>;
15
+ private createBundleDefinition;
16
+ getBundleMetadata({ moduleId, localeId, debug, ssr, }: {
17
+ moduleId: Partial<AbstractModuleId>;
18
+ localeId: string;
19
+ debug: boolean;
20
+ ssr: boolean;
21
+ }): SiteBundle | undefined;
22
+ /**
23
+ * Takes a key from the site bundle metadata and creates an appropriate runtime BaseModuleReference to use in the LWR runtime.
24
+ */
25
+ private getModuleReference;
26
+ getCodePromiser(bundleSourcePath: string, { specifier, version, locale, ssr, debug, }: {
27
+ specifier: string;
28
+ version?: string;
29
+ locale: string;
30
+ ssr: boolean;
31
+ debug: boolean;
32
+ }): () => Promise<string>;
33
+ /**
34
+ * Logs an error when a bundle fails to load and provides debugging metadata.
35
+ *
36
+ * This function logs details about the failed bundle load attempt, including the module ID,
37
+ * locale, debug mode, and SSR status. It also attempts to retrieve additional metadata
38
+ * about the site bundles and debug bundles associated with the module.
39
+ *
40
+ * @param {Partial<AbstractModuleId>} moduleId - The module identifier, which may include a namespace and name.
41
+ * @param {string} localeId - The locale associated with the bundle.
42
+ * @param {boolean} debug - Indicates whether debug mode is enabled.
43
+ * @param {boolean} ssr - Indicates whether the bundle is for server-side rendering (SSR).
44
+ */
45
+ logBundleError(moduleId: Partial<AbstractModuleId>, localeId: string, debug: boolean, ssr: boolean): void;
46
+ /**
47
+ * Get the local source code path for the a static bundle
48
+ * 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
49
+ *
50
+ * @param bundlePath The default path for the bundle for prod read from .metadata/bundle-metadata.json, for debug .metadata/bundle-metadata-debug.json
51
+ * @param debug Is the request in debug mode?
52
+ * @param specifier Root specifier for the requested bundle
53
+ * @param version Root specifier version
54
+ * @param localeId Locale id (e.g. en-US) for the current request
55
+ * @param ssr True if this is a server bundle
56
+ */
57
+ getCodePath(bundlePath: string, debug: boolean, specifier: string, version: string | undefined, localeId: string, ssr: boolean): string;
58
+ }
59
+ //# sourceMappingURL=static-bundle-provider.d.ts.map
@@ -0,0 +1,257 @@
1
+ import { logger } from '@lwrjs/diagnostics';
2
+ import { VERSION_SIGIL, explodeSpecifier, getSpecifier, isExternalSpecifier, isLambdaEnv, joinUrlPath, normalizeFromFileURL, } from '@lwrjs/shared-utils';
3
+ import path from 'path';
4
+ import fs from 'fs-extra';
5
+ import { LRUCache } from 'lru-cache';
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';
10
+ export default class StaticBundleProvider {
11
+ constructor(config, context) {
12
+ this.name = 'static-bundle-provider';
13
+ if (!context.siteMetadata) {
14
+ throw new Error(`[${this.name}] Site metadata was not found`);
15
+ }
16
+ this.siteMetadata = context.siteMetadata;
17
+ this.siteRootDir = context.siteMetadata.getSiteRootDir();
18
+ this.bundleConfig = context.config.bundleConfig;
19
+ this.i18n = context.config.i18n;
20
+ this.bundleCacheSize =
21
+ config.bundleCacheSize ?? parseInt(process.env.BUNDLE_CODE_CACHE_SIZE ?? '500', 10);
22
+ if (this.bundleCacheSize > 0) {
23
+ this.codeCache = new LRUCache({
24
+ max: this.bundleCacheSize,
25
+ dispose: (_value, key) => {
26
+ if (isLambdaEnv()) {
27
+ logger.warn(`Bundle Code evicted from cache ${key}`);
28
+ }
29
+ else {
30
+ logger.verbose(`Bundle Code evicted from cache ${key}`);
31
+ }
32
+ },
33
+ });
34
+ }
35
+ }
36
+ async bundle(moduleId, runtimeEnvironment, runtimeParams) {
37
+ const { specifier, version } = moduleId;
38
+ const { debug, i18n: { defaultLocale }, } = runtimeEnvironment;
39
+ const localeId = (runtimeParams?.locale || defaultLocale);
40
+ const ssr = runtimeParams?.ssr;
41
+ let metadata = this.getBundleMetadata({ moduleId, localeId, debug, ssr });
42
+ if (!metadata && debug) {
43
+ // Fallback to use prod bundles if the debug variant does not exist
44
+ // eg: debug bundles are not shipped to the Lambda
45
+ // eg: locally, an MRT bundle may or may not have debug metadata, depending on how it's generated
46
+ metadata = this.getBundleMetadata({ moduleId, localeId, debug: false, ssr });
47
+ }
48
+ if (!metadata && isExternalSpecifier(moduleId.specifier, this.bundleConfig)) {
49
+ const { specifier: unversionedSepcifier } = explodeSpecifier(moduleId.specifier);
50
+ metadata = {
51
+ path: this.bundleConfig?.external?.[unversionedSepcifier],
52
+ imports: [],
53
+ dynamicImports: [],
54
+ version: moduleId.version,
55
+ };
56
+ return this.createBundleDefinition(moduleId, metadata, localeId, debug, ssr, async () => '', normalizeFromFileURL(metadata.path, this.siteRootDir) ?? metadata.path);
57
+ }
58
+ if (!metadata) {
59
+ this.logBundleError(moduleId, localeId, debug, ssr);
60
+ return undefined;
61
+ }
62
+ // Default bundle source path
63
+ const bundlePath = joinUrlPath(this.siteRootDir, metadata.path);
64
+ // Get the associated bundle source code
65
+ const resolvedBundlePath = this.getCodePath(bundlePath, debug, specifier, version, localeId, ssr);
66
+ const codePromiser = this.getCodePromiser(resolvedBundlePath, {
67
+ specifier,
68
+ version,
69
+ locale: localeId,
70
+ ssr,
71
+ debug,
72
+ });
73
+ return this.createBundleDefinition(moduleId, metadata, localeId, debug, ssr, codePromiser, bundlePath);
74
+ }
75
+ async createBundleDefinition(moduleId, metadata, localeId, debug, ssr, codePromiser, bundlePath) {
76
+ const { specifier, name, namespace, version } = moduleId;
77
+ const imports = metadata.imports.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
78
+ const dynamicImports = metadata.dynamicImports?.map((importSpecifier) => this.getModuleReference(importSpecifier, localeId, debug, false));
79
+ const id = getSpecifier(moduleId);
80
+ const exploded = explodeSpecifier(id);
81
+ // Seem unlikely name was not in the moduleId but just incase set it form the exploded id
82
+ const resolvedName = name ?? exploded.name;
83
+ const resolvedNamespace = namespace ?? exploded.namespace;
84
+ const resolvedVersion = resolveStaticBundleVersion(metadata.version, version);
85
+ const includedModules = metadata.includedModules?.map((includedId) => {
86
+ const includedModule = this.getModuleReference(includedId, localeId, debug, ssr);
87
+ return getSpecifier(includedModule);
88
+ }) || [];
89
+ return {
90
+ getCode: codePromiser,
91
+ id: getSpecifier({
92
+ specifier: specifier,
93
+ version: resolvedVersion,
94
+ name: resolvedName,
95
+ namespace: resolvedNamespace,
96
+ }),
97
+ name: resolvedName,
98
+ namespace: resolvedNamespace,
99
+ version: resolvedVersion,
100
+ specifier: specifier,
101
+ config: this.bundleConfig,
102
+ integrity: metadata.integrity,
103
+ bundleRecord: {
104
+ // TODO we need to solve include modules for fingerprints support
105
+ includedModules,
106
+ imports,
107
+ dynamicImports,
108
+ },
109
+ src: bundlePath,
110
+ };
111
+ }
112
+ getBundleMetadata({ moduleId, localeId, debug, ssr, }) {
113
+ const siteBundleId = getSiteBundleId(moduleId, localeId, ssr, this.i18n);
114
+ return this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleId, debug);
115
+ }
116
+ /**
117
+ * Takes a key from the site bundle metadata and creates an appropriate runtime BaseModuleReference to use in the LWR runtime.
118
+ */
119
+ getModuleReference(siteBundleIdStr, localeId, debug, ssr) {
120
+ const siteBundleId = parseSiteId(siteBundleIdStr);
121
+ const includedModule = explodeSpecifier(siteBundleId.specifier);
122
+ if (!siteBundleId.variants[VERSION_SIGIL]) {
123
+ const importBundleMetadata = this.siteMetadata
124
+ .getSiteBundlesDecisionTree()
125
+ .find(siteBundleIdStr, debug, ssr, localeId);
126
+ includedModule.version = resolveStaticBundleVersion(importBundleMetadata?.version);
127
+ }
128
+ else {
129
+ includedModule.version = siteBundleId.variants[VERSION_SIGIL];
130
+ }
131
+ return includedModule;
132
+ }
133
+ getCodePromiser(bundleSourcePath, { specifier, version, locale, ssr, debug, }) {
134
+ const cache = this.codeCache;
135
+ return async () => {
136
+ let code = cache?.get(bundleSourcePath);
137
+ if (!code) {
138
+ try {
139
+ // Debug metadata was not found
140
+ if (bundleSourcePath === BUNDLE_SOURCE_NOT_FOUND) {
141
+ throw new Error(BUNDLE_SOURCE_NOT_FOUND);
142
+ }
143
+ // Increment the cache count store
144
+ cacheCountStore.incrementCacheKey('missedReads');
145
+ await getTracer().trace({
146
+ name: BundleSpan.ReadBundle,
147
+ attributes: {
148
+ specifier,
149
+ version: version ?? '',
150
+ locale,
151
+ ssr: ssr ? 'TRUE' : 'FALSE',
152
+ debug: debug ? 'TRUE' : 'FALSE',
153
+ bundleSourcePath,
154
+ },
155
+ }, async () => {
156
+ code = await fs.readFile(path.join(bundleSourcePath), 'utf-8');
157
+ if (cache) {
158
+ cache.set(bundleSourcePath, code);
159
+ }
160
+ });
161
+ }
162
+ catch (err) {
163
+ // Ran it an un-expected error reading the bundle source code
164
+ logger.warn({
165
+ label: 'static-bundle-provider',
166
+ message: `Unexpected code reference: ${specifier} ${bundleSourcePath}`,
167
+ }, err);
168
+ // Returning source code that throws and error is someone tries to evaluate it
169
+ code = `throw new Error('Unexpected code reference: ${specifier} ${bundleSourcePath}');`;
170
+ if (cache) {
171
+ cache.set(bundleSourcePath, code);
172
+ }
173
+ }
174
+ }
175
+ return code;
176
+ };
177
+ }
178
+ /**
179
+ * Logs an error when a bundle fails to load and provides debugging metadata.
180
+ *
181
+ * This function logs details about the failed bundle load attempt, including the module ID,
182
+ * locale, debug mode, and SSR status. It also attempts to retrieve additional metadata
183
+ * about the site bundles and debug bundles associated with the module.
184
+ *
185
+ * @param {Partial<AbstractModuleId>} moduleId - The module identifier, which may include a namespace and name.
186
+ * @param {string} localeId - The locale associated with the bundle.
187
+ * @param {boolean} debug - Indicates whether debug mode is enabled.
188
+ * @param {boolean} ssr - Indicates whether the bundle is for server-side rendering (SSR).
189
+ */
190
+ logBundleError(moduleId, localeId, debug, ssr) {
191
+ const moduleSpecifier = moduleId.namespace
192
+ ? `${moduleId.namespace}/${moduleId.name}`
193
+ : moduleId.name;
194
+ const siteBundleId = getSiteBundleId(moduleId, localeId, ssr, this.i18n);
195
+ // Retrieve site bundles and debug bundles
196
+ const siteBundles = this.siteMetadata.getSiteBundles()?.bundles || {};
197
+ const siteDebugBundles = this.siteMetadata.getDebugSiteBundles()?.bundles || {};
198
+ // Extract keys and filter bundles by module specifier
199
+ const runtimeBundles = Object.keys(siteBundles).filter((key) => key.startsWith(moduleSpecifier));
200
+ const debugBundles = Object.keys(siteDebugBundles).filter((key) => key.startsWith(moduleSpecifier));
201
+ logger.error({
202
+ message: JSON.stringify({
203
+ message: 'Failed to find static bundle',
204
+ moduleId,
205
+ localeId,
206
+ debug,
207
+ ssr,
208
+ moduleSpecifier,
209
+ siteBundleId,
210
+ debugBundles,
211
+ runtimeBundles,
212
+ totalBundlesCount: Object.keys(siteBundles).length,
213
+ totalDebugBundlesCount: Object.keys(siteDebugBundles).length,
214
+ }),
215
+ label: 'static-bundle-provider',
216
+ });
217
+ }
218
+ /**
219
+ * Get the local source code path for the a static bundle
220
+ * 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
221
+ *
222
+ * @param bundlePath The default path for the bundle for prod read from .metadata/bundle-metadata.json, for debug .metadata/bundle-metadata-debug.json
223
+ * @param debug Is the request in debug mode?
224
+ * @param specifier Root specifier for the requested bundle
225
+ * @param version Root specifier version
226
+ * @param localeId Locale id (e.g. en-US) for the current request
227
+ * @param ssr True if this is a server bundle
228
+ */
229
+ getCodePath(bundlePath, debug, specifier, version, localeId, ssr) {
230
+ // Flag is used to indicate that we are running on a lambda
231
+ const isLambda = isLambdaEnv() || process.env.FORCE_DEBUG_FALLBACK === 'true'; // Env variable for testing purposes only
232
+ // Default source code path determined from metadata based on debug mode
233
+ let bundleSourcePath = bundlePath;
234
+ // This is the special case where the request is in debug mode and we are on the lambda
235
+ // So we will look up the prod source code instead of the debug source code
236
+ if (debug && isLambda) {
237
+ const metadata = this.getBundleMetadata({
238
+ moduleId: { specifier, version },
239
+ localeId,
240
+ debug: false,
241
+ ssr,
242
+ });
243
+ if (!metadata) {
244
+ // We did not find the bundle prod bundle even though we did find it in the debug metadata before
245
+ logger.error({
246
+ label: 'static-bundle-provider',
247
+ message: `debug-to-prod fallback missing metadata for specifier: ${specifier}`,
248
+ });
249
+ return BUNDLE_SOURCE_NOT_FOUND;
250
+ }
251
+ // Overwrite the default source code path the prod source code path
252
+ bundleSourcePath = joinUrlPath(this.siteRootDir, metadata.path);
253
+ }
254
+ return bundleSourcePath;
255
+ }
256
+ }
257
+ //# sourceMappingURL=static-bundle-provider.js.map
@@ -0,0 +1,15 @@
1
+ import type { AbstractModuleId, I18NConfig, ModuleCompiled, ModuleEntry, ModuleProvider, ProviderContext, RuntimeParams, SiteMetadata } from '@lwrjs/types';
2
+ export default class StaticModuleProvider implements ModuleProvider {
3
+ name: string;
4
+ siteRootDir: string;
5
+ externals: string[];
6
+ fingerprintIndex: Record<string, ModuleEntry>;
7
+ i18n: I18NConfig;
8
+ siteMetadata: SiteMetadata;
9
+ constructor(_config: {}, context: ProviderContext);
10
+ getModule<T extends AbstractModuleId>(moduleId: T, runtimeParams: RuntimeParams): Promise<ModuleCompiled | undefined>;
11
+ getModuleEntry<T extends AbstractModuleId>(moduleId: T, runtimeParams: RuntimeParams): Promise<ModuleEntry | undefined>;
12
+ private getEntryFromFingerprintIndex;
13
+ private getBundleMetadata;
14
+ }
15
+ //# sourceMappingURL=static-module-provider.d.ts.map
@@ -0,0 +1,118 @@
1
+ import { logger } from '@lwrjs/diagnostics';
2
+ import { VERSION_SIGIL, explodeSpecifier, getSpecifier, isLambdaEnv, joinUrlPath } from '@lwrjs/shared-utils';
3
+ import { getSiteBundleId, parseSiteId, resolveStaticBundleVersion } from '../site-metadata.js';
4
+ export default class StaticModuleProvider {
5
+ constructor(_config, context) {
6
+ this.name = 'static-module-provider';
7
+ if (!context.siteMetadata) {
8
+ throw new Error(`[${this.name}] Site metadata was not found`);
9
+ }
10
+ this.externals = Object.keys(context.config.bundleConfig.external || {});
11
+ this.siteRootDir = context.siteMetadata.getSiteRootDir();
12
+ this.i18n = context.config.i18n;
13
+ this.siteMetadata = context.siteMetadata;
14
+ // If we are using fingerprints collect all the specifiers in the bundles and add them to an index for creating the mapping identities
15
+ this.fingerprintIndex = buildFingerprintsIndex(context);
16
+ }
17
+ async getModule(moduleId, runtimeParams) {
18
+ const localeId = (runtimeParams?.locale || this.i18n.defaultLocale);
19
+ const ssr = runtimeParams?.ssr;
20
+ const metadata = this.getBundleMetadata({ moduleId, localeId, debug: false, ssr });
21
+ if (metadata && isLambdaEnv()) {
22
+ logger.warn({
23
+ label: `${this.name}`,
24
+ message: `We should not be asking for module source we have in our site metadata: ${moduleId.specifier}`,
25
+ });
26
+ // proceed to next provider
27
+ return undefined;
28
+ }
29
+ // proceed to next provider
30
+ return undefined;
31
+ }
32
+ async getModuleEntry(moduleId, runtimeParams) {
33
+ // TODO shouldn't we be passing the runtime environment here to test?
34
+ const { specifier, version } = moduleId;
35
+ const localeId = (runtimeParams?.locale || this.i18n.defaultLocale);
36
+ const ssr = runtimeParams?.ssr;
37
+ const metadata = this.getBundleMetadata({ moduleId, localeId, ssr, debug: false });
38
+ if (metadata) {
39
+ logger.debug({
40
+ label: `${this.name}`,
41
+ message: `Module Entry request for static bundle ${specifier}`,
42
+ });
43
+ // Have to make the bundle code available for SSR
44
+ const bundlePath = joinUrlPath(this.siteRootDir, metadata.path);
45
+ const resolvedVersion = resolveStaticBundleVersion(metadata.version, version);
46
+ return {
47
+ id: getSpecifier({ ...moduleId, version: resolvedVersion }),
48
+ version: resolvedVersion,
49
+ specifier: specifier,
50
+ entry: 'entry-not-provided',
51
+ src: bundlePath,
52
+ };
53
+ }
54
+ else if (this.externals.includes(specifier)) {
55
+ // Externals are not SSG'ed so hard coding definition
56
+ const resolvedVersion = resolveStaticBundleVersion(undefined, version);
57
+ return {
58
+ id: getSpecifier({ ...moduleId, version: resolvedVersion }),
59
+ version: resolvedVersion,
60
+ specifier: specifier,
61
+ entry: 'entry-not-provided',
62
+ };
63
+ }
64
+ // checks the fingerprint index or proceeds to next provider
65
+ return this.getEntryFromFingerprintIndex(moduleId);
66
+ }
67
+ getEntryFromFingerprintIndex(moduleId) {
68
+ const versionedSpecifier = getSpecifier(moduleId);
69
+ return this.fingerprintIndex[versionedSpecifier] || this.fingerprintIndex[moduleId.specifier];
70
+ }
71
+ getBundleMetadata({ moduleId, localeId, debug, ssr, }) {
72
+ const siteBundleId = getSiteBundleId(moduleId, localeId, ssr, this.i18n);
73
+ return this.siteMetadata.getSiteBundlesDecisionTree().find(siteBundleId, debug);
74
+ }
75
+ }
76
+ /**
77
+ * Map each of the includedModules for a bundle to the bundle src
78
+ * This enables lookup of modules which are not top-level in the bundle metadata
79
+ */
80
+ function buildFingerprintsIndex(context) {
81
+ const fingerprintIndex = {};
82
+ if (!context.runtimeEnvironment.featureFlags.LEGACY_LOADER) {
83
+ const bundles = context.siteMetadata?.getSiteBundles().bundles || {};
84
+ for (const bundle of Object.values(bundles)) {
85
+ const bundlePath = joinUrlPath(String(context.siteMetadata?.getSiteRootDir()), bundle.path);
86
+ const includedModules = bundle.includedModules || [];
87
+ for (const includedModule of includedModules) {
88
+ const versionedSpecifier = convertSiteIdToVersionedSpecifier(includedModule);
89
+ const moduleId = explodeSpecifier(versionedSpecifier);
90
+ if (!fingerprintIndex[versionedSpecifier]) {
91
+ fingerprintIndex[versionedSpecifier] = {
92
+ id: versionedSpecifier,
93
+ version: resolveStaticBundleVersion(moduleId.version),
94
+ specifier: moduleId.specifier,
95
+ entry: 'entry-not-provided',
96
+ src: bundlePath,
97
+ };
98
+ }
99
+ // Add an un-versioned match for the first hit
100
+ if (!fingerprintIndex[moduleId.specifier]) {
101
+ fingerprintIndex[moduleId.specifier] = {
102
+ id: moduleId.specifier,
103
+ version: resolveStaticBundleVersion(moduleId.version),
104
+ specifier: moduleId.specifier,
105
+ entry: 'entry-not-provided',
106
+ src: bundlePath,
107
+ };
108
+ }
109
+ }
110
+ }
111
+ }
112
+ return fingerprintIndex;
113
+ }
114
+ function convertSiteIdToVersionedSpecifier(siteId) {
115
+ const parsedSiteId = parseSiteId(siteId);
116
+ return getSpecifier({ specifier: parsedSiteId.specifier, version: parsedSiteId.variants[VERSION_SIGIL] });
117
+ }
118
+ //# sourceMappingURL=static-module-provider.js.map
@@ -0,0 +1,10 @@
1
+ import type { BootstrapRuntimeEnvironment, ProviderContext, ResourceDefinition, ResourceIdentifier, ResourceProvider, RuntimeParams } from '@lwrjs/types';
2
+ export default class StaticResourceProvider implements ResourceProvider {
3
+ name: string;
4
+ siteRootDir: string;
5
+ siteMetadata: import("@lwrjs/types").SiteMetadata;
6
+ resourceRegistry: import("@lwrjs/types").PublicResourceRegistry;
7
+ constructor(_config: {}, context: ProviderContext);
8
+ getResource<Identifier extends ResourceIdentifier, RuntimeEnvironment extends BootstrapRuntimeEnvironment>(resourceIdentity: Identifier, runtimeEnvironment: RuntimeEnvironment, runtimeParams: RuntimeParams): Promise<ResourceDefinition | undefined>;
9
+ }
10
+ //# sourceMappingURL=static-resource-provider.d.ts.map
@@ -0,0 +1,53 @@
1
+ import { logger } from '@lwrjs/diagnostics';
2
+ import { joinUrlPath, mimeLookup } from '@lwrjs/shared-utils';
3
+ import path from 'path';
4
+ import fs from 'fs-extra';
5
+ import { getSiteResourceId } from '../site-metadata.js';
6
+ export default class StaticResourceProvider {
7
+ constructor(_config, context) {
8
+ this.name = 'static-resource-provider';
9
+ if (!context.siteMetadata) {
10
+ throw new Error(`[${this.name}] Site metadata was not found`);
11
+ }
12
+ this.resourceRegistry = context.resourceRegistry;
13
+ this.siteRootDir = context.siteMetadata.getSiteRootDir();
14
+ this.siteMetadata = context.siteMetadata;
15
+ }
16
+ async getResource(resourceIdentity, runtimeEnvironment, runtimeParams) {
17
+ const { debug } = runtimeEnvironment;
18
+ // HACK: this code is tricky because resource IDs are different between prod vs debug ("lwr-loader-shim.bundle.min.js" vs "lwr-loader-shim.bundle.js").
19
+ // 1. In debug mode on Lambda (during SSR), we need to ignore runtimeEnvironment.debug because we will always ask for the prod version (lwr-loader-shim.bundle.min.js)
20
+ // 2. But when we generate the view, we can't ignore runtimeEnvironment.debug because we need the debug version of the loader shim (lwr-loader-shim.bundle.js)
21
+ const { ignoreDebug } = runtimeParams;
22
+ const resourceMetadata = this.siteMetadata
23
+ .getSiteResourcesDecisionTree()
24
+ .find(getSiteResourceId(resourceIdentity), debug && !ignoreDebug);
25
+ if (!resourceMetadata) {
26
+ logger.warn({
27
+ label: `${this.name}`,
28
+ message: `Did not find requested specifier ${resourceIdentity.specifier}`,
29
+ });
30
+ return undefined;
31
+ }
32
+ const resourcePath = joinUrlPath(this.siteRootDir, resourceMetadata.path);
33
+ // Figure out mime type
34
+ const type = resourceMetadata.mimeType ||
35
+ mimeLookup(resourcePath) ||
36
+ 'application/javascript';
37
+ return {
38
+ type,
39
+ stream: () => {
40
+ logger.debug({
41
+ label: `${this.name}`,
42
+ message: `Resource read from lambda ${resourceIdentity.specifier}`,
43
+ });
44
+ return fs.createReadStream(resourcePath);
45
+ },
46
+ src: resourcePath,
47
+ inline: resourceMetadata.inline,
48
+ integrity: resourceMetadata.integrity,
49
+ entry: path.resolve(resourcePath),
50
+ };
51
+ }
52
+ }
53
+ //# sourceMappingURL=static-resource-provider.js.map