@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/cjs/env-config.cjs +37 -3
- package/build/cjs/index.cjs +26 -9
- package/build/cjs/middlewares/api-middleware.cjs +6 -6
- package/build/cjs/middlewares/utils.cjs +1 -1
- package/build/cjs/tools/static-generation.cjs +73 -55
- package/build/cjs/tools/utils/network-dispatcher.cjs +22 -2
- package/build/cjs/validation/app-config-context.cjs +5 -2
- package/build/cjs/validation/app-config.cjs +1 -0
- package/build/es/env-config.js +40 -3
- package/build/es/index.js +29 -9
- package/build/es/middlewares/api-middleware.js +6 -6
- package/build/es/middlewares/ui-middleware.js +2 -2
- package/build/es/middlewares/utils.d.ts +2 -5
- package/build/es/middlewares/utils.js +3 -3
- package/build/es/tools/static-generation.d.ts +34 -2
- package/build/es/tools/static-generation.js +101 -74
- package/build/es/tools/types.d.ts +13 -2
- package/build/es/tools/utils/network-dispatcher.d.ts +3 -0
- package/build/es/tools/utils/network-dispatcher.js +26 -2
- package/build/es/validation/app-config-context.d.ts +2 -2
- package/build/es/validation/app-config-context.js +3 -0
- package/build/es/validation/app-config.js +1 -0
- package/package.json +29 -25
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 =
|
|
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
|
-
|
|
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 (
|
|
65
|
-
const
|
|
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(
|
|
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 (
|
|
75
|
-
const
|
|
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(
|
|
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
|
|
9
|
+
* @param error - an Error/Diagnostic object; thrown from try/catch
|
|
13
10
|
*/
|
|
14
|
-
export declare function createReturnStatus(name: string, error:
|
|
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
|
|
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 {
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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
|
-
|
|
442
|
-
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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}'
|
|
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(
|
|
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
|