@lwrjs/core 0.6.0-alpha.1 → 0.6.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/es/index.js CHANGED
@@ -5,6 +5,7 @@ import { LwrModuleRegistry } from '@lwrjs/module-registry';
5
5
  import { LwrResourceRegistry } from '@lwrjs/resource-registry';
6
6
  import { LwrAssetRegistry } from '@lwrjs/asset-registry';
7
7
  import { LwrViewRegistry } from '@lwrjs/view-registry';
8
+ import { LwrServerError, createSingleDiagnosticError, descriptions } from '@lwrjs/diagnostics';
8
9
  import { normalizeConfig, explodeMode } from './env-config.js';
9
10
  import { LwrApplicationObserver } from './lwr-app-observer.js';
10
11
  import localeMiddleware from './middlewares/locale-middleware.js';
@@ -52,10 +53,12 @@ async function initContext(app, server, rawLwrConfig) {
52
53
  };
53
54
  const hookProviders = await getServices(rawLwrConfig.hooks, undefined, rawLwrConfig);
54
55
  const { lwrConfig, dataConfig, runtimeConfig } = await runConfigurationsHook(hookProviders, rawLwrConfig, rawDataConfig, rawRuntimeEnvConfig);
56
+ const assetTransformers = await getServices(rawLwrConfig.assetTransformers, undefined, rawLwrConfig);
55
57
  const appObserver = new LwrApplicationObserver();
56
58
  const appEmitter = appObserver.createLwrEmitter();
57
59
  const compiler = new LwrCompiler();
