Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@
"@bazel/buildifier": "7.3.1",
"@bazel/concatjs": "patch:@bazel/concatjs@npm%3A5.8.1#~/.yarn/patches/@bazel-concatjs-npm-5.8.1-1bf81df846.patch",
"@bazel/jasmine": "patch:@bazel/jasmine@npm%3A5.8.1#~/.yarn/patches/@bazel-jasmine-npm-5.8.1-3370fee155.patch",
"@bazel/rollup": "^5.8.1",
"@bazel/runfiles": "^5.8.1",
"@discoveryjs/json-ext": "0.6.2",
"@inquirer/confirm": "5.0.0",
"@inquirer/prompts": "7.0.0",
"@listr2/prompt-adapter-inquirer": "2.0.17",
"@rollup/plugin-alias": "^5.1.1",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Are these dependency changes expected? I'm surprised we didn't already have this for Critters?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because of the second commit that switches the bundling from esbuild to use rollup.

0f22795

"@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-node-resolve": "^13.0.5",
"@stylistic/eslint-plugin": "^2.8.0",
Expand Down Expand Up @@ -124,12 +126,12 @@
"ansi-colors": "4.1.3",
"autoprefixer": "10.4.20",
"babel-loader": "9.2.1",
"beasties": "0.1.0",
"browser-sync": "3.0.3",
"browserslist": "^4.21.5",
"buffer": "6.0.3",
"chokidar": "4.0.1",
"copy-webpack-plugin": "12.0.2",
"critters": "0.0.25",
"css-loader": "7.1.2",
"debug": "^4.1.1",
"esbuild": "0.24.0",
Expand Down Expand Up @@ -184,6 +186,7 @@
"quicktype-core": "23.0.170",
"resolve-url-loader": "5.0.0",
"rollup": "4.24.0",
"rollup-license-plugin": "^3.0.0",
"rollup-plugin-sourcemaps": "^0.6.0",
"rxjs": "7.8.1",
"sass": "1.80.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/build/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ ts_library(
"@npm//@types/semver",
"@npm//@types/watchpack",
"@npm//@vitejs/plugin-basic-ssl",
"@npm//beasties",
"@npm//browserslist",
"@npm//critters",
"@npm//esbuild",
"@npm//esbuild-wasm",
"@npm//fast-glob",
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/build/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"@babel/plugin-syntax-import-attributes": "7.25.9",
"@inquirer/confirm": "5.0.0",
"@vitejs/plugin-basic-ssl": "1.1.0",
"beasties": "0.1.0",
"browserslist": "^4.23.0",
"critters": "0.0.25",
"esbuild": "0.24.0",
"fast-glob": "3.3.2",
"https-proxy-agent": "7.0.5",
Expand Down
4 changes: 2 additions & 2 deletions packages/angular/build/src/tools/esbuild/commonjs-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ export function checkCommonJSModules(
allowedRequests.add('xhr2');

// Packages used by @angular/ssr.
// While critters is ESM it has a number of direct and transtive CJS deps.
// While beasties is ESM it has a number of direct and transtive CJS deps.
allowedRequests.add('express');
allowedRequests.add('critters');
allowedRequests.add('beasties');

// Find all entry points that contain code (JS/TS)
const files: string[] = [];
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/build/src/tools/esbuild/global-styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function createGlobalStylesBundleOptions(
);

// Keep special CSS comments `/*! comment */` in place when `removeSpecialComments` is disabled.
// These comments are special for a number of CSS tools such as Critters and PurgeCSS.
// These comments are special for a number of CSS tools such as Beasties and PurgeCSS.
buildOptions.legalComments = optimizationOptions.styles?.removeSpecialComments
? 'none'
: 'inline';
Expand Down
2 changes: 1 addition & 1 deletion packages/angular/build/src/typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

// The `bundled_critters` causes issues with module mappings in Bazel,
// The `bundled_beasties` causes issues with module mappings in Bazel,
// leading to unexpected behavior with esbuild. Specifically, the problem occurs
// when esbuild resolves to a different module or version than expected, due to
// how Bazel handles module mappings.
Expand Down
39 changes: 19 additions & 20 deletions packages/angular/build/src/utils/index-file/inline-critical-css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
* found in the LICENSE file at https://angular.dev/license
*/

import Critters from 'critters';
import Beasties from 'beasties';
import { readFile } from 'node:fs/promises';

/**
* Pattern used to extract the media query set by Critters in an `onload` handler.
* Pattern used to extract the media query set by Beasties in an `onload` handler.
*/
const MEDIA_SET_HANDLER_PATTERN = /^this\.media=["'](.*)["'];?$/;

/**
* Name of the attribute used to save the Critters media query so it can be re-assigned on load.
* Name of the attribute used to save the Beasties media query so it can be re-assigned on load.
*/
const CSP_MEDIA_ATTR = 'ngCspMedia';

Expand Down Expand Up @@ -58,8 +58,7 @@ const LINK_LOAD_SCRIPT_CONTENT = `
};

documentElement.addEventListener('load', listener, true);
})();
`.trim();
})();`;

export interface InlineCriticalCssProcessOptions {
outputPath: string;
Expand Down Expand Up @@ -98,14 +97,14 @@ interface PartialDocument {
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */

// We use Typescript declaration merging because `embedLinkedStylesheet` it's not declared in
// the `Critters` types which means that we can't call the `super` implementation.
interface CrittersBase {
// the `Beasties` types which means that we can't call the `super` implementation.
interface BeastiesBase {
embedLinkedStylesheet(link: PartialHTMLElement, document: PartialDocument): Promise<unknown>;
}
class CrittersBase extends Critters {}
class BeastiesBase extends Beasties {}
/* eslint-enable @typescript-eslint/no-unsafe-declaration-merging */

class CrittersExtended extends CrittersBase {
class BeastiesExtended extends BeastiesBase {
readonly warnings: string[] = [];
readonly errors: string[] = [];
private addedCspScriptsDocuments = new WeakSet<PartialDocument>();
Expand Down Expand Up @@ -143,7 +142,7 @@ class CrittersExtended extends CrittersBase {
}

/**
* Override of the Critters `embedLinkedStylesheet` method
* Override of the Beasties `embedLinkedStylesheet` method
* that makes it work with Angular's CSP APIs.
*/
override async embedLinkedStylesheet(
Expand All @@ -165,19 +164,19 @@ class CrittersExtended extends CrittersBase {
const cspNonce = this.findCspNonce(document);

if (cspNonce) {
const crittersMedia = link.getAttribute('onload')?.match(MEDIA_SET_HANDLER_PATTERN);
const beastiesMedia = link.getAttribute('onload')?.match(MEDIA_SET_HANDLER_PATTERN);

if (crittersMedia) {
// If there's a Critters-generated `onload` handler and the file has an Angular CSP nonce,
if (beastiesMedia) {
// If there's a Beasties-generated `onload` handler and the file has an Angular CSP nonce,
// we have to remove the handler, because it's incompatible with CSP. We save the value
// in a different attribute and we generate a script tag with the nonce that uses
// `addEventListener` to apply the media query instead.
link.removeAttribute('onload');
link.setAttribute(CSP_MEDIA_ATTR, crittersMedia[1]);
link.setAttribute(CSP_MEDIA_ATTR, beastiesMedia[1]);
this.conditionallyInsertCspLoadingScript(document, cspNonce, link);
}

// Ideally we would hook in at the time Critters inserts the `style` tags, but there isn't
// Ideally we would hook in at the time Beasties inserts the `style` tags, but there isn't
// a way of doing that at the moment so we fall back to doing it any time a `link` tag is
// inserted. We mitigate it by only iterating the direct children of the `<head>` which
// should be pretty shallow.
Expand All @@ -200,7 +199,7 @@ class CrittersExtended extends CrittersBase {
return this.documentNonces.get(document)!;
}

// HTML attribute are case-insensitive, but the parser used by Critters is case-sensitive.
// HTML attribute are case-insensitive, but the parser used by Beasties is case-sensitive.
const nonceElement = document.querySelector('[ngCspNonce], [ngcspnonce]');
const cspNonce =
nonceElement?.getAttribute('ngCspNonce') || nonceElement?.getAttribute('ngcspnonce') || null;
Expand Down Expand Up @@ -240,16 +239,16 @@ export class InlineCriticalCssProcessor {
html: string,
options: InlineCriticalCssProcessOptions,
): Promise<{ content: string; warnings: string[]; errors: string[] }> {
const critters = new CrittersExtended({ ...this.options, ...options });
const content = await critters.process(html);
const beasties = new BeastiesExtended({ ...this.options, ...options });
const content = await beasties.process(html);

return {
// Clean up value from value less attributes.
// This is caused because parse5 always requires attributes to have a string value.
// nomodule="" defer="" -> nomodule defer.
content: content.replace(/(\s(?:defer|nomodule))=""/g, '$1'),
errors: critters.errors,
warnings: critters.warnings,
errors: beasties.errors,
warnings: beasties.warnings,
};
}
}
6 changes: 3 additions & 3 deletions packages/angular/ssr/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ts_library(
module_name = "@angular/ssr",
tsconfig = "//:tsconfig-build-ng",
deps = [
"//packages/angular/ssr/third_party/critters:bundled_critters_lib",
"//packages/angular/ssr/third_party/beasties:bundled_beasties_lib",
"//packages/angular/ssr/tokens",
"@npm//@angular/common",
"@npm//@angular/core",
Expand All @@ -34,13 +34,13 @@ ng_package(
package_name = "@angular/ssr",
srcs = [
":package.json",
"//packages/angular/ssr/third_party/critters:bundled_critters_lib",
"//packages/angular/ssr/third_party/beasties:bundled_beasties_lib",
],
externals = [
"@angular/ssr",
"@angular/ssr/node",
"@angular/ssr/tokens",
"../../third_party/critters",
"../../third_party/beasties",
],
nested_packages = [
"//packages/angular/ssr/schematics:npm_package",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class CommonEngineInlineCriticalCssProcessor {
private readonly resourceCache = new Map<string, string>();

async process(html: string, outputPath: string | undefined): Promise<string> {
const critters = new InlineCriticalCssProcessor(async (path) => {
const beasties = new InlineCriticalCssProcessor(async (path) => {
let resourceContent = this.resourceCache.get(path);
if (resourceContent === undefined) {
resourceContent = await readFile(path, 'utf-8');
Expand All @@ -23,6 +23,6 @@ export class CommonEngineInlineCriticalCssProcessor {
return resourceContent;
}, outputPath);

return critters.process(html);
return beasties.process(html);
}
}
31 changes: 15 additions & 16 deletions packages/angular/ssr/src/utils/inline-critical-css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
* found in the LICENSE file at https://angular.dev/license
*/

import Critters from '../../third_party/critters';
import Beasties from '../../third_party/beasties';

/**
* Pattern used to extract the media query set by Critters in an `onload` handler.
* Pattern used to extract the media query set by Beasties in an `onload` handler.
*/
const MEDIA_SET_HANDLER_PATTERN = /^this\.media=["'](.*)["'];?$/;

/**
* Name of the attribute used to save the Critters media query so it can be re-assigned on load.
* Name of the attribute used to save the Beasties media query so it can be re-assigned on load.
*/
const CSP_MEDIA_ATTR = 'ngCspMedia';

Expand Down Expand Up @@ -57,8 +57,7 @@ const LINK_LOAD_SCRIPT_CONTENT = `
};

