@angular/ssr 19.1.0-next.0 → 19.1.0-next.1
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/ssr.mjs +291 -26
- package/fesm2022/ssr.mjs.map +1 -1
- package/index.d.ts +48 -6
- package/package.json +7 -7
- package/third_party/beasties/index.js +80 -29
- package/third_party/beasties/index.js.map +1 -1
package/index.d.ts
CHANGED
|
@@ -36,9 +36,9 @@ export declare class AngularAppEngine {
|
|
|
36
36
|
*/
|
|
37
37
|
private readonly manifest;
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* A map of supported locales from the server application's manifest.
|
|
40
40
|
*/
|
|
41
|
-
private readonly
|
|
41
|
+
private readonly supportedLocales;
|
|
42
42
|
/**
|
|
43
43
|
* A cache that holds entry points, keyed by their potential locale string.
|
|
44
44
|
*/
|
|
@@ -55,6 +55,15 @@ export declare class AngularAppEngine {
|
|
|
55
55
|
* corresponding to `https://www.example.com/page`.
|
|
56
56
|
*/
|
|
57
57
|
handle(request: Request, requestContext?: unknown): Promise<Response | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Handles requests for the base path when i18n is enabled.
|
|
60
|
+
* Redirects the user to a locale-specific path based on the `Accept-Language` header.
|
|
61
|
+
*
|
|
62
|
+
* @param request The incoming request.
|
|
63
|
+
* @returns A `Response` object with a 302 redirect, or `null` if i18n is not enabled
|
|
64
|
+
* or the request is not for the base path.
|
|
65
|
+
*/
|
|
66
|
+
private redirectBasedOnAcceptLanguage;
|
|
58
67
|
/**
|
|
59
68
|
* Retrieves the Angular server application instance for a given request.
|
|
60
69
|
*
|
|
@@ -95,7 +104,7 @@ declare interface AngularAppEngineManifest {
|
|
|
95
104
|
/**
|
|
96
105
|
* A readonly record of entry points for the server application.
|
|
97
106
|
* Each entry consists of:
|
|
98
|
-
* - `key`: The
|
|
107
|
+
* - `key`: The url segment for the entry point.
|
|
99
108
|
* - `value`: A function that returns a promise resolving to an object of type `EntryPointExports`.
|
|
100
109
|
*/
|
|
101
110
|
readonly entryPoints: Readonly<Record<string, (() => Promise<EntryPointExports>) | undefined>>;
|
|
@@ -104,6 +113,13 @@ declare interface AngularAppEngineManifest {
|
|
|
104
113
|
* This is used to determine the root path of the application.
|
|
105
114
|
*/
|
|
106
115
|
readonly basePath: string;
|
|
116
|
+
/**
|
|
117
|
+
* A readonly record mapping supported locales to their respective entry-point paths.
|
|
118
|
+
* Each entry consists of:
|
|
119
|
+
* - `key`: The locale identifier (e.g., 'en', 'fr').
|
|
120
|
+
* - `value`: The url segment associated with that locale.
|
|
121
|
+
*/
|
|
122
|
+
readonly supportedLocales: Readonly<Record<string, string | undefined>>;
|
|
107
123
|
}
|
|
108
124
|
|
|
109
125
|
/**
|
|
@@ -144,6 +160,26 @@ declare interface AngularAppManifest {
|
|
|
144
160
|
* the application, aiding with localization and rendering content specific to the locale.
|
|
145
161
|
*/
|
|
146
162
|
readonly locale?: string;
|
|
163
|
+
/**
|
|
164
|
+
* Maps entry-point names to their corresponding browser bundles and loading strategies.
|
|
165
|
+
*
|
|
166
|
+
* - **Key**: The entry-point name, typically the value of `ɵentryName`.
|
|
167
|
+
* - **Value**: An array of objects, each representing a browser bundle with:
|
|
168
|
+
* - `path`: The filename or URL of the associated JavaScript bundle to preload.
|
|
169
|
+
* - `dynamicImport`: A boolean indicating whether the bundle is loaded via a dynamic `import()`.
|
|
170
|
+
* If `true`, the bundle is lazily loaded, impacting its preloading behavior.
|
|
171
|
+
*
|
|
172
|
+
* ### Example
|
|
173
|
+
* ```ts
|
|
174
|
+
* {
|
|
175
|
+
* 'src/app/lazy/lazy.ts': [{ path: 'src/app/lazy/lazy.js', dynamicImport: true }]
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
readonly entryPointToBrowserMapping?: Readonly<Record<string, ReadonlyArray<{
|
|
180
|
+
path: string;
|
|
181
|
+
dynamicImport: boolean;
|
|
182
|
+
}> | undefined>>;
|
|
147
183
|
}
|
|
148
184
|
|
|
149
185
|
/**
|
|
@@ -293,6 +329,7 @@ declare class AngularServerApp {
|
|
|
293
329
|
*
|
|
294
330
|
* @param html - The raw HTML content to be transformed.
|
|
295
331
|
* @param url - The URL associated with the HTML content, used for context during transformations.
|
|
332
|
+
* @param preload - An array of URLs representing the JavaScript resources to preload.
|
|
296
333
|
* @returns A promise that resolves to the transformed HTML string.
|
|
297
334
|
*/
|
|
298
335
|
private runTransformsOnHtml;
|
|
@@ -369,6 +406,8 @@ declare interface EntryPointExports {
|
|
|
369
406
|
ɵdestroyAngularServerApp: () => void;
|
|
370
407
|
}
|
|
371
408
|
|
|
409
|
+
declare type EntryPointToBrowserMapping = AngularAppManifest['entryPointToBrowserMapping'];
|
|
410
|
+
|
|
372
411
|
/**
|
|
373
412
|
* Defines the names of available hooks for registering and triggering custom logic within the application.
|
|
374
413
|
*/
|
|
@@ -493,8 +532,6 @@ export declare enum PrerenderFallback {
|
|
|
493
532
|
* @param options - (Optional) An object containing additional configuration options for server routes.
|
|
494
533
|
* @returns An `EnvironmentProviders` instance with the server routes configuration.
|
|
495
534
|
*
|
|
496
|
-
* @returns An `EnvironmentProviders` object that contains the server routes configuration.
|
|
497
|
-
*
|
|
498
535
|
* @see {@link ServerRoute}
|
|
499
536
|
* @see {@link ServerRoutesConfigOptions}
|
|
500
537
|
* @developerPreview
|
|
@@ -700,6 +737,10 @@ declare interface RouteTreeNodeMetadata {
|
|
|
700
737
|
* Specifies the rendering mode used for this route.
|
|
701
738
|
*/
|
|
702
739
|
renderMode: RenderMode;
|
|
740
|
+
/**
|
|
741
|
+
* A list of resource that should be preloaded by the browser.
|
|
742
|
+
*/
|
|
743
|
+
preload?: readonly string[];
|
|
703
744
|
}
|
|
704
745
|
|
|
705
746
|
/**
|
|
@@ -920,10 +961,11 @@ export declare function ɵgetOrCreateAngularServerApp(options?: Readonly<Angular
|
|
|
920
961
|
* @param invokeGetPrerenderParams - A boolean flag indicating whether to invoke `getPrerenderParams` for parameterized SSG routes
|
|
921
962
|
* to handle prerendering paths. Defaults to `false`.
|
|
922
963
|
* @param includePrerenderFallbackRoutes - A flag indicating whether to include fallback routes in the result. Defaults to `true`.
|
|
964
|
+
* @param entryPointToBrowserMapping - Maps the entry-point name to the associated JavaScript browser bundles.
|
|
923
965
|
*
|
|
924
966
|
* @returns A promise that resolves to an object of type `AngularRouterConfigResult` or errors.
|
|
925
967
|
*/
|
|
926
|
-
export declare function ɵgetRoutesFromAngularRouterConfig(bootstrap: AngularBootstrap, document: string, url: URL, invokeGetPrerenderParams?: boolean, includePrerenderFallbackRoutes?: boolean): Promise<AngularRouterConfigResult>;
|
|
968
|
+
export declare function ɵgetRoutesFromAngularRouterConfig(bootstrap: AngularBootstrap, document: string, url: URL, invokeGetPrerenderParams?: boolean, includePrerenderFallbackRoutes?: boolean, entryPointToBrowserMapping?: EntryPointToBrowserMapping | undefined): Promise<AngularRouterConfigResult>;
|
|
927
969
|
|
|
928
970
|
export declare class ɵInlineCriticalCssProcessor extends BeastiesBase {
|
|
929
971
|
readFile: (path: string) => Promise<string>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular/ssr",
|
|
3
|
-
"version": "19.1.0-next.
|
|
3
|
+
"version": "19.1.0-next.1",
|
|
4
4
|
"description": "Angular server side rendering utilities",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/angular/angular-cli",
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@angular/common": "19.1.0-next.
|
|
31
|
-
"@angular/compiler": "19.1.0-next.
|
|
32
|
-
"@angular/core": "19.1.0-next.
|
|
33
|
-
"@angular/platform-browser": "19.1.0-next.
|
|
34
|
-
"@angular/platform-server": "19.1.0-next.
|
|
35
|
-
"@angular/router": "19.1.0-next.
|
|
30
|
+
"@angular/common": "19.1.0-next.2",
|
|
31
|
+
"@angular/compiler": "19.1.0-next.2",
|
|
32
|
+
"@angular/core": "19.1.0-next.2",
|
|
33
|
+
"@angular/platform-browser": "19.1.0-next.2",
|
|
34
|
+
"@angular/platform-server": "19.1.0-next.2",
|
|
35
|
+
"@angular/router": "19.1.0-next.2",
|
|
36
36
|
"@bazel/runfiles": "^5.8.1"
|
|
37
37
|
},
|
|
38
38
|
"sideEffects": false,
|
|
@@ -10964,36 +10964,43 @@ function parseStylesheet(stylesheet) {
|
|
|
10964
10964
|
return parse$2(stylesheet);
|
|
10965
10965
|
}
|
|
10966
10966
|
function serializeStylesheet(ast, options) {
|
|
10967
|
-
|
|
10967
|
+
const cssParts = [];
|
|
10968
10968
|
stringify(ast, (result, node, type) => {
|
|
10969
10969
|
if (node?.type === "decl" && node.value.includes("</style>")) {
|
|
10970
10970
|
return;
|
|
10971
10971
|
}
|
|
10972
10972
|
if (!options.compress) {
|
|
10973
|
-
|
|
10973
|
+
cssParts.push(result);
|
|
10974
10974
|
return;
|
|
10975
10975
|
}
|
|
10976
10976
|
if (node?.type === "comment")
|
|
10977
10977
|
return;
|
|
10978
10978
|
if (node?.type === "decl") {
|
|
10979
10979
|
const prefix = node.prop + node.raws.between;
|
|
10980
|
-
|
|
10980
|
+
cssParts.push(result.replace(prefix, prefix.trim()));
|
|
10981
10981
|
return;
|
|
10982
10982
|
}
|
|
10983
10983
|
if (type === "start") {
|
|
10984
10984
|
if (node?.type === "rule" && node.selectors) {
|
|
10985
|
-
|
|
10985
|
+
if (node.selectors.length === 1) {
|
|
10986
|
+
cssParts.push(node.selectors[0] ?? "", "{");
|
|
10987
|
+
} else {
|
|
10988
|
+
cssParts.push(node.selectors.join(","), "{");
|
|
10989
|
+
}
|
|
10986
10990
|
} else {
|
|
10987
|
-
|
|
10991
|
+
cssParts.push(result.trim());
|
|
10988
10992
|
}
|
|
10989
10993
|
return;
|
|
10990
10994
|
}
|
|
10991
10995
|
if (type === "end" && result === "}" && node?.raws?.semicolon) {
|
|
10992
|
-
|
|
10996
|
+
const lastItemIdx = cssParts.length - 2;
|
|
10997
|
+
if (lastItemIdx >= 0 && cssParts[lastItemIdx]) {
|
|
10998
|
+
cssParts[lastItemIdx] = cssParts[lastItemIdx].slice(0, -1);
|
|
10999
|
+
}
|
|
10993
11000
|
}
|
|
10994
|
-
|
|
11001
|
+
cssParts.push(result.trim());
|
|
10995
11002
|
});
|
|
10996
|
-
return
|
|
11003
|
+
return cssParts.join("");
|
|
10997
11004
|
}
|
|
10998
11005
|
function markOnly(predicate) {
|
|
10999
11006
|
return (rule) => {
|
|
@@ -11176,7 +11183,7 @@ function extendElement(element) {
|
|
|
11176
11183
|
return this.getAttribute("id");
|
|
11177
11184
|
},
|
|
11178
11185
|
set(value) {
|
|
11179
|
-
this.
|
|
11186
|
+
this.setAttribute("id", value);
|
|
11180
11187
|
}
|
|
11181
11188
|
},
|
|
11182
11189
|
className: {
|
|
@@ -11336,21 +11343,40 @@ function extendDocument(document) {
|
|
|
11336
11343
|
}
|
|
11337
11344
|
});
|
|
11338
11345
|
}
|
|
11346
|
+
const selectorTokensCache = /* @__PURE__ */ new Map();
|
|
11339
11347
|
function cachedQuerySelector(sel, node) {
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11348
|
+
let selectorTokens = selectorTokensCache.get(sel);
|
|
11349
|
+
if (selectorTokens === void 0) {
|
|
11350
|
+
selectorTokens = parseRelevantSelectors(sel);
|
|
11351
|
+
selectorTokensCache.set(sel, selectorTokens);
|
|
11352
|
+
}
|
|
11353
|
+
if (selectorTokens) {
|
|
11354
|
+
for (const token of selectorTokens) {
|
|
11355
|
+
if (token.name === "class") {
|
|
11345
11356
|
return classCache.has(token.value);
|
|
11346
11357
|
}
|
|
11347
|
-
if (token.
|
|
11358
|
+
if (token.name === "id") {
|
|
11348
11359
|
return idCache.has(token.value);
|
|
11349
11360
|
}
|
|
11350
11361
|
}
|
|
11351
11362
|
}
|
|
11352
11363
|
return !!selectOne(sel, node);
|
|
11353
11364
|
}
|
|
11365
|
+
function parseRelevantSelectors(sel) {
|
|
11366
|
+
const tokens = parse$1(sel);
|
|
11367
|
+
const relevantTokens = [];
|
|
11368
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
11369
|
+
const tokenGroup = tokens[i];
|
|
11370
|
+
if (tokenGroup?.length !== 1) {
|
|
11371
|
+
continue;
|
|
11372
|
+
}
|
|
11373
|
+
const token = tokenGroup[0];
|
|
11374
|
+
if (token?.type === "attribute" && (token.name === "class" || token.name === "id")) {
|
|
11375
|
+
relevantTokens.push(token);
|
|
11376
|
+
}
|
|
11377
|
+
}
|
|
11378
|
+
return relevantTokens.length > 0 ? relevantTokens : null;
|
|
11379
|
+
}
|
|
11354
11380
|
|
|
11355
11381
|
const LOG_LEVELS = ["trace", "debug", "info", "warn", "error", "silent"];
|
|
11356
11382
|
const defaultLogger = {
|
|
@@ -11393,8 +11419,25 @@ var __publicField = (obj, key, value) => {
|
|
|
11393
11419
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
11394
11420
|
return value;
|
|
11395
11421
|
};
|
|
11422
|
+
var __accessCheck = (obj, member, msg) => {
|
|
11423
|
+
if (!member.has(obj))
|
|
11424
|
+
throw TypeError("Cannot " + msg);
|
|
11425
|
+
};
|
|
11426
|
+
var __privateGet = (obj, member, getter) => {
|
|
11427
|
+
__accessCheck(obj, member, "read from private field");
|
|
11428
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
11429
|
+
};
|
|
11430
|
+
var __privateAdd = (obj, member, value) => {
|
|
11431
|
+
if (member.has(obj))
|
|
11432
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
11433
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
11434
|
+
};
|
|
11435
|
+
var _selectorCache;
|
|
11436
|
+
const removePseudoClassesAndElementsPattern = /(?<!\\)::?[a-z-]+(?:\(.+\))?/gi;
|
|
11437
|
+
const removeTrailingCommasPattern = /\(\s*,|,\s*\)/g;
|
|
11396
11438
|
class Beasties {
|
|
11397
11439
|
constructor(options = {}) {
|
|
11440
|
+
__privateAdd(this, _selectorCache, /* @__PURE__ */ new Map());
|
|
11398
11441
|
__publicField(this, "options");
|
|
11399
11442
|
__publicField(this, "logger");
|
|
11400
11443
|
__publicField(this, "fs");
|
|
@@ -11435,22 +11478,20 @@ class Beasties {
|
|
|
11435
11478
|
const start = Date.now();
|
|
11436
11479
|
const document = createDocument(html);
|
|
11437
11480
|
if (this.options.additionalStylesheets.length > 0) {
|
|
11438
|
-
this.embedAdditionalStylesheet(document);
|
|
11481
|
+
await this.embedAdditionalStylesheet(document);
|
|
11439
11482
|
}
|
|
11440
11483
|
if (this.options.external !== false) {
|
|
11441
|
-
const externalSheets = [
|
|
11442
|
-
document.querySelectorAll('link[rel="stylesheet"]')
|
|
11443
|
-
);
|
|
11484
|
+
const externalSheets = [...document.querySelectorAll('link[rel="stylesheet"]')];
|
|
11444
11485
|
await Promise.all(
|
|
11445
11486
|
externalSheets.map((link) => this.embedLinkedStylesheet(link, document))
|
|
11446
11487
|
);
|
|
11447
11488
|
}
|
|
11448
11489
|
const styles = this.getAffectedStyleTags(document);
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11490
|
+
for (const style of styles) {
|
|
11491
|
+
this.processStyle(style, document);
|
|
11492
|
+
}
|
|
11452
11493
|
if (this.options.mergeStylesheets !== false && styles.length !== 0) {
|
|
11453
|
-
|
|
11494
|
+
this.mergeStylesheets(document);
|
|
11454
11495
|
}
|
|
11455
11496
|
const output = serializeDocument(document);
|
|
11456
11497
|
const end = Date.now();
|
|
@@ -11467,7 +11508,7 @@ class Beasties {
|
|
|
11467
11508
|
}
|
|
11468
11509
|
return styles;
|
|
11469
11510
|
}
|
|
11470
|
-
|
|
11511
|
+
mergeStylesheets(document) {
|
|
11471
11512
|
const styles = this.getAffectedStyleTags(document);
|
|
11472
11513
|
if (styles.length === 0) {
|
|
11473
11514
|
this.logger.warn?.(
|
|
@@ -11654,7 +11695,7 @@ class Beasties {
|
|
|
11654
11695
|
/**
|
|
11655
11696
|
* Parse the stylesheet within a <style> element, then reduce it to contain only rules used by the document.
|
|
11656
11697
|
*/
|
|
11657
|
-
|
|
11698
|
+
processStyle(style, document) {
|
|
11658
11699
|
if (style.$$reduce === false)
|
|
11659
11700
|
return;
|
|
11660
11701
|
const name = style.$$name ? style.$$name.replace(/^\//, "") : "inline CSS";
|
|
@@ -11733,10 +11774,10 @@ class Beasties {
|
|
|
11733
11774
|
});
|
|
11734
11775
|
if (isAllowedRule)
|
|
11735
11776
|
return true;
|
|
11736
|
-
if (sel === ":root" || sel === "html" || sel === "body" || /^::?(?:before|after)$/.test(sel)) {
|
|
11777
|
+
if (sel === ":root" || sel === "html" || sel === "body" || sel[0] === ":" && /^::?(?:before|after)$/.test(sel)) {
|
|
11737
11778
|
return true;
|
|
11738
11779
|
}
|
|
11739
|
-
sel =
|
|
11780
|
+
sel = this.normalizeCssSelector(sel);
|
|
11740
11781
|
if (!sel)
|
|
11741
11782
|
return false;
|
|
11742
11783
|
try {
|
|
@@ -11769,8 +11810,8 @@ class Beasties {
|
|
|
11769
11810
|
}
|
|
11770
11811
|
if (rule.type === "atrule" && rule.name === "font-face")
|
|
11771
11812
|
return;
|
|
11772
|
-
const
|
|
11773
|
-
return
|
|
11813
|
+
const hasRemainingRules = ("nodes" in rule && rule.nodes?.some((rule2) => !rule2.$$remove)) ?? true;
|
|
11814
|
+
return hasRemainingRules;
|
|
11774
11815
|
})
|
|
11775
11816
|
);
|
|
11776
11817
|
if (failedSelectors.length !== 0) {
|
|
@@ -11852,7 +11893,17 @@ class Beasties {
|
|
|
11852
11893
|
`\x1B[32mInlined ${formatSize(sheet.length)} (${percent}% of original ${formatSize(before.length)}) of ${name}${afterText}.\x1B[39m`
|
|
11853
11894
|
);
|
|
11854
11895
|
}
|
|
11896
|
+
normalizeCssSelector(sel) {
|
|
11897
|
+
let normalizedSelector = __privateGet(this, _selectorCache).get(sel);
|
|
11898
|
+
if (normalizedSelector !== void 0) {
|
|
11899
|
+
return normalizedSelector;
|
|
11900
|
+
}
|
|
11901
|
+
normalizedSelector = sel.replace(removePseudoClassesAndElementsPattern, "").replace(removeTrailingCommasPattern, (match) => match.includes("(") ? "(" : ")").trim();
|
|
11902
|
+
__privateGet(this, _selectorCache).set(sel, normalizedSelector);
|
|
11903
|
+
return normalizedSelector;
|
|
11904
|
+
}
|
|
11855
11905
|
}
|
|
11906
|
+
_selectorCache = new WeakMap();
|
|
11856
11907
|
function formatSize(size) {
|
|
11857
11908
|
if (size <= 0) {
|
|
11858
11909
|
return "0 bytes";
|