@angular/ssr 22.2.0-next.5 → 22.2.0-next.7
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/fesm2022/_validation-chunk.mjs.map +1 -1
- package/fesm2022/node.mjs +33 -8
- package/fesm2022/node.mjs.map +1 -1
- package/fesm2022/ssr.mjs +28 -233
- package/fesm2022/ssr.mjs.map +1 -1
- package/package.json +9 -9
- package/types/ssr.d.ts +12 -75
- package/third_party/beasties/THIRD_PARTY_LICENSES.txt +0 -524
- package/third_party/beasties/index.d.ts +0 -9
- package/third_party/beasties/index.js +0 -12913
- package/third_party/beasties/index.js.map +0 -1
package/fesm2022/ssr.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { APP_BASE_HREF, PlatformLocation } from '@angular/common';
|
|
|
3
3
|
import { ɵConsole as _Console, ApplicationRef, REQUEST, makeEnvironmentProviders, provideEnvironmentInitializer, inject, InjectionToken, ɵENABLE_ROOT_COMPONENT_BOOTSTRAP as _ENABLE_ROOT_COMPONENT_BOOTSTRAP, Compiler, createEnvironmentInjector, EnvironmentInjector, runInInjectionContext, ɵresetCompiledComponents as _resetCompiledComponents, REQUEST_CONTEXT, RESPONSE_INIT, LOCALE_ID } from '@angular/core';
|
|
4
4
|
import { platformServer, INITIAL_CONFIG, ɵSERVER_CONTEXT as _SERVER_CONTEXT, ɵrenderInternal as _renderInternal, provideServerRendering as provideServerRendering$1 } from '@angular/platform-server';
|
|
5
5
|
import { ActivatedRoute, Router, ROUTES, ɵloadChildren as _loadChildren } from '@angular/router';
|
|
6
|
-
import
|
|
6
|
+
import { createProcessor } from 'beasties/runtime';
|
|
7
7
|
|
|
8
8
|
class ServerAssets {
|
|
9
9
|
manifest;
|
|
@@ -962,197 +962,7 @@ class ServerRouter {
|
|
|
962
962
|
}
|
|
963
963
|
}
|
|
964
964
|
|
|
965
|
-
async function sha256(data) {
|
|
966
|
-
const encodedData = new TextEncoder().encode(data);
|
|
967
|
-
const hashBuffer = await crypto.subtle.digest('SHA-256', encodedData);
|
|
968
|
-
const hashParts = [];
|
|
969
|
-
for (const h of new Uint8Array(hashBuffer)) {
|
|
970
|
-
hashParts.push(h.toString(16).padStart(2, '0'));
|
|
971
|
-
}
|
|
972
|
-
return hashParts.join('');
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
const MEDIA_SET_HANDLER_PATTERN = /^this\.media=["'](.*)["'];?$/;
|
|
976
|
-
const CSP_MEDIA_ATTR = 'ngCspMedia';
|
|
977
|
-
const LINK_LOAD_SCRIPT_CONTENT = /* @__PURE__ */(() => `(() => {
|
|
978
|
-
const CSP_MEDIA_ATTR = '${CSP_MEDIA_ATTR}';
|
|
979
|
-
const documentElement = document.documentElement;
|
|
980
|
-
|
|
981
|
-
// Listener for load events on link tags.
|
|
982
|
-
const listener = (e) => {
|
|
983
|
-
const target = e.target;
|
|
984
|
-
if (
|
|
985
|
-
!target ||
|
|
986
|
-
target.tagName !== 'LINK' ||
|
|
987
|
-
!target.hasAttribute(CSP_MEDIA_ATTR)
|
|
988
|
-
) {
|
|
989
|
-
return;
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
target.media = target.getAttribute(CSP_MEDIA_ATTR);
|
|
993
|
-
target.removeAttribute(CSP_MEDIA_ATTR);
|
|
994
|
-
|
|
995
|
-
if (!document.head.querySelector(\`link[\${CSP_MEDIA_ATTR}]\`)) {
|
|
996
|
-
documentElement.removeEventListener('load', listener);
|
|
997
|
-
}
|
|
998
|
-
};
|
|
999
|
-
|
|
1000
|
-
documentElement.addEventListener('load', listener, true);
|
|
1001
|
-
})();`)();
|
|
1002
|
-
class BeastiesBase extends Beasties {}
|
|
1003
|
-
class InlineCriticalCssProcessor extends BeastiesBase {
|
|
1004
|
-
readFile;
|
|
1005
|
-
outputPath;
|
|
1006
|
-
addedCspScriptsDocuments = new WeakSet();
|
|
1007
|
-
documentNonces = new WeakMap();
|
|
1008
|
-
constructor(readFile, outputPath) {
|
|
1009
|
-
super({
|
|
1010
|
-
logger: {
|
|
1011
|
-
warn: s => console.warn(s),
|
|
1012
|
-
error: s => console.error(s),
|
|
1013
|
-
info: () => {}
|
|
1014
|
-
},
|
|
1015
|
-
logLevel: 'warn',
|
|
1016
|
-
path: outputPath,
|
|
1017
|
-
publicPath: undefined,
|
|
1018
|
-
compress: false,
|
|
1019
|
-
pruneSource: false,
|
|
1020
|
-
reduceInlineStyles: false,
|
|
1021
|
-
mergeStylesheets: false,
|
|
1022
|
-
preload: 'media',
|
|
1023
|
-
noscriptFallback: true,
|
|
1024
|
-
inlineFonts: true
|
|
1025
|
-
});
|
|
1026
|
-
this.readFile = readFile;
|
|
1027
|
-
this.outputPath = outputPath;
|
|
1028
|
-
}
|
|
1029
|
-
async embedLinkedStylesheet(link, document) {
|
|
1030
|
-
if (link.getAttribute('media') === 'print' && link.next?.name === 'noscript') {
|
|
1031
|
-
const media = link.getAttribute('onload')?.match(MEDIA_SET_HANDLER_PATTERN);
|
|
1032
|
-
if (media) {
|
|
1033
|
-
link.removeAttribute('onload');
|
|
1034
|
-
link.setAttribute('media', media[1]);
|
|
1035
|
-
link?.next?.remove();
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
const returnValue = await super.embedLinkedStylesheet(link, document);
|
|
1039
|
-
const cspNonce = this.findCspNonce(document);
|
|
1040
|
-
if (cspNonce) {
|
|
1041
|
-
const beastiesMedia = link.getAttribute('onload')?.match(MEDIA_SET_HANDLER_PATTERN);
|
|
1042
|
-
if (beastiesMedia) {
|
|
1043
|
-
link.removeAttribute('onload');
|
|
1044
|
-
link.setAttribute(CSP_MEDIA_ATTR, beastiesMedia[1]);
|
|
1045
|
-
this.conditionallyInsertCspLoadingScript(document, cspNonce, link);
|
|
1046
|
-
}
|
|
1047
|
-
document.head.children.forEach(child => {
|
|
1048
|
-
if (child.tagName === 'style' && !child.hasAttribute('nonce')) {
|
|
1049
|
-
child.setAttribute('nonce', cspNonce);
|
|
1050
|
-
}
|
|
1051
|
-
});
|
|
1052
|
-
}
|
|
1053
|
-
return returnValue;
|
|
1054
|
-
}
|
|
1055
|
-
findCspNonce(document) {
|
|
1056
|
-
if (this.documentNonces.has(document)) {
|
|
1057
|
-
return this.documentNonces.get(document);
|
|
1058
|
-
}
|
|
1059
|
-
const nonceElement = document.querySelector('[ngCspNonce], [ngcspnonce]');
|
|
1060
|
-
const cspNonce = nonceElement?.getAttribute('ngCspNonce') || nonceElement?.getAttribute('ngcspnonce') || null;
|
|
1061
|
-
this.documentNonces.set(document, cspNonce);
|
|
1062
|
-
return cspNonce;
|
|
1063
|
-
}
|
|
1064
|
-
conditionallyInsertCspLoadingScript(document, nonce, link) {
|
|
1065
|
-
if (this.addedCspScriptsDocuments.has(document)) {
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
if (document.head.textContent.includes(LINK_LOAD_SCRIPT_CONTENT)) {
|
|
1069
|
-
this.addedCspScriptsDocuments.add(document);
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
const script = document.createElement('script');
|
|
1073
|
-
script.setAttribute('nonce', nonce);
|
|
1074
|
-
script.textContent = LINK_LOAD_SCRIPT_CONTENT;
|
|
1075
|
-
document.head.insertBefore(script, link);
|
|
1076
|
-
this.addedCspScriptsDocuments.add(document);
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
class LRUCache {
|
|
1081
|
-
capacity;
|
|
1082
|
-
cache = new Map();
|
|
1083
|
-
head;
|
|
1084
|
-
tail;
|
|
1085
|
-
constructor(capacity) {
|
|
1086
|
-
this.capacity = capacity;
|
|
1087
|
-
}
|
|
1088
|
-
get(key) {
|
|
1089
|
-
const node = this.cache.get(key);
|
|
1090
|
-
if (node) {
|
|
1091
|
-
this.moveToHead(node);
|
|
1092
|
-
return node.value;
|
|
1093
|
-
}
|
|
1094
|
-
return undefined;
|
|
1095
|
-
}
|
|
1096
|
-
put(key, value) {
|
|
1097
|
-
const cachedNode = this.cache.get(key);
|
|
1098
|
-
if (cachedNode) {
|
|
1099
|
-
cachedNode.value = value;
|
|
1100
|
-
this.moveToHead(cachedNode);
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
const newNode = {
|
|
1104
|
-
key,
|
|
1105
|
-
value,
|
|
1106
|
-
prev: undefined,
|
|
1107
|
-
next: undefined
|
|
1108
|
-
};
|
|
1109
|
-
this.cache.set(key, newNode);
|
|
1110
|
-
this.addToHead(newNode);
|
|
1111
|
-
if (this.cache.size > this.capacity) {
|
|
1112
|
-
const tail = this.removeTail();
|
|
1113
|
-
if (tail) {
|
|
1114
|
-
this.cache.delete(tail.key);
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
addToHead(node) {
|
|
1119
|
-
node.next = this.head;
|
|
1120
|
-
node.prev = undefined;
|
|
1121
|
-
if (this.head) {
|
|
1122
|
-
this.head.prev = node;
|
|
1123
|
-
}
|
|
1124
|
-
this.head = node;
|
|
1125
|
-
if (!this.tail) {
|
|
1126
|
-
this.tail = node;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
removeNode(node) {
|
|
1130
|
-
if (node.prev) {
|
|
1131
|
-
node.prev.next = node.next;
|
|
1132
|
-
} else {
|
|
1133
|
-
this.head = node.next;
|
|
1134
|
-
}
|
|
1135
|
-
if (node.next) {
|
|
1136
|
-
node.next.prev = node.prev;
|
|
1137
|
-
} else {
|
|
1138
|
-
this.tail = node.prev;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
moveToHead(node) {
|
|
1142
|
-
this.removeNode(node);
|
|
1143
|
-
this.addToHead(node);
|
|
1144
|
-
}
|
|
1145
|
-
removeTail() {
|
|
1146
|
-
const node = this.tail;
|
|
1147
|
-
if (node) {
|
|
1148
|
-
this.removeNode(node);
|
|
1149
|
-
}
|
|
1150
|
-
return node;
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
965
|
const WELL_KNOWN_NON_ANGULAR_URLS = new Set(['/favicon.ico', '/.well-known/appspecific/com.chrome.devtools.json']);
|
|
1155
|
-
const MAX_INLINE_CSS_CACHE_ENTRIES = 50;
|
|
1156
966
|
const SERVER_CONTEXT_VALUE = {
|
|
1157
967
|
[RenderMode.Prerender]: 'ssg',
|
|
1158
968
|
[RenderMode.Server]: 'ssr',
|
|
@@ -1166,20 +976,13 @@ class AngularServerApp {
|
|
|
1166
976
|
this.options = options;
|
|
1167
977
|
this.allowStaticRouteRender = this.options.allowStaticRouteRender ?? false;
|
|
1168
978
|
this.hooks = options.hooks ?? new Hooks();
|
|
1169
|
-
if (this.manifest.inlineCriticalCss) {
|
|
1170
|
-
this.inlineCriticalCssProcessor = new InlineCriticalCssProcessor(path => {
|
|
1171
|
-
const fileName = path.split('/').pop() ?? path;
|
|
1172
|
-
return this.assets.getServerAsset(fileName).text();
|
|
1173
|
-
});
|
|
1174
|
-
}
|
|
1175
979
|
}
|
|
1176
980
|
manifest = getAngularAppManifest();
|
|
1177
981
|
assets = new ServerAssets(this.manifest);
|
|
1178
982
|
router;
|
|
1179
983
|
inlineCriticalCssProcessor;
|
|
1180
984
|
boostrap;
|
|
1181
|
-
|
|
1182
|
-
criticalCssLRUCache = new LRUCache(MAX_INLINE_CSS_CACHE_ENTRIES);
|
|
985
|
+
textEncoder = new TextEncoder();
|
|
1183
986
|
async handle(request, requestContext) {
|
|
1184
987
|
const url = new URL(request.url);
|
|
1185
988
|
if (WELL_KNOWN_NON_ANGULAR_URLS.has(url.pathname)) {
|
|
@@ -1315,15 +1118,15 @@ class AngularServerApp {
|
|
|
1315
1118
|
}
|
|
1316
1119
|
if (renderMode === RenderMode.Prerender) {
|
|
1317
1120
|
const renderedHtml = await result.content();
|
|
1318
|
-
const finalHtml =
|
|
1121
|
+
const finalHtml = this.inlineCriticalCss(renderedHtml);
|
|
1319
1122
|
return new Response(finalHtml, responseInit);
|
|
1320
1123
|
}
|
|
1321
1124
|
const stream = new ReadableStream({
|
|
1322
1125
|
start: async controller => {
|
|
1323
1126
|
try {
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
controller.enqueue(
|
|
1127
|
+
let renderedHtml = await result.content();
|
|
1128
|
+
renderedHtml = this.inlineCriticalCss(renderedHtml);
|
|
1129
|
+
controller.enqueue(this.textEncoder.encode(renderedHtml));
|
|
1327
1130
|
controller.close();
|
|
1328
1131
|
} catch (error) {
|
|
1329
1132
|
result.destroy();
|
|
@@ -1336,47 +1139,39 @@ class AngularServerApp {
|
|
|
1336
1139
|
});
|
|
1337
1140
|
return new Response(stream, responseInit);
|
|
1338
1141
|
}
|
|
1339
|
-
|
|
1142
|
+
inlineCriticalCss(html) {
|
|
1340
1143
|
const {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1144
|
+
criticalCssPlans,
|
|
1145
|
+
nonce
|
|
1146
|
+
} = this.manifest;
|
|
1147
|
+
if (!criticalCssPlans?.length) {
|
|
1344
1148
|
return html;
|
|
1345
1149
|
}
|
|
1346
1150
|
try {
|
|
1347
|
-
|
|
1151
|
+
this.inlineCriticalCssProcessor ??= createProcessor([...criticalCssPlans], {
|
|
1152
|
+
preload: 'media-script',
|
|
1153
|
+
nonce,
|
|
1154
|
+
preloadFonts: true,
|
|
1155
|
+
inlineFonts: true,
|
|
1156
|
+
noscriptFallback: true,
|
|
1157
|
+
cache: true,
|
|
1158
|
+
logger: {
|
|
1159
|
+
warn: console.warn
|
|
1160
|
+
}
|
|
1161
|
+
}).process;
|
|
1162
|
+
return this.inlineCriticalCssProcessor(html);
|
|
1348
1163
|
} catch (error) {
|
|
1349
|
-
console.error(
|
|
1164
|
+
console.error('An error occurred while inlining critical CSS.', error);
|
|
1350
1165
|
return html;
|
|
1351
1166
|
}
|
|
1352
1167
|
}
|
|
1353
|
-
async inlineCriticalCssWithCache(html, url) {
|
|
1354
|
-
const {
|
|
1355
|
-
inlineCriticalCssProcessor,
|
|
1356
|
-
criticalCssLRUCache,
|
|
1357
|
-
textDecoder
|
|
1358
|
-
} = this;
|
|
1359
|
-
if (!inlineCriticalCssProcessor) {
|
|
1360
|
-
return textDecoder.encode(html);
|
|
1361
|
-
}
|
|
1362
|
-
const cacheKey = url.toString();
|
|
1363
|
-
const cached = criticalCssLRUCache.get(cacheKey);
|
|
1364
|
-
const shaOfContentPreInlinedCss = await sha256(html);
|
|
1365
|
-
if (cached?.shaOfContentPreInlinedCss === shaOfContentPreInlinedCss) {
|
|
1366
|
-
return cached.contentWithCriticialCSS;
|
|
1367
|
-
}
|
|
1368
|
-
const processedHtml = await this.inlineCriticalCss(html, url);
|
|
1369
|
-
const finalHtml = textDecoder.encode(processedHtml);
|
|
1370
|
-
criticalCssLRUCache.put(cacheKey, {
|
|
1371
|
-
shaOfContentPreInlinedCss,
|
|
1372
|
-
contentWithCriticialCSS: finalHtml
|
|
1373
|
-
});
|
|
1374
|
-
return finalHtml;
|
|
1375
|
-
}
|
|
1376
1168
|
buildServerAssetPathFromRequest(request) {
|
|
1377
1169
|
let {
|
|
1378
1170
|
pathname: assetPath
|
|
1379
1171
|
} = new URL(request.url);
|
|
1172
|
+
try {
|
|
1173
|
+
assetPath = decodeURIComponent(assetPath);
|
|
1174
|
+
} catch {}
|
|
1380
1175
|
if (!assetPath.endsWith('/index.html')) {
|
|
1381
1176
|
assetPath = joinUrlParts(assetPath, 'index.html');
|
|
1382
1177
|
}
|
|
@@ -1612,5 +1407,5 @@ function createRequestHandler(handler) {
|
|
|
1612
1407
|
return handler;
|
|
1613
1408
|
}
|
|
1614
1409
|
|
|
1615
|
-
export { AngularAppEngine, IS_DISCOVERING_ROUTES, PrerenderFallback, RenderMode, createRequestHandler, provideServerRendering, withAppShell, withRoutes,
|
|
1410
|
+
export { AngularAppEngine, IS_DISCOVERING_ROUTES, PrerenderFallback, RenderMode, createRequestHandler, provideServerRendering, withAppShell, withRoutes, destroyAngularServerApp as ɵdestroyAngularServerApp, extractRoutesAndCreateRouteTree as ɵextractRoutesAndCreateRouteTree, getOrCreateAngularServerApp as ɵgetOrCreateAngularServerApp, getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig, setAngularAppEngineManifest as ɵsetAngularAppEngineManifest, setAngularAppManifest as ɵsetAngularAppManifest };
|
|
1616
1411
|
//# sourceMappingURL=ssr.mjs.map
|