58
60
  const assetRegistry = new LwrAssetRegistry({
61
+ assetTransformers,
59
62
  appObserver,
60
63
  appEmitter,
61
64
  runtimeEnvironment: runtimeConfig,
@@ -96,9 +99,9 @@ async function initContext(app, server, rawLwrConfig) {
96
99
  const { cacheDir, lwc: { modules = [] }, routes, errorRoutes, rootDir, contentDir, layoutsDir, locker, amdLoader, esmLoader, environment, } = lwrConfig;
97
100
  const { onModuleDefinitionChange, onModuleSourceChange } = appObserver;
98
101
  const { notifyModuleDefinitionChanged, notifyModuleSourceChanged, notifyViewSourceChanged, notifyAssetSourceChanged, } = appEmitter;
99
- const providerContext = deepFreeze({
102
+ const providerContext = {
100
103
  compiler,
101
- appObserver: { onModuleDefinitionChange, onModuleSourceChange },
104
+ appObserver: deepFreeze({ onModuleDefinitionChange, onModuleSourceChange }),
102
105
  appEmitter: {
103
106
  notifyModuleDefinitionChanged: (payload) => notifyModuleDefinitionChanged.call(appEmitter, payload),
104
107
  notifyModuleSourceChanged: (payload) => notifyModuleSourceChanged.call(appEmitter, payload),
@@ -106,10 +109,11 @@ async function initContext(app, server, rawLwrConfig) {
106
109
  notifyAssetSourceChanged: (payload) => notifyAssetSourceChanged.call(appEmitter, payload),
107
110
  },
108
111
  moduleRegistry: moduleRegistry.getPublicApi(),
112
+ moduleBundler: moduleBundler,
109
113
  resourceRegistry: resourceRegistry.getPublicApi(),
110
114
  viewRegistry: viewRegistry.getPublicApi(),
111
115
  assetRegistry: assetRegistry.getPublicApi(),
112
- config: {
116
+ config: deepFreeze({
113
117
  cacheDir,
114
118
  modules,
115
119
  routes,
@@ -121,9 +125,9 @@ async function initContext(app, server, rawLwrConfig) {
121
125
  amdLoader,
122
126
  esmLoader,
123
127
  environment,
124
- },
125
- runtimeEnvironment: runtimeConfig,
126
- });
128
+ }),
129
+ runtimeEnvironment: deepFreeze(runtimeConfig),
130
+ };
127
131
  // Module Providers
128
132
  const moduleProviders = await getServices(lwrConfig.moduleProviders, providerContext, lwrConfig);
129
133
  moduleRegistry.addModuleProviders(moduleProviders);
@@ -132,7 +136,10 @@ async function initContext(app, server, rawLwrConfig) {
132
136
  resourceRegistry.addResourceProviders(resourceProviders);
133
137
  // View Providers
134
138
  const viewProviders = await getServices(lwrConfig.viewProviders, providerContext, lwrConfig);
139
+ // View Transformers
140
+ const viewTransformers = await getServices(rawLwrConfig.viewTransformers, providerContext, rawLwrConfig);
135
141
  viewRegistry.addViewProviders(viewProviders);
142
+ viewRegistry.addViewTransformers(viewTransformers);
136
143
  await viewRegistry.initializeViewProviders();
137
144
  // Asset Providers
138
145
  const assetProviders = await getServices(lwrConfig.assetProviders, providerContext, lwrConfig);
@@ -154,9 +161,15 @@ export class LwrApp {
154
161
  }
155
162
  async init() {
156
163
  if (!this.initialized) {
157
- const context = await initContext(this.app, this.server, this.config);
158
- initMiddlewares(this.app, this.server, context);
159
164
  this.initialized = true;
165
+ try {
166
+ const context = await initContext(this.app, this.server, this.config);
167
+ initMiddlewares(this.app, this.server, context);
168
+ }
169
+ catch (e) {
170
+ this.initialized = false;
171
+ throw e;
172
+ }
160
173
  }
161
174
  }
162
175
  async listen(callback) {
@@ -165,7 +178,14 @@ export class LwrApp {
165
178
  const { serverMode, port } = config;
166
179
  server.listen(port || config.port, async () => {
167
180
  if (process.env.WARMUP?.toLowerCase() === 'true') {
168
- await warmupServer(config, app.getInternalRequestKey());
181
+ try {
182
+ await warmupServer(config, app.getInternalRequestKey());
183
+ }
184
+ catch (err) {
185
+ throw createSingleDiagnosticError({
186
+ description: descriptions.SERVER.WARMUP_ERROR(err.message),
187
+ }, LwrServerError);
188
+ }
169
189
  }
170
190
  callback?.({ serverMode, port });
171
191
  });
@@ -61,20 +61,20 @@ export default function apiMiddleware(app, context) {
61
61
  // TODO might be able to remove this in the future but not sure how to properly send
62
62
  // back bundleRecord imports with absolute uris (lwc is the main one)
63
63
  if (bundleDef.bundleRecord.imports) {
64
- for (let index = 0; index < bundleDef.bundleRecord.imports.length; index++) {
65
- const theImport = bundleDef.bundleRecord.imports[index];
64
+ for (const theImport of bundleDef.bundleRecord.imports) {
65
+ const childSpecifier = theImport.specifier;
66
66
  // eslint-disable-next-line no-await-in-loop
67
- const id = await getVersionedModuleId(theImport.specifier, moduleRegistry);
67
+ const id = await getVersionedModuleId(childSpecifier, moduleRegistry);
68
68
  // eslint-disable-next-line no-await-in-loop
69
69
  const uri = await moduleRegistry.resolveModuleUri(id, runtimeEnvironment, runtimeParams);
70
70
  resolvedUris.push(uri);
71
71
  }
72
72
  }
73
73
  if (bundleDef.bundleRecord.dynamicImports) {
74
- for (let index = 0; index < bundleDef.bundleRecord.dynamicImports.length; index++) {
75
- const theImport = bundleDef.bundleRecord.dynamicImports[index];
74
+ for (const theImport of bundleDef.bundleRecord.dynamicImports) {
75
+ const childSpecifier = theImport.specifier;
76
76
  // eslint-disable-next-line no-await-in-loop
77
- const id = await getVersionedModuleId(theImport.specifier, moduleRegistry);
77
+ const id = await getVersionedModuleId(childSpecifier, moduleRegistry);
78
78
  // eslint-disable-next-line no-await-in-loop
79
79
  const uri = await moduleRegistry.resolveModuleUri(id, runtimeEnvironment, runtimeParams);
80
80
  resolvedUris.push(uri);
@@ -29,7 +29,7 @@ export default function uiMiddleware(app, context) {
29
29
  url: req.originalUrl,
30
30
  params: req.params,
31
31
  query: req.query,
32
- requestPath: req.path,
32
+ requestPath: req.path, // Runtime resolved version vs. the original route path
33
33
  };
34
34
  const response = req.isJsonRequest()
35
35
  ? await viewHandler.getViewJson(viewRequest, route, runtimeEnvironment, runtimeParams)
@@ -85,7 +85,7 @@ export default function uiMiddleware(app, context) {
85
85
  url,
86
86
  params,
87
87
  query: req.query,
88
- requestPath,
88
+ requestPath, // Runtime resolved version vs. the original route path
89
89
  };
90
90
  const response = await viewHandler.getViewConfiguration(viewRequest, route, runtimeEnvironment, runtimeParams);
91
91
  if (!response) {
@@ -2,16 +2,13 @@
2
2
  import http from 'http';
3
3
  import { EnvironmentConfig } from '@lwrjs/types';
4
4
  import qs from 'qs';
5
- interface E extends Error {
6
- code: string;
7
- }
8
5
  /**
9
6
  * Create a status object Express can return when there is an error
10
7
  *
11
8
  * @param name - string name of the problem module/resource
12
- * @param error? - an Error/Diagnostic object
9
+ * @param error - an Error/Diagnostic object; thrown from try/catch
13
10
  */
14
- export declare function createReturnStatus(name: string, error: E): {
11
+ export declare function createReturnStatus(name: string, error: unknown): {
15
12
  status: number;
16
13
  message: string;
17
14
  };
@@ -1,4 +1,4 @@
1
- import { LwrUnresolvableError, descriptions } from '@lwrjs/diagnostics';
1
+ import { LwrUnresolvableError, descriptions, isNodeError } from '@lwrjs/diagnostics';
2
2
  import { pathToRegexp } from 'path-to-regexp';
3
3
  import qs from 'qs';
4
4
  import createDOMPurify from 'dompurify';
@@ -9,11 +9,11 @@ const DOMPurify = createDOMPurify(window);
9
9
  * Create a status object Express can return when there is an error
10
10
  *
11
11
  * @param name - string name of the problem module/resource
12
- * @param error? - an Error/Diagnostic object
12
+ * @param error - an Error/Diagnostic object; thrown from try/catch
13
13
  */
14
14
  export function createReturnStatus(name, error) {
15
15
  let returnStatus = { status: 501, message: '' };
16
- if (error.code === 'NO_LWC_MODULE_FOUND') {
16
+ if (isNodeError(error) && error.code === 'NO_LWC_MODULE_FOUND') {
17
17
  returnStatus = { status: 404, message: descriptions.UNRESOLVABLE.LWC_MODULE(name).message };
18
18
  }
19
19
  else if (error instanceof LwrUnresolvableError &&
@@ -1,5 +1,5 @@
1
- import { LwrDispatcher, StaticSiteGenerator, LwrRoute, NormalizedLwrGlobalConfig } from '@lwrjs/types';
2
- import { ResourceContextOpts, SiteConfig } from './types.js';
1
+ import { ImportMetadata, LwrDispatcher, StaticSiteGenerator, LwrRoute, NormalizedLwrGlobalConfig } from '@lwrjs/types';
2
+ import { ResourceContextOpts, SiteConfig, ViewImportMetadata } from './types.js';
3
3
  export default class SiteGenerator {
4
4
  /**
5
5
  * Build a static site in the configured directory
@@ -87,5 +87,37 @@ export default class SiteGenerator {
87
87
  *
88
88
  */
89
89
  private copyAssets;
90
+ /**
91
+ * Create a new site config for the current view
92
+ */
93
+ private createSiteConfig;
94
+ private filterExperimentalFeatures;
95
+ /**
96
+ * Add any additional import metadata collected during static site generation to the Client Bootstrap Config for this view.
97
+ */
98
+ private addAdditionalImportMetadataToViewConfig;
99
+ }
100
+ export declare class ViewImportMetadataImpl implements ViewImportMetadata {
101
+ private existing;
102
+ private additional;
103
+ constructor(existingImportMetadata: ImportMetadata, additionalImportMetadata?: ImportMetadata);
104
+ /**
105
+ * Get the additional import metadata collected while generating this view
106
+ * @returns
107
+ */
108
+ getAdditionalImportMetadata(): ImportMetadata;
109
+ /**
110
+ * Adds any new imports found to the additional metadata map. Returns a filtered
111
+ * map of imports not in the initial view
112
+ */
113
+ addAdditionalMetadata(newMetadata: ImportMetadata): ImportMetadata;
114
+ /**
115
+ * Filter out any existing import metadata the would have already been sent back with the view from set of additional metadata detected
116
+ */
117
+ private filterMetadata;
118
+ /**
119
+ * Merge new import metadata into target import metadata
120
+ */
121
+ private mergeImportMetadata;
90
122
  }
91
123
  //# sourceMappingURL=static-generation.d.ts.map
@@ -19,7 +19,8 @@ export default class SiteGenerator {
19
19
  staticSiteGenerator.outputDir = '__generated_site__';
20
20
  }
21
21
  const outputDir = join(rootDir, staticSiteGenerator.outputDir);
22
- console.log(`[INFO] Output Location: ${outputDir}`);
22
+ console.log(`[INFO] Clear Output Location: ${outputDir}`);
23
+ fs.rmSync(outputDir, { recursive: true, force: true });
23
24
  const urlRewriteMap = new Map();
24
25
  // For each locale, generate all the modules
25
26
  await this.generateRoutes(staticSiteGenerator, routes, dispatcher, outputDir, urlRewriteMap);
@@ -42,13 +43,13 @@ export default class SiteGenerator {
42
43
  for (const locale of staticSiteGenerator.locales) {
43
44
  // Generate all the routes
44
45
  for (const route of routes) {
45
- const siteConfig = createSiteConfig(outputDir, locale, urlRewriteMap);
46
+ const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap);
46
47
  dispatchRequests.push(generateUrl(route.path, siteConfig));
47
48
  }
48
49
  // Generate any additional urls
49
50
  if (staticSiteGenerator._additionalRoutePaths) {
50
51
  for (const uri of staticSiteGenerator._additionalRoutePaths) {
51
- const siteConfig = createSiteConfig(outputDir, locale, urlRewriteMap);
52
+ const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap);
52
53
  dispatchRequests.push(generateUrl(uri, siteConfig));
53
54
  }
54
55
  }
@@ -66,7 +67,7 @@ export default class SiteGenerator {
66
67
  // Kick off site generation for the current route
67
68
  await this.dispatchResourceRecursive(uri, dispatcher, { resourceType: 'route' }, siteConfig);
68
69
  // If there is a view config add any extra collected import metadata to the config
69
- addAdditionalImportMetadataToViewConfig(siteConfig);
70
+ this.addAdditionalImportMetadataToViewConfig(siteConfig);
70
71
  console.log(`[INFO] End Generate ${locale} ${uri}`);
71
72
  };
72
73
  return generateRoute.bind(this);
@@ -171,16 +172,18 @@ export default class SiteGenerator {
171
172
  * @param dispatcher - Network dispatcher
172
173
  */
173
174
  async handleMappingResource(url, context, siteConfig, dispatcher) {
174
- const { additionalImportMetadata: importMetadata } = siteConfig;
175
+ const { importMetadata: importMetatdata } = siteConfig;
175
176
  const statusCode = context.response?.status;
176
177
  // Received a server error
177
178
  if (statusCode === 200) {
178
179
  // Read JSON
179
180
  const newImportMetadata = context.fs?.body;
181
+ if (!importMetatdata) {
182
+ console.warn('[WARN] Import metadata collector was never initialized');
183
+ return;
184
+ }
180
185
  // Filter out and import metadata already included with the view
181
- const filteredImportMetadata = filterMetadata(siteConfig.existingImportMetadata, newImportMetadata);
182
- // Merge Imports with global collection
183
- mergeImportMetadata(importMetadata, filteredImportMetadata);
186
+ const filteredImportMetadata = importMetatdata.addAdditionalMetadata(newImportMetadata);
184
187
  // Build up a list of dispatch requests to kick off in parallel
185
188
  const dispatchRequests = [];
186
189
  // Iterate through the import mappings and return request uris
@@ -239,7 +242,8 @@ export default class SiteGenerator {
239
242
  siteConfig.endpoints = viewDefinition.viewRecord.endpoints;
240
243
  // Save existing import metadata
241
244
  if (viewDefinition.viewRecord.importMetadata) {
242
- mergeImportMetadata(siteConfig.existingImportMetadata, viewDefinition.viewRecord.importMetadata);
245
+ // Initialize import metadata collector
246
+ siteConfig.importMetadata = new ViewImportMetadataImpl(viewDefinition.viewRecord.importMetadata);
243
247
  }
244
248
  // Build up a list of dispatch requests to kick off in parallel
245
249
  const dispatchRequests = [];
@@ -396,74 +400,97 @@ export default class SiteGenerator {
396
400
  }
397
401
  }
398
402
  }
399
- }
400
- /**
401
- * Add any additional import metadata collected during static site generation to the Client Bootstrap Config for this view.
402
- */
403
- function addAdditionalImportMetadataToViewConfig(siteConfig) {
404
- const supportsFingerprints = siteConfig.experimentalFeatures?.ENABLE_FINGERPRINTS;
405
- if (supportsFingerprints &&
406
- siteConfig.viewConfigPath &&
407
- Object.keys(siteConfig.additionalImportMetadata.imports).length > 0) {
408
- const imports = siteConfig.additionalImportMetadata.imports
409
- ? JSON.stringify(siteConfig.additionalImportMetadata.imports)
410
- : '{}';
411
- const initImports = `if (!globalThis.LWR.imports) { globalThis.LWR.imports = {}; }`;
412
- const mergeImports = `Object.assign(globalThis.LWR.imports, ${imports})`;
413
- const index = siteConfig.additionalImportMetadata.index
414
- ? JSON.stringify(siteConfig.additionalImportMetadata.index)
415
- : '{}';
416
- const initIndex = `if (!globalThis.LWR.index) { globalThis.LWR.index = {}; }`;
417
- const mergeIndex = `Object.assign(globalThis.LWR.index, ${index})`;
418
- fs.appendFileSync(siteConfig.viewConfigPath, `\n// Appended by Static Site Generator\n${initImports}\n${mergeImports}\n${initIndex}\n${mergeIndex}\n`);
403
+ /**
404
+ * Create a new site config for the current view
405
+ */
406
+ createSiteConfig(outputDir, locale, urlRewriteMap) {
407
+ const experimentalFeatures = this.filterExperimentalFeatures();
408
+ return {
409
+ outputDir,
410
+ visitedUrls: new Set(),
411
+ locale,
412
+ urlRewriteMap,
413
+ // Only include ENABLE_FINGERPRINTS if true
414
+ ...experimentalFeatures,
415
+ };
419
416
  }
420
- }
421
- /**
422
- * Create a new site config for the current view
423
- */
424
- function createSiteConfig(outputDir, locale, urlRewriteMap) {
425
- const experimentalFeatures = filterExperimentalFeatures();
426
- return {
427
- outputDir,
428
- visitedUrls: new Set(),
429
- locale,
430
- urlRewriteMap,
431
- existingImportMetadata: { imports: {}, index: {} },
432
- additionalImportMetadata: { imports: {}, index: {} },
433
- // Only include ENABLE_FINGERPRINTS if true
434
- ...experimentalFeatures,
435
- };
436
- }
437
- function filterExperimentalFeatures() {
438
- if (getExperimentalFeatures().ENABLE_FINGERPRINTS) {
439
- return { experimentalFeatures: { ENABLE_FINGERPRINTS: true } };
417
+ filterExperimentalFeatures() {
418
+ if (getExperimentalFeatures().ENABLE_FINGERPRINTS) {
419
+ return { experimentalFeatures: { ENABLE_FINGERPRINTS: true } };
420
+ }
421
+ else {
422
+ return undefined;
423
+ }
440
424
  }
441
- else {
442
- return undefined;
425
+ /**
426
+ * Add any additional import metadata collected during static site generation to the Client Bootstrap Config for this view.
427
+ */
428
+ addAdditionalImportMetadataToViewConfig(siteConfig) {
429
+ const supportsFingerprints = siteConfig.experimentalFeatures?.ENABLE_FINGERPRINTS;
430
+ const additionalImportMetadata = siteConfig?.importMetadata?.getAdditionalImportMetadata();
431
+ if (supportsFingerprints &&
432
+ siteConfig.viewConfigPath &&
433
+ additionalImportMetadata?.imports &&
434
+ Object.keys(additionalImportMetadata.imports).length > 0) {
435
+ const imports = additionalImportMetadata.imports
436
+ ? JSON.stringify(additionalImportMetadata.imports)
437
+ : '{}';
438
+ const initImports = `if (!globalThis.LWR.imports) { globalThis.LWR.imports = {}; }`;
439
+ const mergeImports = `Object.assign(globalThis.LWR.imports, ${imports})`;
440
+ const index = additionalImportMetadata.index
441
+ ? JSON.stringify(additionalImportMetadata.index)
442
+ : '{}';
443
+ const initIndex = `if (!globalThis.LWR.index) { globalThis.LWR.index = {}; }`;
444
+ const mergeIndex = `Object.assign(globalThis.LWR.index, ${index})`;
445
+ fs.appendFileSync(siteConfig.viewConfigPath, `\n// Appended by Static Site Generator\n${initImports}\n${mergeImports}\n${initIndex}\n${mergeIndex}\n`);
446
+ }
443
447
  }
444
448
  }
445
- /**
446
- * Merge new import metadata into target import metadata
447
- */
448
- function mergeImportMetadata(targetImportMetdadata, newImportMetadata) {
449
- Object.assign(targetImportMetdadata.imports, newImportMetadata.imports);
450
- Object.assign(targetImportMetdadata.index, newImportMetadata.index);
451
- }
452
- /**
453
- * Filter out any existing import metadata the would have already been sent back with the view from set of additional metadata detected
454
- */
455
- function filterMetadata(existingMetadata, newMetadata) {
456
- // Filter Imports
457
- const importsArray = Object.entries(newMetadata.imports);
458
- const filteredImports = importsArray.filter(([key]) => !existingMetadata.imports[key]);
459
- const imports = Object.fromEntries(filteredImports);
460
- // Filter Index
461
- const indexArray = Object.entries(newMetadata.index || {});
462
- const filteredIndex = indexArray.filter(([key]) => !existingMetadata.index || !existingMetadata.index[key]);
463
- const index = Object.fromEntries(filteredIndex);
464
- return {
465
- imports,
466
- index,
467
- };
449
+ // Class used to track import metadata for a view
450
+ export class ViewImportMetadataImpl {
451
+ constructor(existingImportMetadata, additionalImportMetadata) {
452
+ this.existing = existingImportMetadata;
453
+ this.additional = additionalImportMetadata || { imports: {}, index: {} };
454
+ }
455
+ /**
456
+ * Get the additional import metadata collected while generating this view
457
+ * @returns
458
+ */
459
+ getAdditionalImportMetadata() {
460
+ return this.additional;
461
+ }
462
+ /**
463
+ * Adds any new imports found to the additional metadata map. Returns a filtered
464
+ * map of imports not in the initial view
465
+ */
466
+ addAdditionalMetadata(newMetadata) {
467
+ const filteredImports = this.filterMetadata(newMetadata);
468
+ this.mergeImportMetadata(this.additional, filteredImports);
469
+ return filteredImports;
470
+ }
471
+ /**
472
+ * Filter out any existing import metadata the would have already been sent back with the view from set of additional metadata detected
473
+ */
474
+ filterMetadata(newMetadata) {
475
+ // Filter Imports
476
+ const importsArray = Object.entries(newMetadata.imports);
477
+ const filteredImports = importsArray.filter(([key]) => !this.existing.imports[key]);
478
+ const imports = Object.fromEntries(filteredImports);
479
+ // Filter Index
480
+ const indexArray = Object.entries(newMetadata.index || {});
481
+ const filteredIndex = indexArray.filter(([key]) => !this.existing.index || !this.existing.index[key]);
482
+ const index = Object.fromEntries(filteredIndex);
483
+ return {
484
+ imports,
485
+ index,
486
+ };
487
+ }
488
+ /**
489
+ * Merge new import metadata into target import metadata
490
+ */
491
+ mergeImportMetadata(targetImportMetdadata, newImportMetadata) {
492
+ Object.assign(targetImportMetdadata.imports, newImportMetadata.imports);
493
+ Object.assign(targetImportMetdadata.index, newImportMetadata.index);
494
+ }
468
495
  }
469
496
  //# sourceMappingURL=static-generation.js.map
@@ -20,14 +20,25 @@ export interface MappingResourceOpts extends BaseResourceContextOpts {
20
20
  resourceType: 'mapping';
21
21
  }
22
22
  export declare type ResourceContextOpts = RouteResourceOpts | AssetResourceOpts | JsResourceOpts | ResResourceOpts | MappingResourceOpts;
23
+ export interface ViewImportMetadata {
24
+ /**
25
+ * Get the additional import metadata collected while generating this view
26
+ * @returns
27
+ */
28
+ getAdditionalImportMetadata(): ImportMetadata;
29
+ /**
30
+ * Adds any new imports found to the additional metadata map. Returns a filtered
31
+ * map of imports not in the initial view
32
+ */
33
+ addAdditionalMetadata(newMetadata: ImportMetadata): ImportMetadata;
34
+ }
23
35
  export interface SiteConfig {
24
36
  outputDir: string;
25
37
  visitedUrls: Set<string>;
26
38
  locale: string;
27
39
  urlRewriteMap: Map<string, string>;
28
- existingImportMetadata: ImportMetadata;
29
- additionalImportMetadata: ImportMetadata;
30
40
  endpoints?: Endpoints;
41
+ importMetadata?: ViewImportMetadata;
31
42
  viewConfigPath?: string;
32
43
  experimentalFeatures?: ExperimentalFeatures;
33
44
  }
@@ -1,7 +1,10 @@
1
+ /// <reference types="node" />
2
+ import http from 'http';
1
3
  import { LwrDispatcher, FsContext } from '@lwrjs/types';
2
4
  export default class NetworkDispatcher implements LwrDispatcher {
3
5
  port: number;
4
6
  internalRequestKey: string;
7
+ pool: http.Agent;
5
8
  constructor(port: number, internalRequestKey: string);
6
9
  dispatchUrl(url: string, method: string, lang: string): Promise<FsContext>;
7
10
  }
@@ -1,8 +1,13 @@
1
1
  import http from 'http';
2
2
  import https from 'https';
3
+ import { DiagnosticsError } from '@lwrjs/diagnostics';
3
4
  export default class NetworkDispatcher {
4
5
  constructor(port, internalRequestKey) {
5
6
  this.port = port || 3000;
7
+ const httpClient = this.port == 443 ? https : http;
8
+ this.pool = new httpClient.Agent({
9
+ maxSockets: 25,
10
+ });
6
11
  this.internalRequestKey = internalRequestKey || '';
7
12
  }
8
13
  dispatchUrl(url, method, lang) {
@@ -11,6 +16,7 @@ export default class NetworkDispatcher {
11
16
  host: 'localhost',
12
17
  port: this.port,
13
18
  path: url,
19
+ agent: this.pool,
14
20
  headers: {
15
21
  'Accept-Language': lang,
16
22
  // pass private key to get access to internal metadata
@@ -20,24 +26,42 @@ export default class NetworkDispatcher {
20
26
  return new Promise((resolve, reject) => {
21
27
  const httpClient = options.port == 443 ? https : http;
22
28
  const bodyChunks = [];
29
+ // console.log(`[INFO][NetworkDispatcher] Request: [${method}][${lang}] ${url}`);
23
30
  const req = httpClient.request(options, (res) => {
24
31
  res.on('data', (chunk) => {
25
32
  bodyChunks.push(chunk);
26
33
  });
27
34
  res.on('end', () => {
35
+ // console.log(`[END][NetworkDispatcher] Request: [${method}][${lang}] ${url}`);
28
36
  const body = Buffer.concat(bodyChunks).toString();
29
37
  try {
30
38
  const jsonResponse = JSON.parse(body);
31
39
  resolve(jsonResponse);
32
40
  }
33
41
  catch (e) {
34
- console.error(`[NetworkDispatcher] unexpected response body: '${body}'`, e);
42
+ console.error(`[ERROR][NetworkDispatcher] unexpected response body: [${method}][${lang}] ${url}: '${body}'`);
43
+ if (e instanceof DiagnosticsError) {
44
+ console.log('LWR Diagnostic Error: ');
45
+ console.log(e.diagnostics);
46
+ console.log(e.stack);
47
+ }
48
+ else {
49
+ console.error(e);
50
+ }
35
51
  resolve({});
36
52
  }
37
53
  });
38
54
  });
39
55
  req.on('error', (err) => {
40
- console.error('Error occurred fetching metadata: ' + err.message);
56
+ console.error(`[ERROR][NetworkDispatcher] Request: [${method}][${lang}] ${url}`);
57
+ if (err instanceof DiagnosticsError) {
58
+ console.log('LWR Diagnostic Error: ');
59
+ console.log(err.diagnostics);
60
+ console.log(err.stack);
61
+ }
62
+ else {
63
+ console.error(err);
64
+ }
41
65
  reject(err);
42
66
  });
43
67
  req.end();
@@ -15,13 +15,13 @@ interface ConfigMap {
15
15
  bootstrap: NormalizedLwrAppBootstrapConfig;
16
16
  locker: RequiredLwrLockerConfig;
17
17
  }
18
- export declare const ROOT_ATTRIBUTE_KEYS: ["amdLoader", "apiVersion", "assets", "assetProviders", "bundleConfig", "cacheDir", "contentDir", "environment", "errorRoutes", "esmLoader", "staticSiteGenerator", "globalData", "globalDataDir", "hooks", "ignoreLwrConfigFile", "lwrConfigFile", "layoutsDir", "locker", "lwc", "lwrVersion", "moduleProviders", "port", "resourceProviders", "rootDir", "routes", "serverMode", "serverType", "templateEngine", "viewProviders"];
18
+ export declare const ROOT_ATTRIBUTE_KEYS: ["amdLoader", "apiVersion", "assets", "assetProviders", "assetTransformers", "bundleConfig", "cacheDir", "contentDir", "environment", "errorRoutes", "esmLoader", "staticSiteGenerator", "globalData", "globalDataDir", "hooks", "ignoreLwrConfigFile", "lwrConfigFile", "layoutsDir", "locker", "lwc", "lwrVersion", "moduleProviders", "port", "resourceProviders", "rootDir", "routes", "serverMode", "serverType", "templateEngine", "viewProviders", "viewTransformers"];
19
19
  export declare const ASSET_DIR_ATTRIBUTE_KEYS: ["alias", "dir", "urlPath"];
20
20
  export declare const ASSET_FILE_ATTRIBUTE_KEYS: ["alias", "file", "urlPath"];
21
21
  export declare const LOCKER_ATTRIBUTE_KEYS: ["enabled", "trustedComponents", "clientOnly"];
22
22
  export declare const ROUTE_ATTRIBUTE_KEYS: ["bootstrap", "contentTemplate", "id", "cache", "layoutTemplate", "method", "path", "rootComponent", "routeHandler", "properties"];
23
23
  export declare const ERROR_ROUTE_ATTRIBUTE_KEYS: ["bootstrap", "contentTemplate", "id", "layoutTemplate", "rootComponent", "routeHandler", "status", "properties", "cache"];
24
- export declare const BOOTSTRAP_ATTRIBUTE_KEYS: ["autoBoot", "syntheticShadow", "workers", "services", "configAsSrc"];
24
+ export declare const BOOTSTRAP_ATTRIBUTE_KEYS: ["autoBoot", "syntheticShadow", "workers", "services", "configAsSrc", "experimentalSSR"];
25
25
  export declare class ValidationContext {
26
26
  diagnostics: Diagnostic[];
27
27
  sourceText: string;
@@ -11,6 +11,7 @@ export const ROOT_ATTRIBUTE_KEYS = createKeys('root', [
11
11
  'apiVersion',
12
12
  'assets',
13
13
  'assetProviders',
14
+ 'assetTransformers',
14
15
  'bundleConfig',
15
16
  'cacheDir',
16
17
  'contentDir',
@@ -36,6 +37,7 @@ export const ROOT_ATTRIBUTE_KEYS = createKeys('root', [
36
37
  'serverType',
37
38
  'templateEngine',
38
39
  'viewProviders',
40
+ 'viewTransformers',
39
41
  ]);
40
42
  export const ASSET_DIR_ATTRIBUTE_KEYS = createKeys('assetDir', ['alias', 'dir', 'urlPath']);
41
43
  export const ASSET_FILE_ATTRIBUTE_KEYS = createKeys('assetFile', ['alias', 'file', 'urlPath']);
@@ -69,6 +71,7 @@ export const BOOTSTRAP_ATTRIBUTE_KEYS = createKeys('bootstrap', [
69
71
  'workers',
70
72
  'services',
71
73
  'configAsSrc',
74
+ 'experimentalSSR',
72
75
  ]);
73
76
  const SPECIFIER_REGEX = /^@?[\w-]+(\/[\w-]+)*$/;
74
77
  function isNotEmptyString(node) {
@@ -21,6 +21,7 @@ function validateBootstrap(node, validationContext, propPrefix) {
21
21
  validationContext.assertValidKeys(node, 'bootstrap', BOOTSTRAP_ATTRIBUTE_KEYS);
22
22
  validationContext.assertArrayOfSpecifiers(findNode(node, ['services']), `${propPrefix}.services`);
23
23
  validationContext.assertIsBoolean(findNode(node, ['autoBoot']), `${propPrefix}.autoBoot`);
24
+ validationContext.assertIsBoolean(findNode(node, ['experimentalSSR']), `${propPrefix}.experimentalSSR`);
24
25
  validationContext.assertIsBoolean(findNode(node, ['configAsSrc']), `${propPrefix}.configAsSrc`);
25
26
  validationContext.assertIsBoolean(findNode(node, ['syntheticShadow']), `${propPrefix}.syntheticShadow`);
26
27
  // Each value in the worker map msut be a specifier