@lwrjs/core 0.11.0-alpha.8 → 0.11.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.
Files changed (37) hide show
  1. package/build/cjs/context/server.cjs +1 -1
  2. package/build/cjs/index.cjs +3 -1
  3. package/build/cjs/middleware/asset-middleware.cjs +10 -2
  4. package/build/cjs/middleware/bundle-middleware.cjs +20 -7
  5. package/build/cjs/middleware/hmr-middleware.cjs +6 -5
  6. package/build/cjs/middleware/locale-middleware.cjs +3 -1
  7. package/build/cjs/middleware/mapping-middleware.cjs +14 -4
  8. package/build/cjs/middleware/module-middleware.cjs +12 -4
  9. package/build/cjs/middleware/request-processor-middleware.cjs +64 -0
  10. package/build/cjs/middleware/resource-middleware.cjs +3 -3
  11. package/build/cjs/middleware/utils/error-handling.cjs +5 -4
  12. package/build/cjs/middleware/view-middleware.cjs +37 -8
  13. package/build/cjs/middleware.cjs +2 -0
  14. package/build/cjs/tools/server-warmup.cjs +6 -6
  15. package/build/cjs/tools/static-generation.cjs +72 -66
  16. package/build/cjs/tools/utils/network-dispatcher.cjs +12 -11
  17. package/build/es/context/server.js +1 -2
  18. package/build/es/index.js +5 -2
  19. package/build/es/middleware/asset-middleware.js +10 -2
  20. package/build/es/middleware/bundle-middleware.js +17 -9
  21. package/build/es/middleware/hmr-middleware.js +6 -5
  22. package/build/es/middleware/locale-middleware.js +1 -1
  23. package/build/es/middleware/mapping-middleware.js +9 -4
  24. package/build/es/middleware/module-middleware.js +14 -6
  25. package/build/es/middleware/request-processor-middleware.d.ts +3 -0
  26. package/build/es/middleware/request-processor-middleware.js +53 -0
  27. package/build/es/middleware/resource-middleware.js +3 -3
  28. package/build/es/middleware/utils/error-handling.js +5 -4
  29. package/build/es/middleware/view-middleware.js +48 -8
  30. package/build/es/middleware.d.ts +1 -0
  31. package/build/es/middleware.js +1 -0
  32. package/build/es/tools/server-warmup.js +2 -2
  33. package/build/es/tools/static-generation.d.ts +4 -0
  34. package/build/es/tools/static-generation.js +66 -52
  35. package/build/es/tools/types.d.ts +2 -1
  36. package/build/es/tools/utils/network-dispatcher.js +2 -1
  37. package/package.json +31 -29
@@ -0,0 +1,3 @@
1
+ import type { ServerContext, InternalAppServer, ServerTypes } from '@lwrjs/types';
2
+ export declare function requestProcessorMiddleware<T extends ServerTypes>(app: InternalAppServer<T>, context: ServerContext): void;
3
+ //# sourceMappingURL=request-processor-middleware.d.ts.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Parse passed to us via the X-Mobify-Request-Class.
3
+ *
4
+ * basePath: The dynamic base path
5
+ * '' or undefined -> LWR basePath ''
6
+ * token or /token -> LWR basePath '/token'
7
+ *
8
+ */
9
+ import { logger } from '@lwrjs/diagnostics';
10
+ const MRT_REQUEST_CLASS = 'X-Mobify-Request-Class';
11
+ const MRT_REQUEST_CLASS_KEY = MRT_REQUEST_CLASS.toLowerCase();
12
+ export function requestProcessorMiddleware(app, context) {
13
+ const { basePath } = context.runtimeEnvironment;
14
+ app.use(async (req, _res, next) => {
15
+ let requestClass;
16
+ if (req.headers) {
17
+ // If debug print log all the headers
18
+ if (logger.currentLevel === 'debug' || logger.currentLevel == 'verbose') {
19
+ // Loop through and print each header
20
+ for (const headerName in req.headers) {
21
+ logger.debug(`[request-processor-middleware] Header ${headerName}: ${req.headers[headerName]}`);
22
+ }
23
+ }
24
+ requestClass = req.headers[MRT_REQUEST_CLASS_KEY];
25
+ }
26
+ if (req.headers && typeof requestClass === 'string') {
27
+ const parsedRequestClass = parseRequestClass(requestClass);
28
+ logger.debug(`[request-processor-middleware] parsedRequestClass?.basePath: ${parsedRequestClass?.basePath}`);
29
+ const pathValue = parsedRequestClass?.basePath || basePath || '';
30
+ // If base path is '' or starts with / leave it alone
31
+ req.basePath = pathValue === '' || pathValue.indexOf('/') === 0 ? pathValue : `/${pathValue}`;
32
+ }
33
+ else {
34
+ logger.debug(`[request-processor-middleware] ${MRT_REQUEST_CLASS_KEY} ignored ${req.headers ? req.headers[MRT_REQUEST_CLASS_KEY] : 'no-headers'}`);
35
+ req.basePath = basePath;
36
+ }
37
+ // await is required when calling next to support koa
38
+ await next();
39
+ });
40
+ }
41
+ function parseRequestClass(requestClass) {
42
+ // Split the Forwarded header into individual key-value pairs
43
+ const keyValuePairs = requestClass.split(';');
44
+ // Create an object to store the parsed values
45
+ const parsed = {};
46
+ // Iterate through the key-value pairs and populate the parsed object
47
+ for (const pair of keyValuePairs) {
48
+ const [key, value] = pair.split('=');
49
+ parsed[key] = value;
50
+ }
51
+ return parsed;
52
+ }
53
+ //# sourceMappingURL=request-processor-middleware.js.map
@@ -2,13 +2,13 @@ import { descriptions } from '@lwrjs/diagnostics';
2
2
  import { getResourceIdentity } from './utils/identity.js';
