@lwrjs/core 0.9.0-alpha.8 → 0.9.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.
- package/build/cjs/context/provider.cjs +9 -5
- package/build/cjs/context/server.cjs +6 -6
- package/build/cjs/index.cjs +66 -41
- package/build/cjs/middleware/asset-middleware.cjs +70 -0
- package/build/cjs/middleware/bundle-middleware.cjs +113 -0
- package/build/cjs/{middlewares → middleware}/hmr-middleware.cjs +6 -6
- package/build/cjs/{middlewares → middleware}/locale-middleware.cjs +2 -2
- package/build/cjs/middleware/mapping-middleware.cjs +61 -0
- package/build/cjs/middleware/module-middleware.cjs +88 -0
- package/build/cjs/middleware/redirects/unsigned-module-redirect.cjs +37 -0
- package/build/cjs/middleware/resource-middleware.cjs +64 -0
- package/build/cjs/{context/global-data.cjs → middleware/utils/error-handling.cjs} +26 -24
- package/build/cjs/middleware/utils/identity.cjs +92 -0
- package/build/cjs/{context/services.cjs → middleware/utils/metadata.cjs} +19 -20
- package/build/cjs/{middlewares/utils.cjs → middleware/utils/request.cjs} +17 -16
- package/build/cjs/middleware/view-middleware.cjs +151 -0
- package/build/cjs/middleware.cjs +16 -9
- package/build/cjs/tools/server-warmup.cjs +2 -9
- package/build/cjs/tools/static-generation.cjs +190 -62
- package/build/es/context/provider.js +5 -3
- package/build/es/context/server.d.ts +1 -1
- package/build/es/context/server.js +6 -5
- package/build/es/index.d.ts +3 -2
- package/build/es/index.js +85 -49
- package/build/es/middleware/asset-middleware.d.ts +3 -0
- package/build/es/middleware/asset-middleware.js +42 -0
- package/build/es/middleware/bundle-middleware.d.ts +3 -0
- package/build/es/middleware/bundle-middleware.js +88 -0
- package/build/es/middleware/hmr-middleware.d.ts +5 -0
- package/build/es/{middlewares → middleware}/hmr-middleware.js +4 -4
- package/build/es/middleware/locale-middleware.d.ts +3 -0
- package/build/es/{middlewares → middleware}/locale-middleware.js +2 -1
- package/build/es/middleware/mapping-middleware.d.ts +3 -0
- package/build/es/middleware/mapping-middleware.js +34 -0
- package/build/es/middleware/module-middleware.d.ts +3 -0
- package/build/es/middleware/module-middleware.js +64 -0
- package/build/es/middleware/redirects/unsigned-module-redirect.d.ts +6 -0
- package/build/es/middleware/redirects/unsigned-module-redirect.js +25 -0
- package/build/es/middleware/resource-middleware.d.ts +3 -0
- package/build/es/middleware/resource-middleware.js +37 -0
- package/build/es/middleware/utils/error-handling.d.ts +3 -0
- package/build/es/middleware/utils/error-handling.js +32 -0
- package/build/es/middleware/utils/identity.d.ts +6 -0
- package/build/es/middleware/utils/identity.js +62 -0
- package/build/es/middleware/utils/metadata.d.ts +3 -0
- package/build/es/middleware/utils/metadata.js +24 -0
- package/build/es/middleware/utils/request.d.ts +15 -0
- package/build/es/{middlewares/utils.js → middleware/utils/request.js} +15 -23
- package/build/es/middleware/view-middleware.d.ts +3 -0
- package/build/es/middleware/view-middleware.js +136 -0
- package/build/es/middleware.d.ts +8 -14
- package/build/es/middleware.js +12 -20
- package/build/es/tools/server-warmup.js +3 -10
- package/build/es/tools/static-generation.d.ts +11 -1
- package/build/es/tools/static-generation.js +230 -79
- package/build/es/tools/types.d.ts +3 -2
- package/package.json +33 -34
- package/build/cjs/context/configurations.cjs +0 -82
- package/build/cjs/middlewares/api-middleware.cjs +0 -359
- package/build/cjs/middlewares/base-middleware.cjs +0 -15
- package/build/cjs/middlewares/ui-middleware.cjs +0 -183
- package/build/cjs/tools/server-build.cjs +0 -182
- package/build/es/context/configurations.d.ts +0 -9
- package/build/es/context/configurations.js +0 -53
- package/build/es/context/global-data.d.ts +0 -3
- package/build/es/context/global-data.js +0 -29
- package/build/es/context/services.d.ts +0 -3
- package/build/es/context/services.js +0 -27
- package/build/es/middlewares/api-middleware.d.ts +0 -3
- package/build/es/middlewares/api-middleware.js +0 -410
- package/build/es/middlewares/base-middleware.d.ts +0 -3
- package/build/es/middlewares/base-middleware.js +0 -4
- package/build/es/middlewares/hmr-middleware.d.ts +0 -5
- package/build/es/middlewares/locale-middleware.d.ts +0 -3
- package/build/es/middlewares/ui-middleware.d.ts +0 -3
- package/build/es/middlewares/ui-middleware.js +0 -186
- package/build/es/middlewares/utils.d.ts +0 -22
- package/build/es/tools/server-build.d.ts +0 -14
- package/build/es/tools/server-build.js +0 -182
|
@@ -1,52 +1,52 @@
|
|
|
1
1
|
import { performance } from 'perf_hooks';
|
|
2
|
-
import { getSpecifier, getFeatureFlags, hashContent, isSelfUrl, getModuleUriPrefix, getMappingUriPrefix, logger, WARN, INFO, } from '@lwrjs/shared-utils';
|
|
3
|
-
import { join, dirname, extname } from 'path';
|
|
2
|
+
import { getSpecifier, getFeatureFlags, hashContent, isSelfUrl, getModuleUriPrefix, getMappingUriPrefix, logger, WARN, INFO, SiteMetadataImpl, isExternalUrl, mimeLookup, } from '@lwrjs/shared-utils';
|
|
3
|
+
import { join, dirname, extname, normalize } from 'path';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
5
|
import { writeResponse } from './utils/stream.js';
|
|
6
6
|
import { createDir, createResourceDir } from './utils/dir.js';
|
|
7
|
-
import {
|
|
7
|
+
import { getRuntimeEnvironment } from '@lwrjs/config';
|
|
8
8
|
export default class SiteGenerator {
|
|
9
9
|
/**
|
|
10
10
|
* Build a static site in the configured directory
|
|
11
11
|
* - Generate all routes / modules
|
|
12
12
|
* - copy assets / resources
|
|
13
13
|
*
|
|
14
|
+
* @deprecated - use new build api
|
|
14
15
|
* @param config - LWR config for the site
|
|
15
16
|
* @param dispatcher - Facilitate server requests
|
|
16
17
|
*/
|
|
17
18
|
async buildStaticApplication(config, dispatcher) {
|
|
18
19
|
const startTime = performance.now();
|
|
19
|
-
logger.info('[Static Generation
|
|
20
|
+
logger.info('[SSG] Static Site Generation');
|
|
20
21
|
// De-duplicate warming messages if log level is warn or info
|
|
21
22
|
if (!logger.currentLevel || logger.currentLevel == WARN || logger.currentLevel == INFO) {
|
|
22
23
|
logger.setOptions({ dedupe: new Set([WARN]) });
|
|
23
24
|
}
|
|
24
25
|
const { routes, staticSiteGenerator, rootDir, assets } = config;
|
|
25
26
|
if (!staticSiteGenerator.outputDir) {
|
|
26
|
-
staticSiteGenerator.outputDir = '
|
|
27
|
+
staticSiteGenerator.outputDir = 'site';
|
|
27
28
|
}
|
|
28
29
|
const outputDir = join(rootDir, staticSiteGenerator.outputDir);
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
if (!staticSiteGenerator.skipCleanOutputDir) {
|
|
31
|
+
logger.info(`[SSG] Clearing output directory: ${outputDir}`);
|
|
32
|
+
fs.rmSync(outputDir, { recursive: true, force: true });
|
|
33
|
+
}
|
|
34
|
+
else if (fs.existsSync(outputDir)) {
|
|
35
|
+
logger.info(`[SSG] Reusing existing output directory: ${outputDir}`);
|
|
36
|
+
}
|
|
31
37
|
const urlRewriteMap = new Map();
|
|
32
|
-
const {
|
|
33
|
-
const runtimeEnvironment =
|
|
34
|
-
...explodeMode(serverMode),
|
|
35
|
-
apiVersion,
|
|
36
|
-
basePath,
|
|
37
|
-
lwrVersion,
|
|
38
|
-
debug: false,
|
|
39
|
-
serverMode,
|
|
40
|
-
};
|
|
38
|
+
const { basePath } = config;
|
|
39
|
+
const runtimeEnvironment = getRuntimeEnvironment(config);
|
|
41
40
|
// For each locale, generate all the modules
|
|
41
|
+
logger.info(`[SSG] Building routes (this may take some time to complete)`);
|
|
42
42
|
await this.generateRoutes(runtimeEnvironment, staticSiteGenerator, routes, basePath, dispatcher, outputDir, urlRewriteMap);
|
|
43
43
|
// Write redirect files
|
|
44
44
|
this.writeNetlifyRedirectConfig(outputDir, urlRewriteMap);
|
|
45
45
|
// Copy over assets
|
|
46
|
-
this.copyAssets(assets, outputDir,
|
|
46
|
+
await this.copyAssets(assets, outputDir, config);
|
|
47
47
|
const endTime = performance.now();
|
|
48
48
|
const timeDiff = (endTime - startTime) / 1000;
|
|
49
|
-
logger.info(`[Static Generation
|
|
49
|
+
logger.info(`[SSG] Static Site Generation complete in ${Math.round(timeDiff)} seconds`);
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
52
|
* Crawl all view routes for a site
|
|
@@ -57,17 +57,18 @@ export default class SiteGenerator {
|
|
|
57
57
|
}
|
|
58
58
|
const generateUrl = this.createGenerateURLFunction(dispatcher);
|
|
59
59
|
// Note: generateUrl can consume a lot of memory so we need to do this sequentially
|
|
60
|
+
const { skipBaseDocumentGeneration = false } = staticSiteGenerator;
|
|
60
61
|
for (const locale of staticSiteGenerator.locales) {
|
|
61
62
|
// Generate all the routes
|
|
62
63
|
for (const route of routes) {
|
|
63
|
-
const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap, runtimeEnvironment);
|
|
64
|
+
const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment);
|
|
64
65
|
// eslint-disable-next-line no-await-in-loop
|
|
65
66
|
await generateUrl(basePath + route.path, siteConfig);
|
|
66
67
|
}
|
|
67
68
|
// Generate any additional urls
|
|
68
69
|
if (staticSiteGenerator._additionalRoutePaths) {
|
|
69
70
|
for (const uri of staticSiteGenerator._additionalRoutePaths) {
|
|
70
|
-
const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap, runtimeEnvironment);
|
|
71
|
+
const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment);
|
|
71
72
|
// eslint-disable-next-line no-await-in-loop
|
|
72
73
|
await generateUrl(uri, siteConfig);
|
|
73
74
|
}
|
|
@@ -76,9 +77,17 @@ export default class SiteGenerator {
|
|
|
76
77
|
const { _additionalModules } = staticSiteGenerator;
|
|
77
78
|
if (_additionalModules) {
|
|
78
79
|
for (const specifier of _additionalModules) {
|
|
79
|
-
|
|
80
|
+
logger.debug(`[SSG] Additional Module: ${locale} ${specifier}`);
|
|
81
|
+
const startTime = performance.now();
|
|
82
|
+
const siteConfig = this.createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment);
|
|
80
83
|
// eslint-disable-next-line no-await-in-loop
|
|
81
84
|
await this.dispatchJSResourceRecursive(specifier, dispatcher, siteConfig, true);
|
|
85
|
+
// Capture any additional collected metadata
|
|
86
|
+
// eslint-disable-next-line no-await-in-loop
|
|
87
|
+
await this.captureAdditionalRouteMetadata(siteConfig);
|
|
88
|
+
const endTime = performance.now();
|
|
89
|
+
const timeDiff = endTime - startTime;
|
|
90
|
+
logger.info(`[SSG] Additional Module ${locale} ${specifier} in ${Math.round(timeDiff)} ms`);
|
|
82
91
|
}
|
|
83
92
|
}
|
|
84
93
|
}
|
|
@@ -89,12 +98,15 @@ export default class SiteGenerator {
|
|
|
89
98
|
createGenerateURLFunction(dispatcher) {
|
|
90
99
|
const generateRoute = async (uri, siteConfig) => {
|
|
91
100
|
const locale = siteConfig.locale;
|
|
92
|
-
logger.
|
|
101
|
+
logger.debug(`[SSG] Start Generate: ${locale} ${uri}`);
|
|
102
|
+
const startTime = performance.now();
|
|
93
103
|
// Kick off site generation for the current route
|
|
94
104
|
await this.dispatchResourceRecursive(uri, dispatcher, { resourceType: 'route' }, siteConfig);
|
|
95
|
-
//
|
|
96
|
-
this.
|
|
97
|
-
|
|
105
|
+
// Capture any additional route metadata
|
|
106
|
+
await this.captureAdditionalRouteMetadata(siteConfig);
|
|
107
|
+
const endTime = performance.now();
|
|
108
|
+
const timeDiff = endTime - startTime;
|
|
109
|
+
logger.info(`[SSG] ${locale} ${uri} in ${Math.round(timeDiff)} ms`);
|
|
98
110
|
};
|
|
99
111
|
return generateRoute.bind(this);
|
|
100
112
|
}
|
|
@@ -110,10 +122,15 @@ export default class SiteGenerator {
|
|
|
110
122
|
const { visitedUrls } = siteConfig;
|
|
111
123
|
if (!visitedUrls.has(url)) {
|
|
112
124
|
visitedUrls.add(url); // Maintain a list of visited urls here to avoid potential infinite loops
|
|
125
|
+
// Skip remote urls (i.e. http://) the static view would call the remote url at runtime
|
|
126
|
+
if (isExternalUrl(url)) {
|
|
127
|
+
logger.warn('[SSG] Skipped generation of external url: ' + url);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
113
130
|
// Skip urls with path segment variables (i.e. '/custom/:bar')
|
|
114
131
|
// Users can specify specific urls via the '_additionalRoutePaths' config property
|
|
115
132
|
if (url.indexOf('/:') !== -1 || url.indexOf('*') !== -1) {
|
|
116
|
-
logger.warn('Skipped generation of url with variable path segment: ' + url);
|
|
133
|
+
logger.warn('[SSG] Skipped generation of url with variable path segment: ' + url);
|
|
117
134
|
return;
|
|
118
135
|
}
|
|
119
136
|
// Generate resource
|
|
@@ -169,11 +186,11 @@ export default class SiteGenerator {
|
|
|
169
186
|
// Redirect encoded signed URIs to UNencoded signed URIs
|
|
170
187
|
// e.g. /1/bundle/amd/l/en-US/bi/0/module/mi/c%2Fmodule%2Fv%2F0_1_6/s/{signature} -> /1/bundle/amd/l/en-US/bi/0/module/mi/c/module/v/0_1_6/s/{signature}
|
|
171
188
|
siteConfig.urlRewriteMap.set(url.substring(0, url.indexOf('/s/')), normalizedUrl);
|
|
172
|
-
// Redirect
|
|
189
|
+
// Redirect un-versioned/unsigned URIs to signed URIs
|
|
173
190
|
// e.g. /1/bundle/amd/l/en-US/bi/0/module/mi/c/module -> /1/bundle/amd/l/en-US/bi/0/module/mi/c/module/v/0_1_6/s/{signature}
|
|
174
191
|
// e.g. with importer /1/bundle/amd/l/en-US/bi/0/module/mi/c/module?importer=parent%2Fmodule%2Fv%2F2_1_0 -> /1/bundle/amd/l/en-US/bi/0/module/mi/c/module/v/0_1_6/s/{signature}
|
|
175
192
|
siteConfig.urlRewriteMap.set(normalizedUrl.substring(0, normalizedUrl.indexOf('/v/')), normalizedUrl);
|
|
176
|
-
// Redirect encoded
|
|
193
|
+
// Redirect encoded un-versioned/unsigned URIs to UNencoded signed URIs
|
|
177
194
|
// e.g. /1/bundle/amd/l/en-US/bi/0/module/mi/c%2Fmodule -> /1/bundle/amd/l/en-US/bi/0/module/mi/c/module/v/0_1_6/s/{signature}
|
|
178
195
|
// e.g. with importer /1/bundle/amd/l/en-US/bi/0/module/mi/c%2Fmodule?importer=parent%2Fmodule%2Fv%2F2_1_0 -> /1/bundle/amd/l/en-US/bi/0/module/mi/c/module/v/0_1_6/s/{signature}
|
|
179
196
|
siteConfig.urlRewriteMap.set(url.substring(0, url.indexOf('%2Fv%2F')), normalizedUrl);
|
|
@@ -200,6 +217,10 @@ export default class SiteGenerator {
|
|
|
200
217
|
: getSpecifier(importModule);
|
|
201
218
|
dispatchRequests.push(this.dispatchJSResourceRecursive(jsUri, dispatcher, siteConfig));
|
|
202
219
|
}
|
|
220
|
+
// If this is a bundle add it to the bundle metadata
|
|
221
|
+
if (moduleDefinition.bundleRecord) {
|
|
222
|
+
this.addBundleToSiteMetadata(moduleDefinition, url, siteConfig);
|
|
223
|
+
}
|
|
203
224
|
}
|
|
204
225
|
// Bundles with unresolved module uris
|
|
205
226
|
const uris = context.fs?.metadata?.resolvedUris || [];
|
|
@@ -209,6 +230,58 @@ export default class SiteGenerator {
|
|
|
209
230
|
// -- Dispatch dependencies
|
|
210
231
|
await Promise.all(dispatchRequests);
|
|
211
232
|
}
|
|
233
|
+
addBundleToSiteMetadata(bundleDefinition, url, siteConfig) {
|
|
234
|
+
if (siteConfig.siteMetadata) {
|
|
235
|
+
const specifier = bundleDefinition.specifier;
|
|
236
|
+
const imports = bundleDefinition.bundleRecord.imports?.map((moduleRef) => getSpecifier(moduleRef)) || [];
|
|
237
|
+
const bundleMetadata = {
|
|
238
|
+
version: bundleDefinition.version,
|
|
239
|
+
path: decodeURIComponent(url),
|
|
240
|
+
includedModules: bundleDefinition.bundleRecord.includedModules || [],
|
|
241
|
+
imports,
|
|
242
|
+
};
|
|
243
|
+
const siteBundles = siteConfig.siteMetadata.getSiteBundles().bundles;
|
|
244
|
+
siteBundles[specifier] = bundleMetadata;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
addResourceToSiteMetadata(resourceDefinition, url, siteConfig) {
|
|
248
|
+
if (siteConfig.siteMetadata) {
|
|
249
|
+
if (!resourceDefinition.specifier) {
|
|
250
|
+
logger.warn('[SSG] Could not save resource metadata. There was no specifier.', resourceDefinition);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
const specifier = resourceDefinition.specifier;
|
|
254
|
+
const resourceMetadata = {
|
|
255
|
+
path: decodeURIComponent(url),
|
|
256
|
+
mimeType: resourceDefinition.type,
|
|
257
|
+
};
|
|
258
|
+
const siteResources = siteConfig.siteMetadata.getSiteResources();
|
|
259
|
+
siteResources.resources[specifier] = resourceMetadata;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
addAssetToSiteMetadata(assetDefinition, url, siteConfig) {
|
|
264
|
+
if (siteConfig.siteMetadata) {
|
|
265
|
+
if (!assetDefinition.uri) {
|
|
266
|
+
logger.warn('[SSG] Could not save asset metadata. There was no uri.', assetDefinition);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
const specifier = assetDefinition.uri;
|
|
270
|
+
const resourceMetadata = {
|
|
271
|
+
path: decodeURIComponent(url),
|
|
272
|
+
mimeType: String(assetDefinition.mime),
|
|
273
|
+
};
|
|
274
|
+
const siteAssets = siteConfig.siteMetadata.getSiteAssets();
|
|
275
|
+
// Do not overwrite
|
|
276
|
+
if (!siteAssets.assets[specifier]) {
|
|
277
|
+
siteAssets.assets[specifier] = resourceMetadata;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
logger.debug(`[SSG] Ignore asset redefinition ${specifier}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
212
285
|
/**
|
|
213
286
|
* Handle processing a returned module URI mapping resource and follow all returned references
|
|
214
287
|
* @param url - URL of the request mapping resource
|
|
@@ -217,22 +290,22 @@ export default class SiteGenerator {
|
|
|
217
290
|
* @param dispatcher - Network dispatcher
|
|
218
291
|
*/
|
|
219
292
|
async handleMappingResource(url, context, siteConfig, dispatcher) {
|
|
220
|
-
const { importMetadata:
|
|
293
|
+
const { importMetadata: importMetadata } = siteConfig;
|
|
221
294
|
const statusCode = context.response?.status;
|
|
222
295
|
// Received a server error
|
|
223
296
|
if (statusCode === 200) {
|
|
224
297
|
// Read JSON
|
|
225
298
|
const newImportMetadata = context.fs?.body;
|
|
226
299
|
let filteredImportMetadata;
|
|
227
|
-
if (!
|
|
300
|
+
if (!importMetadata) {
|
|
228
301
|
filteredImportMetadata = newImportMetadata;
|
|
229
302
|
}
|
|
230
303
|
else {
|
|
231
304
|
// need to handle importMetadata when generating from a view
|
|
232
|
-
filteredImportMetadata =
|
|
305
|
+
filteredImportMetadata = importMetadata.addAdditionalMetadata(newImportMetadata);
|
|
233
306
|
}
|
|
234
307
|
// Filter out and import metadata already included with the view
|
|
235
|
-
// const filteredImportMetadata =
|
|
308
|
+
// const filteredImportMetadata = importMetadata.addAdditionalMetadata(newImportMetadata);
|
|
236
309
|
// Build up a list of dispatch requests to kick off in parallel
|
|
237
310
|
const dispatchRequests = [];
|
|
238
311
|
// Iterate through the import mappings and return request uris
|
|
@@ -244,7 +317,7 @@ export default class SiteGenerator {
|
|
|
244
317
|
}
|
|
245
318
|
else {
|
|
246
319
|
const body = context.fs?.body;
|
|
247
|
-
logger.warn(`Failed to fetch ${url}: (${statusCode}) ${body}`);
|
|
320
|
+
logger.warn(`[SSG] Failed to fetch ${url}: (${statusCode}) ${body}`);
|
|
248
321
|
}
|
|
249
322
|
}
|
|
250
323
|
/**
|
|
@@ -256,35 +329,37 @@ export default class SiteGenerator {
|
|
|
256
329
|
* @param dispatcher - Network Dispatcher
|
|
257
330
|
*/
|
|
258
331
|
async handleHtmlResource(url, context, siteConfig, dispatcher) {
|
|
259
|
-
const { outputDir } = siteConfig;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
siteConfig.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
332
|
+
const { outputDir, skipBaseDocumentGeneration } = siteConfig;
|
|
333
|
+
if (!skipBaseDocumentGeneration) {
|
|
334
|
+
let fileName = 'index.html';
|
|
335
|
+
let directoryPath = url;
|
|
336
|
+
// If we have a route path that ends with a html or xml file extension,
|
|
337
|
+
// use that last path segment for the file name
|
|
338
|
+
if (url.endsWith('.html') || url.endsWith('.xml')) {
|
|
339
|
+
const lastPathIndex = url.lastIndexOf('/') + 1;
|
|
340
|
+
fileName = url.substring(lastPathIndex, url.length);
|
|
341
|
+
directoryPath = url.substring(0, lastPathIndex);
|
|
342
|
+
}
|
|
343
|
+
const dir = createResourceDir(directoryPath, outputDir);
|
|
344
|
+
const localeDir = createResourceDir(directoryPath, join(outputDir, siteConfig.locale));
|
|
345
|
+
// TODO: Should we handle routes with non-html extensions differently?
|
|
346
|
+
// Example Route: "path": "/mixed_templates.md" (not sure why you would do this)
|
|
347
|
+
// "contentTemplate": "$contentDir/composed_markdown.md"
|
|
348
|
+
// Today this will get written to /mixed_templates.md/index.html
|
|
349
|
+
// Which we workaround by setting "renderSingle": true in serve.json
|
|
350
|
+
const filePath = join(dir, fileName);
|
|
351
|
+
const fileLocalePath = join(localeDir, fileName);
|
|
352
|
+
// Default Path (only write once)
|
|
353
|
+
// The default locale is english
|
|
354
|
+
if (siteConfig.locale.toLowerCase().startsWith('en')) {
|
|
355
|
+
siteConfig.viewPaths.add(filePath);
|
|
356
|
+
await writeResponse(context, filePath);
|
|
357
|
+
}
|
|
358
|
+
// Language path (always write out)
|
|
359
|
+
createDir(localeDir);
|
|
360
|
+
siteConfig.viewPaths.add(fileLocalePath);
|
|
361
|
+
await writeResponse(context, fileLocalePath);
|
|
362
|
+
}
|
|
288
363
|
// Get the metadata
|
|
289
364
|
const viewDefinition = context.fs?.metadata?.viewDefinition;
|
|
290
365
|
if (viewDefinition) {
|
|
@@ -345,7 +420,7 @@ export default class SiteGenerator {
|
|
|
345
420
|
}
|
|
346
421
|
}
|
|
347
422
|
else {
|
|
348
|
-
logger.warn('Skipped inline bootstrap resource: %j', resource);
|
|
423
|
+
logger.warn('[SSG] Skipped inline bootstrap resource: %j', resource);
|
|
349
424
|
}
|
|
350
425
|
}
|
|
351
426
|
}
|
|
@@ -357,7 +432,7 @@ export default class SiteGenerator {
|
|
|
357
432
|
dispatchRequests.push(this.dispatchResourceRecursive(resourceUri, dispatcher, { resourceType: 'resource' }, siteConfig));
|
|
358
433
|
}
|
|
359
434
|
else {
|
|
360
|
-
logger.warn('Skipped resource: %j', resource);
|
|
435
|
+
logger.warn('[SSG] Skipped resource: %j', resource);
|
|
361
436
|
}
|
|
362
437
|
}
|
|
363
438
|
// -- Dispatch dependencies
|
|
@@ -377,7 +452,7 @@ export default class SiteGenerator {
|
|
|
377
452
|
await this.dispatchResourceRecursive(mappingURL, dispatcher, { resourceType: 'mapping' }, siteConfig);
|
|
378
453
|
}
|
|
379
454
|
else {
|
|
380
|
-
logger.warn('Unable to fetch mapping for bare specifier or variable dynamic import: "' +
|
|
455
|
+
logger.warn('[SSG] Unable to fetch mapping for bare specifier or variable dynamic import: "' +
|
|
381
456
|
jsUri +
|
|
382
457
|
'"');
|
|
383
458
|
}
|
|
@@ -402,6 +477,14 @@ export default class SiteGenerator {
|
|
|
402
477
|
const metadata = context.fs?.metadata;
|
|
403
478
|
const fullPath = this.getResourcePathFromUrl(siteConfig, url);
|
|
404
479
|
await writeResponse(context, fullPath);
|
|
480
|
+
// Save Metadata
|
|
481
|
+
// If resource add to resource metadata
|
|
482
|
+
if (metadata?.resource) {
|
|
483
|
+
this.addResourceToSiteMetadata(metadata?.resource, url, siteConfig);
|
|
484
|
+
}
|
|
485
|
+
else if (metadata?.asset) {
|
|
486
|
+
this.addAssetToSiteMetadata(metadata?.asset, url, siteConfig);
|
|
487
|
+
}
|
|
405
488
|
// Call and referenced assets...
|
|
406
489
|
const assetReferences = metadata?.asset?.metadata?.assetReferences || [];
|
|
407
490
|
const dispatchRequests = [];
|
|
@@ -409,7 +492,7 @@ export default class SiteGenerator {
|
|
|
409
492
|
const refUrl = ref.override?.uri || ref.url;
|
|
410
493
|
dispatchRequests.push(this.dispatchResourceRecursive(refUrl, dispatcher, { resourceType: 'asset', asset: metadata?.asset }, siteConfig).catch((err) => {
|
|
411
494
|
// Warn the user that the we failed to fetch a referenced asset
|
|
412
|
-
logger.warn(`Failed to fetch asset reference => ${refUrl} from ${url}`, err);
|
|
495
|
+
logger.warn(`[SSG] Failed to fetch asset reference => ${refUrl} from ${url}`, err);
|
|
413
496
|
}));
|
|
414
497
|
}
|
|
415
498
|
return Promise.all(dispatchRequests);
|
|
@@ -458,27 +541,77 @@ export default class SiteGenerator {
|
|
|
458
541
|
* @param assets AssetConfig
|
|
459
542
|
*
|
|
460
543
|
*/
|
|
461
|
-
copyAssets(assets, outputDir,
|
|
544
|
+
async copyAssets(assets, outputDir, config) {
|
|
545
|
+
const { basePath } = config;
|
|
546
|
+
const runtimeEnvironment = getRuntimeEnvironment(config);
|
|
547
|
+
const siteConfig = this.createSiteConfig(outputDir, 'en-US', // Copy Assets should not use the locale
|
|
548
|
+
new Map(), true, runtimeEnvironment);
|
|
462
549
|
for (const asset of assets) {
|
|
463
550
|
try {
|
|
464
|
-
const
|
|
465
|
-
const
|
|
551
|
+
const assetSrcFile = asset.file;
|
|
552
|
+
const assetSrcDir = asset.dir;
|
|
553
|
+
const assetsPath = join(outputDir, basePath ? basePath + asset.urlPath : asset.urlPath);
|
|
466
554
|
if (assetSrcDir && fs.existsSync(assetSrcDir)) {
|
|
467
|
-
fs.copySync(assetSrcDir,
|
|
555
|
+
fs.copySync(assetSrcDir, assetsPath);
|
|
556
|
+
this.addAssetsToMetadata(assetsPath, siteConfig);
|
|
557
|
+
}
|
|
558
|
+
else if (assetSrcFile && fs.existsSync(assetSrcFile)) {
|
|
559
|
+
fs.copySync(assetSrcFile, assetsPath);
|
|
560
|
+
this.addAssetToMetadata(assetsPath, siteConfig);
|
|
468
561
|
}
|
|
469
562
|
else {
|
|
470
|
-
logger.warn('Could not find assets to copy at path: ' +
|
|
563
|
+
logger.warn('[SSG] Could not find assets to copy at path: ' + assetsPath);
|
|
471
564
|
}
|
|
472
565
|
}
|
|
473
566
|
catch (e) {
|
|
474
|
-
logger.error('Error occurred processing asset config: ' + JSON.stringify(asset), e);
|
|
567
|
+
logger.error('[SSG] Error occurred processing asset config: ' + JSON.stringify(asset), e);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
await siteConfig.siteMetadata?.persistSiteMetadata();
|
|
571
|
+
}
|
|
572
|
+
addAssetsToMetadata(directoryPath, siteConfig) {
|
|
573
|
+
try {
|
|
574
|
+
const files = fs.readdirSync(directoryPath);
|
|
575
|
+
for (const file of files) {
|
|
576
|
+
const filePath = join(directoryPath, file);
|
|
577
|
+
if (fs.statSync(filePath).isDirectory()) {
|
|
578
|
+
this.addAssetsToMetadata(filePath, siteConfig);
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
this.addAssetToMetadata(filePath, siteConfig);
|
|
582
|
+
}
|
|
475
583
|
}
|
|
476
584
|
}
|
|
585
|
+
catch (err) {
|
|
586
|
+
logger.warn(`[SSG] Unexpected error collecting asset directory metadata for ${directoryPath}`, err);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
addAssetToMetadata(filePath, siteConfig) {
|
|
590
|
+
try {
|
|
591
|
+
const uri = encodeURI(normalize(filePath).replace(siteConfig.outputDir, ''));
|
|
592
|
+
this.addAssetToSiteMetadata({
|
|
593
|
+
uri,
|
|
594
|
+
type: 'asset',
|
|
595
|
+
stream: function (encoding) {
|
|
596
|
+
throw new Error('Function not implemented.');
|
|
597
|
+
},
|
|
598
|
+
entry: filePath,
|
|
599
|
+
ext: extname(filePath),
|
|
600
|
+
mime: mimeLookup(filePath),
|
|
601
|
+
ownHash: 'not-provided',
|
|
602
|
+
content: function (encoding) {
|
|
603
|
+
throw new Error('Function not implemented.');
|
|
604
|
+
},
|
|
605
|
+
}, uri, siteConfig);
|
|
606
|
+
}
|
|
607
|
+
catch (err) {
|
|
608
|
+
logger.warn(`[SSG] Unexpected error collecting asset metadata for ${filePath}`, err);
|
|
609
|
+
}
|
|
477
610
|
}
|
|
478
611
|
/**
|
|
479
612
|
* Create a new site config for the current view
|
|
480
613
|
*/
|
|
481
|
-
createSiteConfig(outputDir, locale, urlRewriteMap, runtimeEnvironment) {
|
|
614
|
+
createSiteConfig(outputDir, locale, urlRewriteMap, skipBaseDocumentGeneration, runtimeEnvironment) {
|
|
482
615
|
const featureFlags = this.filterFeatureFlags();
|
|
483
616
|
const endpoints = {
|
|
484
617
|
uris: {
|
|
@@ -494,13 +627,22 @@ export default class SiteGenerator {
|
|
|
494
627
|
locale,
|
|
495
628
|
urlRewriteMap,
|
|
496
629
|
endpoints,
|
|
630
|
+
skipBaseDocumentGeneration,
|
|
497
631
|
// Only include LEGACY_LOADER if true
|
|
498
632
|
...featureFlags,
|
|
633
|
+
siteMetadata: new SiteMetadataImpl({ rootDir: outputDir }),
|
|
499
634
|
};
|
|
500
635
|
}
|
|
501
636
|
filterFeatureFlags() {
|
|
502
|
-
|
|
503
|
-
|
|
637
|
+
const ffs = getFeatureFlags();
|
|
638
|
+
if (ffs && Object.keys(ffs).length) {
|
|
639
|
+
const accumulator = {};
|
|
640
|
+
for (const [key, value] of Object.entries(ffs)) {
|
|
641
|
+
if (value) {
|
|
642
|
+
accumulator[key] = true;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
return { featureFlags: accumulator };
|
|
504
646
|
}
|
|
505
647
|
else {
|
|
506
648
|
return undefined;
|
|
@@ -546,6 +688,15 @@ export default class SiteGenerator {
|
|
|
546
688
|
});
|
|
547
689
|
}
|
|
548
690
|
}
|
|
691
|
+
/**
|
|
692
|
+
* Capture additional metadata collected during the processing of a route or additional module
|
|
693
|
+
*/
|
|
694
|
+
async captureAdditionalRouteMetadata(siteConfig) {
|
|
695
|
+
// If there is a view config add any extra collected import metadata to the config
|
|
696
|
+
this.addAdditionalImportMetadataToViewConfig(siteConfig);
|
|
697
|
+
// Save site meta data
|
|
698
|
+
await siteConfig.siteMetadata?.persistSiteMetadata();
|
|
699
|
+
}
|
|
549
700
|
}
|
|
550
701
|
// Class used to track import metadata for a view
|
|
551
702
|
export class ViewImportMetadataImpl {
|
|
@@ -589,10 +740,10 @@ export class ViewImportMetadataImpl {
|
|
|
589
740
|
/**
|
|
590
741
|
* Merge new import metadata into target import metadata
|
|
591
742
|
*/
|
|
592
|
-
mergeImportMetadata(
|
|
593
|
-
Object.assign(
|
|
594
|
-
if (
|
|
595
|
-
Object.assign(
|
|
743
|
+
mergeImportMetadata(targetImportMetadata, newImportMetadata) {
|
|
744
|
+
Object.assign(targetImportMetadata.imports, newImportMetadata.imports);
|
|
745
|
+
if (targetImportMetadata.index) {
|
|
746
|
+
Object.assign(targetImportMetadata.index, newImportMetadata.index || {});
|
|
596
747
|
}
|
|
597
748
|
}
|
|
598
749
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Endpoints, FeatureFlags, ImportMetadata } from '@lwrjs/types';
|
|
2
|
-
import { RenderedAssetReference } from '@lwrjs/types';
|
|
1
|
+
import type { Endpoints, FeatureFlags, ImportMetadata, RenderedAssetReference, SiteMetadata } from '@lwrjs/types';
|
|
3
2
|
export interface BaseResourceContextOpts {
|
|
4
3
|
resourceType: 'route' | 'asset' | 'js' | 'resource' | 'mapping';
|
|
5
4
|
}
|
|
@@ -43,5 +42,7 @@ export interface SiteConfig {
|
|
|
43
42
|
viewConfigPath?: string;
|
|
44
43
|
featureFlags?: FeatureFlags;
|
|
45
44
|
legacyDefaultMappingEndpoint?: string;
|
|
45
|
+
skipBaseDocumentGeneration?: boolean;
|
|
46
|
+
siteMetadata?: SiteMetadata;
|
|
46
47
|
}
|
|
47
48
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.9.0
|
|
7
|
+
"version": "0.9.0",
|
|
8
8
|
"homepage": "https://developer.salesforce.com/docs/platform/lwr/overview",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/salesforce/lwr.git",
|
|
11
|
+
"url": "https://github.com/salesforce-experience-platform-emu/lwr.git",
|
|
12
12
|
"directory": "packages/@lwrjs/core"
|
|
13
13
|
},
|
|
14
14
|
"bugs": {
|
|
15
|
-
"url": "https://github.com/salesforce/lwr/issues"
|
|
15
|
+
"url": "https://github.com/salesforce-experience-platform-emu/lwr/issues"
|
|
16
16
|
},
|
|
17
17
|
"type": "module",
|
|
18
18
|
"types": "build/es/index.d.ts",
|
|
@@ -36,48 +36,47 @@
|
|
|
36
36
|
"package.cjs"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@
|
|
40
|
-
"@lwrjs/
|
|
41
|
-
"@lwrjs/asset-
|
|
42
|
-
"@lwrjs/
|
|
43
|
-
"@lwrjs/base-view-provider": "0.9.0
|
|
44
|
-
"@lwrjs/base-view-transformer": "0.9.0
|
|
45
|
-
"@lwrjs/client-modules": "0.9.0
|
|
46
|
-
"@lwrjs/
|
|
47
|
-
"@lwrjs/
|
|
48
|
-
"@lwrjs/
|
|
49
|
-
"@lwrjs/
|
|
50
|
-
"@lwrjs/
|
|
51
|
-
"@lwrjs/
|
|
52
|
-
"@lwrjs/
|
|
53
|
-
"@lwrjs/
|
|
54
|
-
"@lwrjs/
|
|
55
|
-
"@lwrjs/module-
|
|
56
|
-
"@lwrjs/
|
|
57
|
-
"@lwrjs/
|
|
58
|
-
"@lwrjs/
|
|
59
|
-
"@lwrjs/
|
|
60
|
-
"@lwrjs/
|
|
61
|
-
"@lwrjs/
|
|
62
|
-
"@lwrjs/
|
|
63
|
-
"
|
|
64
|
-
"@lwrjs/view-registry": "0.9.0-alpha.8",
|
|
39
|
+
"@locker/compiler": "0.18.14",
|
|
40
|
+
"@lwrjs/app-service": "0.9.0",
|
|
41
|
+
"@lwrjs/asset-registry": "0.9.0",
|
|
42
|
+
"@lwrjs/asset-transformer": "0.9.0",
|
|
43
|
+
"@lwrjs/base-view-provider": "0.9.0",
|
|
44
|
+
"@lwrjs/base-view-transformer": "0.9.0",
|
|
45
|
+
"@lwrjs/client-modules": "0.9.0",
|
|
46
|
+
"@lwrjs/config": "0.9.0",
|
|
47
|
+
"@lwrjs/diagnostics": "0.9.0",
|
|
48
|
+
"@lwrjs/fs-asset-provider": "0.9.0",
|
|
49
|
+
"@lwrjs/html-view-provider": "0.9.0",
|
|
50
|
+
"@lwrjs/loader": "0.9.0",
|
|
51
|
+
"@lwrjs/lwc-module-provider": "0.9.0",
|
|
52
|
+
"@lwrjs/markdown-view-provider": "0.9.0",
|
|
53
|
+
"@lwrjs/module-bundler": "0.9.0",
|
|
54
|
+
"@lwrjs/module-registry": "0.9.0",
|
|
55
|
+
"@lwrjs/npm-module-provider": "0.9.0",
|
|
56
|
+
"@lwrjs/nunjucks-view-provider": "0.9.0",
|
|
57
|
+
"@lwrjs/o11y": "0.9.0",
|
|
58
|
+
"@lwrjs/resource-registry": "0.9.0",
|
|
59
|
+
"@lwrjs/router": "0.9.0",
|
|
60
|
+
"@lwrjs/server": "0.9.0",
|
|
61
|
+
"@lwrjs/shared-utils": "0.9.0",
|
|
62
|
+
"@lwrjs/view-registry": "0.9.0",
|
|
63
|
+
"chokidar": "^3.5.3",
|
|
65
64
|
"esbuild": "^0.9.7",
|
|
66
|
-
"fs-extra": "^
|
|
67
|
-
"ms": "^2.1.3",
|
|
65
|
+
"fs-extra": "^11.1.0",
|
|
68
66
|
"path-to-regexp": "^6.2.0",
|
|
69
67
|
"qs": "^6.9.4",
|
|
68
|
+
"rollup": "~2.45.2",
|
|
70
69
|
"ws": "^8.8.1"
|
|
71
70
|
},
|
|
72
71
|
"devDependencies": {
|
|
73
|
-
"@lwrjs/types": "0.9.0
|
|
72
|
+
"@lwrjs/types": "0.9.0",
|
|
74
73
|
"@types/ws": "^8.5.3"
|
|
75
74
|
},
|
|
76
75
|
"peerDependencies": {
|
|
77
76
|
"lwc": "2.x"
|
|
78
77
|
},
|
|
79
78
|
"engines": {
|
|
80
|
-
"node": ">=
|
|
79
|
+
"node": ">=16.0.0 <20"
|
|
81
80
|
},
|
|
82
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "4e42b0dc5453f92b36b42aa8132c5bc281e616b7"
|
|
83
82
|
}
|