Skip to content
This repository was archived by the owner on Nov 22, 2024. It is now read-only.

Commit b41a3fb

Browse files
committed
feat: enable inlining of critical CSS optimizations
This is another feature that we mentioned in the Eliminate Render Blocking Requests RFC (angular/angular-cli#18730) **Prerendering** To enable critical css inlining for prerendering set the `inlineCritical` to true under the Browser Builder options. Example: ```json "configurations": { "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "optimization": { "styles": { "minify": true, "inlineCritical": true, } }, ``` **Express Engine** Update server.ts ```ts server.engine('html', ngExpressEngine({ bootstrap: AppServerModule, inlineCriticalCss: true, })); ``` **Hapi Engine** Update server.ts ```ts server.route({ method: 'GET', path: '/{path*}', handler: (req: Request) => ngHapiEngine({ bootstrap: AppServerModule, documentFilePath, publicPath: distFolder, inlineCriticalCss: true, req, }) }); ``` Inlining of critical CSS is turned off by default. In a future versions of the Angular CLI and Universal inline critical CSS will be enabled by default. Closes #974
1 parent 61409d1 commit b41a3fb

File tree

29 files changed

+336
-98
lines changed

29 files changed

+336
-98
lines changed

integration/express-engine-ivy-prerender/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
"build": "ng build --prod && ng run express-engine-ivy-prerender:server:production"
2121
},
2222
"private": true,
23+
"resolutions": {
24+
"@nguniversal/common": "file:../../dist/modules-dist/common"
25+
},
2326
"dependencies": {
2427
"@angular/animations": "file:../../node_modules/@angular/animations",
2528
"@angular/common": "file:../../node_modules/@angular/common",

integration/express-engine-ivy/e2e/src/app.e2e-spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ describe('Hello world E2E Tests', () => {
5252
const serverDiv = browser.driver.findElement(by.css('span.href-check'));
5353
expect(serverDiv.getText()).toMatch('//localhost:4200');
5454

55+
// Make sure there were no client side errors.
56+
verifyNoBrowserErrors();
57+
});
58+
59+
it('stylesheets should be configured to load asynchronously', async () => {
60+
// Load the page without waiting for Angular since it is not bootstrapped automatically.
61+
await browser.driver.get(browser.baseUrl);
62+
63+
// Test the contents from the server.
64+
const styleTag = browser.driver.findElement(by.css('link[rel="stylesheet"]'));
65+
expect(styleTag.getAttribute('media')).toMatch('all');
66+
5567
// Make sure there were no client side errors.
5668
verifyNoBrowserErrors();
5769
});

integration/express-engine-ivy/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
"build": "ng build --prod && ng run express-engine-ivy:server:production"
2020
},
2121
"private": true,
22+
"resolutions": {
23+
"@nguniversal/common": "file:../../dist/modules-dist/common"
24+
},
2225
"dependencies": {
2326
"@angular/animations": "file:../../node_modules/@angular/animations",
2427
"@angular/common": "file:../../node_modules/@angular/common",

integration/express-engine-ivy/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export function app(): express.Express {
1717
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
1818
server.engine('html', ngExpressEngine({
1919
bootstrap: AppServerModule,
20+
inlineCriticalCss: true,
2021
}));
2122

2223
server.set('view engine', 'html');
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
/* You can add global styles to this file, and also import other style files */
2+
.foo {
3+
color: red;
4+
}

integration/express-engine-ve/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
"build": "ng build --prod && ng run express-engine-ve:server:production"
2020
},
2121
"private": true,
22+
"resolutions": {
23+
"@nguniversal/common": "file:../../dist/modules-dist/common"
24+
},
2225
"dependencies": {
2326
"@angular/animations": "file:../../node_modules/@angular/animations",
2427
"@angular/common": "file:../../node_modules/@angular/common",

integration/hapi-engine-ivy/e2e/src/app.e2e-spec.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {browser, by, element} from 'protractor';
9+
import { browser, by, element } from 'protractor';
1010

11-
import {verifyNoBrowserErrors, waitForAppRootElement} from './util';
11+
import { verifyNoBrowserErrors, waitForAppRootElement } from './util';
1212

1313
describe('Hello world E2E Tests', () => {
1414
beforeAll(async () => {
@@ -54,5 +54,17 @@ describe('Hello world E2E Tests', () => {
5454

5555
// Make sure there were no client side errors.
5656
verifyNoBrowserErrors();
57-
});
57+
});
58+
59+
it('stylesheets should be configured to load asynchronously', async () => {
60+
// Load the page without waiting for Angular since it is not bootstrapped automatically.
61+
await browser.driver.get(browser.baseUrl);
62+
63+
// Test the contents from the server.
64+
const styleTag = browser.driver.findElement(by.css('link[rel="stylesheet"]'));
65+
expect(styleTag.getAttribute('media')).toMatch('all');
66+
67+
// Make sure there were no client side errors.
68+
verifyNoBrowserErrors();
69+
});
5870
});

integration/hapi-engine-ivy/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
"build": "ng build --prod && ng run hapi-engine-ivy:server:production"
2020
},
2121
"private": true,
22+
"resolutions": {
23+
"@nguniversal/common": "file:../../dist/modules-dist/common"
24+
},
2225
"dependencies": {
2326
"@angular/animations": "file:../../node_modules/@angular/animations",
2427
"@angular/common": "file:../../node_modules/@angular/common",

integration/hapi-engine-ivy/server.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ngHapiEngine } from '@nguniversal/hapi-engine';
44
import * as inert from '@hapi/inert';
55
import { Request, Server, ResponseToolkit } from '@hapi/hapi';
66
import { join } from 'path';
7-
import { readFileSync, existsSync } from 'fs';
7+
import { existsSync } from 'fs';
88

99
import { AppServerModule } from './src/main.server';
1010

@@ -21,15 +21,18 @@ export async function app() {
2121
},
2222
});
2323

24-
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index.html';
25-
const document = readFileSync(join(distFolder, indexHtml), 'utf-8');
24+
const documentFilePath = existsSync(join(distFolder, 'index.original.html'))
25+
? join(distFolder, 'index.original.html')
26+
: join(distFolder, 'index.html');
2627

2728
server.route({
2829
method: 'GET',
2930
path: '/{path*}',
3031
handler: (req: Request) => ngHapiEngine({
3132
bootstrap: AppServerModule,
32-
document,
33+
documentFilePath,
34+
publicPath: distFolder,
35+
inlineCriticalCss: true,
3336
req,
3437
})
3538
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
/* You can add global styles to this file, and also import other style files */
2+
.foo {
3+
color: red;
4+
}

0 commit comments

Comments
 (0)