documentElement.addEventListener('load', listener, true);
})();
`.trim();
})();`;

/** Partial representation of an `HTMLElement`. */
interface PartialHTMLElement {
Expand Down Expand Up @@ -87,14 +86,14 @@ interface PartialDocument {
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */

// We use Typescript declaration merging because `embedLinkedStylesheet` it's not declared in
// the `Critters` types which means that we can't call the `super` implementation.
interface CrittersBase {
// the `Beasties` types which means that we can't call the `super` implementation.
interface BeastiesBase {
embedLinkedStylesheet(link: PartialHTMLElement, document: PartialDocument): Promise<unknown>;
}
class CrittersBase extends Critters {}
class BeastiesBase extends Beasties {}
/* eslint-enable @typescript-eslint/no-unsafe-declaration-merging */

export class InlineCriticalCssProcessor extends CrittersBase {
export class InlineCriticalCssProcessor extends BeastiesBase {
private addedCspScriptsDocuments = new WeakSet<PartialDocument>();
private documentNonces = new WeakMap<PartialDocument, string | null>();

Expand Down Expand Up @@ -126,7 +125,7 @@ export class InlineCriticalCssProcessor extends CrittersBase {
}

/**
* Override of the Critters `embedLinkedStylesheet` method
* Override of the Beasties `embedLinkedStylesheet` method
* that makes it work with Angular's CSP APIs.
*/
override async embedLinkedStylesheet(
Expand All @@ -148,19 +147,19 @@ export class InlineCriticalCssProcessor extends CrittersBase {
const cspNonce = this.findCspNonce(document);

if (cspNonce) {
const crittersMedia = link.getAttribute('onload')?.match(MEDIA_SET_HANDLER_PATTERN);
const beastiesMedia = link.getAttribute('onload')?.match(MEDIA_SET_HANDLER_PATTERN);

if (crittersMedia) {
// If there's a Critters-generated `onload` handler and the file has an Angular CSP nonce,
if (beastiesMedia) {
// If there's a Beasties-generated `onload` handler and the file has an Angular CSP nonce,
// we have to remove the handler, because it's incompatible with CSP. We save the value
// in a different attribute and we generate a script tag with the nonce that uses
// `addEventListener` to apply the media query instead.
link.removeAttribute('onload');
link.setAttribute(CSP_MEDIA_ATTR, crittersMedia[1]);
link.setAttribute(CSP_MEDIA_ATTR, beastiesMedia[1]);
this.conditionallyInsertCspLoadingScript(document, cspNonce, link);
}

// Ideally we would hook in at the time Critters inserts the `style` tags, but there isn't
// Ideally we would hook in at the time Beasties inserts the `style` tags, but there isn't
// a way of doing that at the moment so we fall back to doing it any time a `link` tag is
// inserted. We mitigate it by only iterating the direct children of the `<head>` which
// should be pretty shallow.
Expand All @@ -183,7 +182,7 @@ export class InlineCriticalCssProcessor extends CrittersBase {
return this.documentNonces.get(document)!;
}

// HTML attribute are case-insensitive, but the parser used by Critters is case-sensitive.
// HTML attribute are case-insensitive, but the parser used by Beasties is case-sensitive.
const nonceElement = document.querySelector('[ngCspNonce], [ngcspnonce]');
const cspNonce =
nonceElement?.getAttribute('ngCspNonce') || nonceElement?.getAttribute('ngcspnonce') || null;
Expand Down
16 changes: 8 additions & 8 deletions packages/angular/ssr/test/npm_package/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,38 @@ jasmine_node_test(
)

genrule(
name = "critters_license_file",
name = "beasties_license_file",
srcs = [
"//packages/angular/ssr:npm_package",
],
outs = [
"THIRD_PARTY_LICENSES.txt",
],
cmd = """
cp $(location //packages/angular/ssr:npm_package)/third_party/critters/THIRD_PARTY_LICENSES.txt $(location :THIRD_PARTY_LICENSES.txt)
cp $(location //packages/angular/ssr:npm_package)/third_party/beasties/THIRD_PARTY_LICENSES.txt $(location :THIRD_PARTY_LICENSES.txt)
""",
)

diff_test(
name = "critters_license_test",
name = "beasties_license_test",
failure_message = """

To accept the new golden file, execute:
yarn bazel run //packages/angular/ssr/test/npm_package:critters_license_test.accept
yarn bazel run //packages/angular/ssr/test/npm_package:beasties_license_test.accept
""",
file1 = ":THIRD_PARTY_LICENSES.txt.golden",
file2 = ":critters_license_file",
file2 = ":beasties_license_file",
)

write_file(
name = "critters_license_test.accept",
out = "critters_license_file_accept.sh",
name = "beasties_license_test.accept",
out = "beasties_license_file_accept.sh",
content =
[
"#!/usr/bin/env bash",
"cd ${BUILD_WORKSPACE_DIRECTORY}",
"yarn bazel build //packages/angular/ssr:npm_package",
"cp -fv dist/bin/packages/angular/ssr/npm_package/third_party/critters/THIRD_PARTY_LICENSES.txt packages/angular/ssr/test/npm_package/THIRD_PARTY_LICENSES.txt.golden",
"cp -fv dist/bin/packages/angular/ssr/npm_package/third_party/beasties/THIRD_PARTY_LICENSES.txt packages/angular/ssr/test/npm_package/THIRD_PARTY_LICENSES.txt.golden",
],
is_executable = True,
)
Loading
Loading