3
3
  import { handleErrors } from './utils/error-handling.js';
4
4
  function createResourceMiddleware(context) {
5
- const { resourceRegistry } = context;
5
+ const { appConfig, resourceRegistry, runtimeEnvironment: defaultRuntimeEnvironment } = context;
6
6
  return async (req, res) => {
7
- if (!req.validateEnvironmentRequest(context.appConfig)) {
7
+ if (!req.validateEnvironmentRequest(appConfig)) {
8
8
  res.status(400).send(descriptions.UNRESOLVABLE.INVALID_ENVIRONMENT(req.params.environment).message);
9
9
  return;
10
10
  }
11
- const { runtimeEnvironment, runtimeParams } = req.getRuntimeContext(context.runtimeEnvironment);
11
+ const { runtimeEnvironment, runtimeParams } = req.getRuntimeContext(defaultRuntimeEnvironment);
12
12
  const { resourceId } = getResourceIdentity(req);
13
13
  const resource = await resourceRegistry.getResource(resourceId, runtimeEnvironment, runtimeParams);
14
14
  if (req.isSiteGeneration()) {
@@ -1,4 +1,5 @@
1
1
  import { descriptions, DiagnosticsError, LwrUnresolvableError } from '@lwrjs/diagnostics';
2
+ import { logger } from '@lwrjs/diagnostics';
2
3
  function createReturnStatus(error, url) {
3
4
  if (error instanceof LwrUnresolvableError &&
4
5
  error.diagnostics[0].description.category === 'lwrUnresolvable/invalid') {
@@ -16,12 +17,12 @@ export function handleErrors(middleware) {
16
17
  }
17
18
  catch (err) {
18
19
  if (err instanceof DiagnosticsError) {
19
- console.error('LWR Diagnostic Error: ' + err.message);
20
- console.error(err.diagnostics);
21
- console.error(err.stack);
20
+ logger.error('LWR Diagnostic Error: ' + err.message);
21
+ logger.error(err.diagnostics);
22
+ logger.error(err.stack);
22
23
  }
23
24
  else {
24
- console.error(err);
25
+ logger.error(err);
25
26
  }
26
27
  const { status, message } = createReturnStatus(err, req.originalUrl);
27
28
  res.status(status);
@@ -1,12 +1,15 @@
1
- import { descriptions } from '@lwrjs/diagnostics';
1
+ import { descriptions, logger } from '@lwrjs/diagnostics';
2
2
  import { getClientRoutes } from '@lwrjs/router';
3
- import { decodeViewPath, extractRequestParams, getClientBootstrapConfigurationRoutes, logger, shortestTtl, } from '@lwrjs/shared-utils';
3
+ import { decodeViewPath, extractRequestParams, getClientBootstrapConfigurationRoutes, shortestTtl, } from '@lwrjs/shared-utils';
4
+ import { RequestHandlerSpan, getTracer } from '@lwrjs/instrumentation';
4
5
  import { handleErrors } from './utils/error-handling.js';
5
6
  import { LwrViewHandler } from '@lwrjs/view-registry';
6
7
  function createViewMiddleware(route, errorRoutes, context, viewHandler) {
7
8
  const errorRoute = errorRoutes.find((route) => route.status === 500);
9
+ const appConfig = context.appConfig;
10
+ const { environment: environmentConfig } = appConfig;
8
11
  return async (req, res) => {
9
- if (!req.validateEnvironmentRequest(context.appConfig)) {
12
+ if (!req.validateEnvironmentRequest(appConfig)) {
10
13
  res.status(400);
11
14
  res.send(descriptions.UNRESOLVABLE.INVALID_ENVIRONMENT(req.params.environment).message);
12
15
  return;
@@ -18,7 +21,6 @@ function createViewMiddleware(route, errorRoutes, context, viewHandler) {
18
21
  }
19
22
  const { runtimeEnvironment, runtimeParams } = req.getRuntimeContext(context.runtimeEnvironment);
20
23
  // set the default environment if an environment is configured in the app config
21
- const { environment: environmentConfig } = context.appConfig;
22
24
  if (!runtimeParams.environment && environmentConfig?.default) {
23
25
  runtimeParams.environment = environmentConfig.default;
24
26
  }
@@ -32,7 +34,14 @@ function createViewMiddleware(route, errorRoutes, context, viewHandler) {
32
34
  let viewResponse;
33
35
  let resolvedRoute;
34
36
  try {
35
- viewResponse = await resolve.call(viewHandler, viewRequest, route, runtimeEnvironment, runtimeParams);
37
+ viewResponse = await getTracer().trace({
38
+ name: RequestHandlerSpan.GetView,
39
+ attributes: {
40
+ view: route.id,
41
+ },
42
+ }, () => {
43
+ return resolve.call(viewHandler, viewRequest, route, runtimeEnvironment, runtimeParams);
44
+ });
36
45
  resolvedRoute = route;
37
46
  }
38
47
  catch (err) {
@@ -42,7 +51,14 @@ function createViewMiddleware(route, errorRoutes, context, viewHandler) {
42
51
  // Log Unexpected Routing Errors
43
52
  logger.error(`[view-middleware] Route Error ${req.originalUrl}`);
44
53
  logger.error(err);
45
- viewResponse = await resolve.call(viewHandler, viewRequest, errorRoute, runtimeEnvironment, runtimeParams);
54
+ viewResponse = await getTracer().trace({
55
+ name: RequestHandlerSpan.GetView,
56
+ attributes: {
57
+ view: errorRoute.id,
58
+ },
59
+ }, () => {
60
+ return resolve.call(viewHandler, viewRequest, errorRoute, runtimeEnvironment, runtimeParams);
61
+ });
46
62
  resolvedRoute = errorRoute;
47
63
  }
48
64
  if (req.isSiteGeneration()) {
@@ -125,13 +141,20 @@ export function viewMiddleware(app, context) {
125
141
  }
126
142
  // Add localized routes
127
143
  if (i18n.uriPattern === 'path-prefix') {
128
- const supportedStr = i18n.locales.map((l) => l.id).join('|');
144
+ // Add a redirect handler for the default locale for each route /en-US/home -> 301 /home
145
+ const defaultLocalePaths = paths.map((routePath) => `/${i18n.defaultLocale}${routePath}`);
146
+ // Map all supported locale ids into an array. Filter out the default one. It will be handled separately
147
+ const supportedStr = i18n.locales
148
+ .map((l) => l.id)
149
+ .filter((id) => id !== i18n.defaultLocale)
150
+ .join('|');
129
151
  paths.forEach((routePath) => {
130
152
  const localizedPath = `/:locale(${supportedStr})${routePath}`;
131
- logger.debug(`[view-middleware] Add localized path ${localizedPath}`);
132
153
  paths.push(localizedPath);
133
154
  });
155
+ addDefaultLocaleRedirects(i18n.defaultLocale, defaultLocalePaths, app);
134
156
  }
157
+ logger.debug(`[view-middleware] Add view paths ${paths}`);
135
158
  app.get(paths, handleErrors(createViewMiddleware(route, errorRoutes, context, viewHandler)));
136
159
  }
137
160
  // create and attach middleware for bootstrap configurations
@@ -140,4 +163,21 @@ export function viewMiddleware(app, context) {
140
163
  // NOTE: a greedy `all` is used over `use` due to the way middleware is mounted in the server abstraction
141
164
  app.get('/' + app.getRegexWildcard(), handleErrors(createNotFoundMiddleware(errorRoutes, context, viewHandler)));
142
165
  }
166
+ /**
167
+ * Adds a 301 redirect if attempting to route with default locale as the path prefix
168
+ */
169
+ function addDefaultLocaleRedirects(defaultLocale, defaultLocalePaths, app) {
170
+ logger.debug(`[view-middleware] Add default localized paths ${defaultLocalePaths}`);
171
+ app.get(defaultLocalePaths, (req, res) => {
172
+ // Get the original URL path and split it into segments
173
+ let modifiedPath = req.originalUrl.replace(`/${defaultLocale}`, '');
174
+ // Make sure there is a leading slash. Redirect to '' causes an infinite loop.
175
+ if (modifiedPath.indexOf('/') !== 0) {
176
+ modifiedPath = `/${modifiedPath}`;
177
+ }
178
+ // Perform a 301 redirect to the modified URL
179
+ res.setHeader('Location', modifiedPath);
180
+ return res.sendStatus(301);
181
+ });
182
+ }
143
183
  //# sourceMappingURL=view-middleware.js.map
@@ -1,3 +1,4 @@
1
+ export { requestProcessorMiddleware } from './middleware/request-processor-middleware.js';
1
2
  export { localeMiddleware } from './middleware/locale-middleware.js';
2
3
  export { hmrMiddleware } from './middleware/hmr-middleware.js';
3
4
  export { moduleMiddleware } from './middleware/module-middleware.js';
@@ -2,6 +2,7 @@
2
2
  // handler bundle size. For example, importing `@lwrjs/core` will pull in ALL `@lwrjs/server` dependencies
3
3
  // which includes both `koa` and `express`. Importing `@lwrjs/core/middleware` will only pull in the
4
4
  // middleware dependencies.
5
+ export { requestProcessorMiddleware } from './middleware/request-processor-middleware.js';
5
6
  export { localeMiddleware } from './middleware/locale-middleware.js';
6
7
  export { hmrMiddleware } from './middleware/hmr-middleware.js';
7
8
  export { moduleMiddleware } from './middleware/module-middleware.js';
@@ -2,14 +2,14 @@ import SiteGenerator from './static-generation.js';
2
2
  import { skipDirCreation } from './utils/dir.js';
3
3
  import NetworkDispatcher from './utils/network-dispatcher.js';
4
4
  import { getRuntimeEnvironment } from '@lwrjs/config';
5
- import { logger, WARN, INFO } from '@lwrjs/shared-utils';
5
+ import { logger, WARN, INFO } from '@lwrjs/diagnostics';
6
6
  export async function warmupServer(config, internalRequestKey) {
7
7
  // De-duplicate warming messages if log level is warn or info
8
8
  if (!logger.currentLevel || logger.currentLevel == WARN || logger.currentLevel == INFO) {
9
9
  logger.setOptions({ dedupe: new Set([WARN]) });
10
10
  }
11
11
  logger.info('[Server Warmup] starting');
12
- const { routes, staticSiteGenerator, port, basePath } = config;
12
+ const { basePath, port, routes, staticSiteGenerator } = config;
13
13
  staticSiteGenerator.outputDir = skipDirCreation;
14
14
  const urlRewriteMap = new Map();
15
15
  const runtimeEnvironment = getRuntimeEnvironment(config);
@@ -15,6 +15,10 @@ export default class SiteGenerator {
15
15
  * Crawl all view routes for a site
16
16
  */
17
17
  generateRoutes(runtimeEnvironment: RuntimeEnvironment, staticSiteGenerator: StaticSiteGenerator, routes: LwrRoute[], basePath: string, dispatcher: LwrDispatcher, outputDir: string, urlRewriteMap?: Map<string, string>): Promise<void>;
18
+ /**
19
+ * Generate all routes for a given locale
20
+ */
21
+ private generateRoutesForLocale;
18
22
  /**
19
23
  * Creates a function to dispatch the root requests for a given view url
20
24
  */
@@ -1,10 +1,11 @@
1
1
  import { performance } from 'perf_hooks';
2
- import { getSpecifier, getFeatureFlags, hashContent, isSelfUrl, getModuleUriPrefix, getMappingUriPrefix, logger, WARN, INFO, isExternalUrl, mimeLookup, } from '@lwrjs/shared-utils';
2
+ import { logger, WARN, INFO } from '@lwrjs/diagnostics';
3
+ import { getSpecifier, getFeatureFlags, hashContent, isSelfUrl, getModuleUriPrefix, getMappingUriPrefix, isExternalUrl, mimeLookup, getViewUri, sortLocalesByFallback, } from '@lwrjs/shared-utils';
3
4
  import { SiteMetadataImpl } from '@lwrjs/static/site-metadata';
4
5
  import { join, dirname, extname, normalize } from 'path';
5
6
  import fs from 'fs-extra';
6
7
  import { writeResponse } from './utils/stream.js';
7
- import { createDir, createResourceDir } from './utils/dir.js';
8
+ import { createResourceDir } from './utils/dir.js';
8
9
  import { getRuntimeEnvironment } from '@lwrjs/config';
9
10
  export default class SiteGenerator {
10
11
  /**
@@ -23,7 +24,7 @@ export default class SiteGenerator {
23
24
  if (!logger.currentLevel || logger.currentLevel == WARN || logger.currentLevel == INFO) {
24
25
  logger.setOptions({ dedupe: new Set([WARN]) });
25
26
  }
26
- const { routes, staticSiteGenerator, rootDir, assets } = config;
27
+ const { assets, basePath, rootDir, routes, staticSiteGenerator } = config;
27
28
  if (!staticSiteGenerator.outputDir) {
28
29
  staticSiteGenerator.outputDir = 'site';
29
30
  }
@@ -36,7 +37,6 @@ export default class SiteGenerator {
36
37
  logger.info(`[SSG] Reusing existing output directory: ${outputDir}`);
37
38
  }
38
39
  const urlRewriteMap = new Map();
39
- const { basePath } = config;
40
40
  const runtimeEnvironment = getRuntimeEnvironment(config);
41
41
  // For each locale, generate all the modules
42
42
  logger.info(`[SSG] Building routes (this may take some time to complete)`);
@@ -53,43 +53,60 @@ export default class SiteGenerator {
53
53
  * Crawl all view routes for a site
54
54
  */
55
55
  async generateRoutes(runtimeEnvironment, staticSiteGenerator, routes, basePath, dispatcher, outputDir, urlRewriteMap = new Map()) {
56
- if (!staticSiteGenerator.locales) {
57
- staticSiteGenerator.locales = ['en-US'];
58
- }
59
56
  const generateUrl = this.createGenerateURLFunction(dispatcher);
60
57
  // Note: generateUrl can consume a lot of memory so we need to do this sequentially
61
58
  const { skipBaseDocumentGeneration = false } = staticSiteGenerator;
62
- for (const locale of staticSiteGenerator.locales) {
59
+ const i18n = runtimeEnvironment.i18n;
60
+ // If there is not a know URL pattern it is expected the app is accounting with the locale in the routes
61
+ if (!i18n.uriPattern) {
62
+ // eslint-disable-next-line no-await-in-loop
63
+ await this.generateRoutesForLocale(routes, outputDir, { id: i18n.defaultLocale }, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment, basePath, generateUrl, staticSiteGenerator, dispatcher);
64
+ }
65
+ else {
66
+ // Run through locales in fallback sorted order
67
+ const sortedLocales = sortLocalesByFallback(i18n);
63
68
  // Generate all the routes
64
- for (const route of routes) {
65
- const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment);
69
+ for (const locale of sortedLocales) {
70
+ logger.debug(`[SSG] Generate routes of locale: ${locale.id}`);
66
71
  // eslint-disable-next-line no-await-in-loop
67
- await generateUrl(basePath + route.path, siteConfig);
68
- }
69
- // Generate any additional urls
70
- if (staticSiteGenerator._additionalRoutePaths) {
71
- for (const uri of staticSiteGenerator._additionalRoutePaths) {
72
- const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment);
73
- // eslint-disable-next-line no-await-in-loop
74
- await generateUrl(uri, siteConfig);
75
- }
72
+ await this.generateRoutesForLocale(routes, outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment, basePath, generateUrl, staticSiteGenerator, dispatcher);
76
73
  }
77
- // Handle _additionalModules specifiers
78
- const { _additionalModules } = staticSiteGenerator;
79
- if (_additionalModules) {
80
- for (const specifier of _additionalModules) {
81
- logger.debug(`[SSG] Additional Module: ${locale} ${specifier}`);
82
- const startTime = performance.now();
83
- const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment);
84
- // eslint-disable-next-line no-await-in-loop
85
- await this.dispatchJSResourceRecursive(specifier, dispatcher, siteConfig, true);
86
- // Capture any additional collected metadata
87
- // eslint-disable-next-line no-await-in-loop
88
- await this.captureAdditionalRouteMetadata(siteConfig);
89
- const endTime = performance.now();
90
- const timeDiff = endTime - startTime;
91
- logger.info(`[SSG] Additional Module ${locale} ${specifier} in ${Math.round(timeDiff)} ms`);
92
- }
74
+ }
75
+ }
76
+ /**
77
+ * Generate all routes for a given locale
78
+ */
79
+ async generateRoutesForLocale(routes, outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment, basePath, generateUrl, staticSiteGenerator, dispatcher) {
80
+ const i18n = runtimeEnvironment.i18n;
81
+ for (const route of routes) {
82
+ const siteConfig = this.createSiteConfig(outputDir, locale.id, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment, i18n);
83
+ const localizedPath = getViewUri(route.path, basePath, locale.id, i18n);
84
+ // eslint-disable-next-line no-await-in-loop
85
+ await generateUrl(localizedPath, siteConfig);
86
+ }
87
+ // Generate any additional urls
88
+ if (staticSiteGenerator._additionalRoutePaths) {
89
+ for (const uri of staticSiteGenerator._additionalRoutePaths) {
90
+ const siteConfig = this.createSiteConfig(outputDir, locale.id, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment, i18n);
91
+ // eslint-disable-next-line no-await-in-loop
92
+ await generateUrl(uri, siteConfig);
93
+ }
94
+ }
95
+ // Handle _additionalModules specifiers
96
+ const { _additionalModules } = staticSiteGenerator;
97
+ if (_additionalModules) {
98
+ for (const specifier of _additionalModules) {
99
+ logger.debug(`[SSG] Additional Module: ${locale.id} ${specifier}`);
100
+ const startTime = performance.now();
101
+ const siteConfig = this.createSiteConfig(outputDir, locale.id, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment, i18n);
102
+ // eslint-disable-next-line no-await-in-loop
103
+ await this.dispatchJSResourceRecursive(specifier, dispatcher, siteConfig, true);
104
+ // Capture any additional collected metadata
105
+ // eslint-disable-next-line no-await-in-loop
106
+ await this.captureAdditionalRouteMetadata(siteConfig);
107
+ const endTime = performance.now();
108
+ const timeDiff = endTime - startTime;
109
+ logger.info(`[SSG] Additional Module ${locale.id} ${specifier} in ${Math.round(timeDiff)} ms`);
93
110
  }
94
111
  }
95
112
  }
@@ -233,13 +250,18 @@ export default class SiteGenerator {
233
250
  }
234
251
  addBundleToSiteMetadata(bundleDefinition, url, siteConfig) {
235
252
  if (siteConfig.siteMetadata) {
236
- const specifier = bundleDefinition.specifier;
253
+ const locale = siteConfig.locale;
254
+ const specifier = siteConfig.i18n.defaultLocale === locale
255
+ ? bundleDefinition.specifier
256
+ : `${bundleDefinition.specifier}|l/${locale}`;
237
257
  const imports = bundleDefinition.bundleRecord.imports?.map((moduleRef) => getSpecifier(moduleRef)) || [];
258
+ const dynamicImports = bundleDefinition.bundleRecord.dynamicImports?.map((moduleRef) => getSpecifier(moduleRef));
238
259
  const bundleMetadata = {
239
260
  version: bundleDefinition.version,
240
261
  path: decodeURIComponent(url),
241
262
  includedModules: bundleDefinition.bundleRecord.includedModules || [],
242
263
  imports,
264
+ dynamicImports,
243
265
  };
244
266
  const siteBundles = siteConfig.siteMetadata.getSiteBundles().bundles;
245
267
  siteBundles[specifier] = bundleMetadata;
@@ -343,24 +365,15 @@ export default class SiteGenerator {
343
365
  directoryPath = url.substring(0, lastPathIndex);
344
366
  }
345
367
  const dir = createResourceDir(directoryPath, outputDir);
346
- const localeDir = createResourceDir(directoryPath, join(outputDir, siteConfig.locale));
347
368
  // TODO: Should we handle routes with non-html extensions differently?
348
369
  // Example Route: "path": "/mixed_templates.md" (not sure why you would do this)
349
370
  // "contentTemplate": "$contentDir/composed_markdown.md"
350
371
  // Today this will get written to /mixed_templates.md/index.html
351
372
  // Which we workaround by setting "renderSingle": true in serve.json
352
373
  const filePath = join(dir, fileName);
353
- const fileLocalePath = join(localeDir, fileName);
354
- // Default Path (only write once)
355
- // The default locale is english
356
- if (siteConfig.locale.toLowerCase().startsWith('en')) {
357
- siteConfig.viewPaths.add(filePath);
358
- await writeResponse(context, filePath);
359
- }
360
- // Language path (always write out)
361
- createDir(localeDir);
362
- siteConfig.viewPaths.add(fileLocalePath);
363
- await writeResponse(context, fileLocalePath);
374
+ // Write out response
375
+ siteConfig.viewPaths.add(filePath);
376
+ await writeResponse(context, filePath);
364
377
  }
365
378
  // Get the metadata
366
379
  const viewDefinition = context.fs?.metadata?.viewDefinition;
@@ -549,7 +562,7 @@ export default class SiteGenerator {
549
562
  const { basePath } = config;
550
563
  const runtimeEnvironment = getRuntimeEnvironment(config);
551
564
  const siteConfig = this.createSiteConfig(outputDir, 'en-US', // Copy Assets should not use the locale
552
- new Map(), true, runtimeEnvironment);
565
+ new Map(), true, runtimeEnvironment, config.i18n);
553
566
  for (const asset of assets) {
554
567
  try {
555
568
  const assetSrcFile = asset.file;
@@ -614,14 +627,14 @@ export default class SiteGenerator {
614
627
  this.addAssetToSiteMetadata({
615
628
  uri,
616
629
  type: 'asset',
617
- stream: function (encoding) {
630
+ stream: function (_encoding) {
618
631
  throw new Error('Function not implemented.');
619
632
  },
620
633
  entry: filePath,
621
634
  ext: extname(filePath),
622
635
  mime: mimeLookup(filePath),
623
636
  ownHash: 'not-provided',
624
- content: function (encoding) {
637
+ content: function (_encoding) {
625
638
  throw new Error('Function not implemented.');
626
639
  },
627
640
  }, uri, siteConfig);
@@ -633,7 +646,7 @@ export default class SiteGenerator {
633
646
  /**
634
647
  * Create a new site config for the current view
635
648
  */
636
- createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment) {
649
+ createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment, i18n) {
637
650
  const featureFlags = this.filterFeatureFlags();
638
651
  const endpoints = {
639
652
  uris: {
@@ -653,6 +666,7 @@ export default class SiteGenerator {
653
666
  // Only include LEGACY_LOADER if true
654
667
  ...featureFlags,
655
668
  siteMetadata: new SiteMetadataImpl({ rootDir: outputDir }),
669
+ i18n,
656
670
  };
657
671
  }
658
672
  filterFeatureFlags() {
@@ -1,4 +1,4 @@
1
- import type { Endpoints, FeatureFlags, ImportMetadata, RenderedAssetReference, SiteMetadata } from '@lwrjs/types';
1
+ import type { Endpoints, FeatureFlags, I18NConfig, ImportMetadata, RenderedAssetReference, SiteMetadata } from '@lwrjs/types';
2
2
  export interface BaseResourceContextOpts {
3
3
  resourceType: 'route' | 'asset' | 'js' | 'resource' | 'mapping';
4
4
  }
@@ -36,6 +36,7 @@ export interface SiteConfig {
36
36
  viewPaths: Set<string>;
37
37
  visitedUrls: Set<string>;
38
38
  locale: string;
39
+ i18n: I18NConfig;
39
40
  urlRewriteMap: Map<string, string>;
40
41
  endpoints?: Endpoints;
41
42
  importMetadata?: ViewImportMetadata;
@@ -1,6 +1,7 @@
1
1
  import http from 'http';
2
2
  import https from 'https';
3
- import { DEBUG, isModuleOrBundleUrl, logger, VERBOSE } from '@lwrjs/shared-utils';
3
+ import { logger, DEBUG, VERBOSE } from '@lwrjs/diagnostics';
4
+ import { isModuleOrBundleUrl } from '@lwrjs/shared-utils';
4
5
  export default class NetworkDispatcher {
5
6
  constructor(port, internalRequestKey) {
6
7
  this.port = port || 3000;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.11.0-alpha.8",
7
+ "version": "0.11.0",
8
8
  "homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
9
9
  "repository": {
10
10
  "type": "git",
@@ -39,31 +39,33 @@
39
39
  "build": "tsc -b"
40
40
  },
41
41
  "dependencies": {
42
- "@lwrjs/app-service": "0.11.0-alpha.8",
43
- "@lwrjs/asset-registry": "0.11.0-alpha.8",
44
- "@lwrjs/asset-transformer": "0.11.0-alpha.8",
45
- "@lwrjs/base-view-provider": "0.11.0-alpha.8",
46
- "@lwrjs/base-view-transformer": "0.11.0-alpha.8",
47
- "@lwrjs/client-modules": "0.11.0-alpha.8",
48
- "@lwrjs/config": "0.11.0-alpha.8",
49
- "@lwrjs/diagnostics": "0.11.0-alpha.8",
50
- "@lwrjs/fs-asset-provider": "0.11.0-alpha.8",
51
- "@lwrjs/html-view-provider": "0.11.0-alpha.8",
52
- "@lwrjs/instrumentation": "0.11.0-alpha.8",
53
- "@lwrjs/loader": "0.11.0-alpha.8",
54
- "@lwrjs/lwc-module-provider": "0.11.0-alpha.8",
55
- "@lwrjs/markdown-view-provider": "0.11.0-alpha.8",
56
- "@lwrjs/module-bundler": "0.11.0-alpha.8",
57
- "@lwrjs/module-registry": "0.11.0-alpha.8",
58
- "@lwrjs/npm-module-provider": "0.11.0-alpha.8",
59
- "@lwrjs/nunjucks-view-provider": "0.11.0-alpha.8",
60
- "@lwrjs/o11y": "0.11.0-alpha.8",
61
- "@lwrjs/resource-registry": "0.11.0-alpha.8",
62
- "@lwrjs/router": "0.11.0-alpha.8",
63
- "@lwrjs/server": "0.11.0-alpha.8",
64
- "@lwrjs/shared-utils": "0.11.0-alpha.8",
65
- "@lwrjs/static": "0.11.0-alpha.8",
66
- "@lwrjs/view-registry": "0.11.0-alpha.8",
42
+ "@lwrjs/app-service": "0.11.0",
43
+ "@lwrjs/asset-registry": "0.11.0",
44
+ "@lwrjs/asset-transformer": "0.11.0",
45
+ "@lwrjs/base-view-provider": "0.11.0",
46
+ "@lwrjs/base-view-transformer": "0.11.0",
47
+ "@lwrjs/client-modules": "0.11.0",
48
+ "@lwrjs/config": "0.11.0",
49
+ "@lwrjs/diagnostics": "0.11.0",
50
+ "@lwrjs/esbuild": "0.11.0",
51
+ "@lwrjs/fs-asset-provider": "0.11.0",
52
+ "@lwrjs/fs-watch": "0.11.0",
53
+ "@lwrjs/html-view-provider": "0.11.0",
54
+ "@lwrjs/instrumentation": "0.11.0",
55
+ "@lwrjs/loader": "0.11.0",
56
+ "@lwrjs/lwc-module-provider": "0.11.0",
57
+ "@lwrjs/markdown-view-provider": "0.11.0",
58
+ "@lwrjs/module-bundler": "0.11.0",
59
+ "@lwrjs/module-registry": "0.11.0",
60
+ "@lwrjs/npm-module-provider": "0.11.0",
61
+ "@lwrjs/nunjucks-view-provider": "0.11.0",
62
+ "@lwrjs/o11y": "0.11.0",
63
+ "@lwrjs/resource-registry": "0.11.0",
64
+ "@lwrjs/router": "0.11.0",
65
+ "@lwrjs/server": "0.11.0",
66
+ "@lwrjs/shared-utils": "0.11.0",
67
+ "@lwrjs/static": "0.11.0",
68
+ "@lwrjs/view-registry": "0.11.0",
67
69
  "chokidar": "^3.5.3",
68
70
  "esbuild": "^0.9.7",
69
71
  "fs-extra": "^11.1.1",
@@ -73,11 +75,11 @@
73
75
  "ws": "^8.8.1"
74
76
  },
75
77
  "devDependencies": {
76
- "@lwrjs/types": "0.11.0-alpha.8",
78
+ "@lwrjs/types": "0.11.0",
77
79
  "@types/ws": "^8.5.3"
78
80
  },
79
81
  "peerDependencies": {
80
- "lwc": "2.x || 3.x"
82
+ "lwc": "2.x || 3.x || 4.x"
81
83
  },
82
84
  "engines": {
83
85
  "node": ">=16.0.0"
@@ -85,5 +87,5 @@
85
87
  "volta": {
86
88
  "extends": "../../../package.json"
87
89
  },
88
- "gitHead": "bba3cfa996e84ee702f287e7e7b6361b807434db"
90
+ "gitHead": "fbc883ea90a12672ce6f1adc2201144fda8762bd"
89
91
  }