Skip to content

Commit

Permalink
refactor(@angular/ssr): bundle Critters
Browse files Browse the repository at this point in the history
This commit bundles the Critters library to ensure compatibility with Nodeless environments. Additionally, all licenses for bundled libraries, including Critters, are now included in the package. This helps maintain compliance with open-source license requirements.
  • Loading branch information
alan-agius4 committed Aug 22, 2024
1 parent 7ea85e9 commit ec3823b
Show file tree
Hide file tree
Showing 15 changed files with 620 additions and 292 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@
"tslib": "2.6.3",
"typescript": "5.5.4",
"undici": "6.19.8",
"unenv": "^1.10.0",
"verdaccio": "5.32.1",
"verdaccio-auth-memory": "^10.0.0",
"vite": "5.4.2",
Expand Down
1 change: 1 addition & 0 deletions packages/angular/build/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ ts_library(
"@npm//browserslist",
"@npm//critters",
"@npm//esbuild",
"@npm//esbuild-wasm",
"@npm//fast-glob",
"@npm//https-proxy-agent",
"@npm//listr2",
Expand Down
19 changes: 19 additions & 0 deletions packages/angular/build/src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

// The `bundled_critters` 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.
//
// This change aims to resolve esbuild types correctly and maintain consistency
// in the Bazel build process.

declare module 'esbuild' {
export * from 'esbuild-wasm';
}
11 changes: 9 additions & 2 deletions packages/angular/ssr/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ ts_library(
),
module_name = "@angular/ssr",
deps = [
"//packages/angular/ssr/third_party/critters:bundled_critters_lib",
"@npm//@angular/common",
"@npm//@angular/core",
"@npm//@angular/platform-server",
"@npm//@angular/router",
"@npm//@types/node",
"@npm//critters",
],
)

Expand All @@ -32,8 +32,15 @@ ng_package(
package_name = "@angular/ssr",
srcs = [
":package.json",
"//packages/angular/ssr/third_party/critters:bundled_critters_lib",
],
externals = [
"express",
"../../third_party/critters",
],
nested_packages = [
"//packages/angular/ssr/schematics:npm_package",
],
nested_packages = ["//packages/angular/ssr/schematics:npm_package"],
tags = ["release-package"],
deps = [
":ssr",
Expand Down
1 change: 0 additions & 1 deletion packages/angular/ssr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"save": "dependencies"
},
"dependencies": {
"critters": "0.0.24",
"tslib": "^2.3.0"
},
"peerDependencies": {
Expand Down
42 changes: 38 additions & 4 deletions packages/angular/ssr/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Hooks } from './hooks';
import { getAngularAppManifest } from './manifest';
import { ServerRouter } from './routes/router';
import { REQUEST, REQUEST_CONTEXT, RESPONSE_INIT } from './tokens';
import { InlineCriticalCssProcessor } from './utils/inline-critical-css';
import { renderAngular } from './utils/ng';

/**
Expand Down Expand Up @@ -52,6 +53,11 @@ export class AngularServerApp {
*/
private router: ServerRouter | undefined;

/**
* The `inlineCriticalCssProcessor` is responsible for handling critical CSS inlining.
*/
private inlineCriticalCssProcessor: InlineCriticalCssProcessor | undefined;

/**
* Renders a response for the given HTTP request using the server application.
*
Expand Down Expand Up @@ -177,10 +183,38 @@ export class AngularServerApp {
html = await hooks.run('html:transform:pre', { html });
}

return new Response(
await renderAngular(html, manifest.bootstrap(), new URL(request.url), platformProviders),
responseInit,
);
html = await renderAngular(html, manifest.bootstrap(), new URL(request.url), platformProviders);

if (manifest.inlineCriticalCss) {
// Optionally inline critical CSS.
const inlineCriticalCssProcessor = this.getOrCreateInlineCssProcessor();
html = await inlineCriticalCssProcessor.process(html);
}

return new Response(html, responseInit);
}

/**
* Retrieves or creates the inline critical CSS processor.
* If one does not exist, it initializes a new instance.
*
* @returns The inline critical CSS processor instance.
*/
private getOrCreateInlineCssProcessor(): InlineCriticalCssProcessor {
let inlineCriticalCssProcessor = this.inlineCriticalCssProcessor;

if (!inlineCriticalCssProcessor) {
inlineCriticalCssProcessor = new InlineCriticalCssProcessor();
inlineCriticalCssProcessor.readFile = (path: string) => {
const fileName = path.split('/').pop() ?? path;

return this.assets.getServerAsset(fileName);
};

this.inlineCriticalCssProcessor = inlineCriticalCssProcessor;
}

return inlineCriticalCssProcessor;
}
}

Expand Down
29 changes: 9 additions & 20 deletions packages/angular/ssr/src/common-engine/common-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { renderApplication, renderModule, ɵSERVER_CONTEXT } from '@angular/plat
import * as fs from 'node:fs';
import { dirname, join, normalize, resolve } from 'node:path';
import { URL } from 'node:url';
import { InlineCriticalCssProcessor, InlineCriticalCssResult } from './inline-css-processor';
import { CommonEngineInlineCriticalCssProcessor } from './inline-css-processor';
import {
noopRunMethodAndMeasurePerf,
printPerformanceLogs,
Expand Down Expand Up @@ -55,14 +55,10 @@ export interface CommonEngineRenderOptions {

export class CommonEngine {
private readonly templateCache = new Map<string, string>();
private readonly inlineCriticalCssProcessor: InlineCriticalCssProcessor;
private readonly inlineCriticalCssProcessor = new CommonEngineInlineCriticalCssProcessor();
private readonly pageIsSSG = new Map<string, boolean>();

constructor(private options?: CommonEngineOptions) {
this.inlineCriticalCssProcessor = new InlineCriticalCssProcessor({
minify: false,
});
}
constructor(private options?: CommonEngineOptions) {}

/**
* Render an HTML document for a specific URL with specified
Expand All @@ -81,17 +77,12 @@ export class CommonEngine {
html = await runMethod('Render Page', () => this.renderApplication(opts));

if (opts.inlineCriticalCss !== false) {
const { content, errors, warnings } = await runMethod('Inline Critical CSS', () =>
const content = await runMethod('Inline Critical CSS', () =>
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.inlineCriticalCss(html!, opts),
);

html = content;

// eslint-disable-next-line no-console
warnings?.forEach((m) => console.warn(m));
// eslint-disable-next-line no-console
errors?.forEach((m) => console.error(m));
}
}

Expand All @@ -102,13 +93,11 @@ export class CommonEngine {
return html;
}

private inlineCriticalCss(
html: string,
opts: CommonEngineRenderOptions,
): Promise<InlineCriticalCssResult> {
return this.inlineCriticalCssProcessor.process(html, {
outputPath: opts.publicPath ?? (opts.documentFilePath ? dirname(opts.documentFilePath) : ''),
});
private inlineCriticalCss(html: string, opts: CommonEngineRenderOptions): Promise<string> {
const outputPath =
opts.publicPath ?? (opts.documentFilePath ? dirname(opts.documentFilePath) : '');

return this.inlineCriticalCssProcessor.process(html, outputPath);
}

private async retrieveSSGPage(opts: CommonEngineRenderOptions): Promise<string | undefined> {
Expand Down
Loading

0 comments on commit ec3823b

Please sign in to comment.