Skip to content

feat(@angular-devkit/build-angular): enable font inlining optimizations #18926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 14, 2020
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"@types/babel__core": "7.1.10",
"@types/babel__template": "7.0.3",
"@types/browserslist": "^4.4.0",
"@types/cacache": "^12.0.1",
"@types/caniuse-lite": "^1.0.0",
"@types/copy-webpack-plugin": "^6.0.0",
"@types/cssnano": "^4.0.0",
Expand Down
20 changes: 20 additions & 0 deletions packages/angular/cli/lib/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,26 @@
"type": "boolean",
"description": "Enables optimization of the styles output.",
"default": true
},
"fonts": {
"description": "Enables optimization for fonts. This requires internet access.",
"default": true,
"oneOf": [
{
"type": "object",
"properties": {
"inline": {
"type": "boolean",
"description": "Reduce render blocking requests by inlining external fonts in the application's HTML index file. This requires internet access.",
"default": true
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
}
},
"additionalProperties": false
Expand Down
1 change: 1 addition & 0 deletions packages/angular_devkit/build_angular/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ ts_library(
"@npm//@types/babel__core",
"@npm//@types/babel__template",
"@npm//@types/browserslist",
"@npm//@types/cacache",
"@npm//@types/caniuse-lite",
"@npm//@types/copy-webpack-plugin",
"@npm//@types/cssnano",
Expand Down
11 changes: 9 additions & 2 deletions packages/angular_devkit/build_angular/src/browser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { copyAssets } from '../utils/copy-assets';
import { cachingDisabled } from '../utils/environment-options';
import { i18nInlineEmittedFiles } from '../utils/i18n-inlining';
import { I18nOptions } from '../utils/i18n-options';
import { getHtmlTransforms } from '../utils/index-file/transforms';
import {
IndexHtmlTransform,
writeIndexHtml,
Expand Down Expand Up @@ -280,6 +281,12 @@ export function buildWebpackBrowser(
switchMap(({ config, projectRoot, projectSourceRoot, i18n, buildBrowserFeatures, isDifferentialLoadingNeeded, target }) => {
const useBundleDownleveling = isDifferentialLoadingNeeded && !options.watch;
const startTime = Date.now();
const normalizedOptimization = normalizeOptimization(options.optimization);
const indexTransforms = getHtmlTransforms(
normalizedOptimization,
buildBrowserFeatures,
transforms.indexHtml,
);

return runWebpack(config, context, {
webpackFactory: require('webpack') as typeof webpack,
Expand Down Expand Up @@ -356,7 +363,7 @@ export function buildWebpackBrowser(
// Common options for all bundle process actions
const sourceMapOptions = normalizeSourceMaps(options.sourceMap || false);
const actionOptions: Partial<ProcessBundleOptions> = {
optimize: normalizeOptimization(options.optimization).scripts,
optimize: normalizedOptimization.scripts,
sourceMaps: sourceMapOptions.scripts,
hiddenSourceMaps: sourceMapOptions.hidden,
vendorSourceMaps: sourceMapOptions.vendor,
Expand Down Expand Up @@ -738,7 +745,7 @@ export function buildWebpackBrowser(
sri: options.subresourceIntegrity,
scripts: options.scripts,
styles: options.styles,
postTransform: transforms.indexHtml,
postTransforms: indexTransforms,
crossOrigin: options.crossOrigin,
// i18nLocale is used when Ivy is disabled
lang: locale || options.i18nLocale,
Expand Down
20 changes: 20 additions & 0 deletions packages/angular_devkit/build_angular/src/browser/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,26 @@
"type": "boolean",
"description": "Enables optimization of the styles output.",
"default": true
},
"fonts": {
"description": "Enables optimization for fonts. This requires internet access.",
"default": true,
"oneOf": [
{
"type": "object",
"properties": {
"inline": {
"type": "boolean",
"description": "Reduce render blocking requests by inlining external fonts in the application's HTML index file. This requires internet access.",
"default": true
}
},
"additionalProperties": false
},
{
"type": "boolean"
}
]
}
},
"additionalProperties": false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @license
* Copyright Google Inc. 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.io/license
*/
import { Architect } from '@angular-devkit/architect';
import { browserBuild, createArchitect, host } from '../../test-utils';

describe('Browser Builder font optimization', () => {
const target = { project: 'app', target: 'build' };
const overrides = {
optimization: {
styles: false,
fonts: true,
},
};

let architect: Architect;

beforeEach(async () => {
await host.initialize().toPromise();
architect = (await createArchitect(host.root())).architect;

host.replaceInFile(
'/src/index.html',
'<head>',
`<head><link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">`,
);
});

afterEach(async () => host.restore().toPromise());

it('works', async () => {
const { files } = await browserBuild(architect, host, target, overrides);
const html = await files['index.html'];
expect(html).not.toContain('href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"');
expect(html).toContain(`font-family: 'Roboto'`);
});

it('should not add woff when IE support is not needed', async () => {
const { files } = await browserBuild(architect, host, target, overrides);
const html = await files['index.html'];
expect(html).toContain(`format('woff2');`);
expect(html).not.toContain(`format('woff');`);
});

it('should add woff when IE support is needed', async () => {
host.writeMultipleFiles({
'.browserslistrc': 'IE 11',
});

const { files } = await browserBuild(architect, host, target, overrides);
const html = await files['index.html'];
expect(html).toContain(`format('woff2');`);
expect(html).toContain(`format('woff');`);
});

it('should remove comments and line breaks when styles optimization is true', async () => {
const { files } = await browserBuild(architect, host, target, {
optimization: {
styles: true,
fonts: true,
},
});
const html = await files['index.html'];
expect(html).not.toContain('/*');
expect(html).toContain(';font-style:normal;');
});

it('should not remove comments and line breaks when styles optimization is false', async () => {
const { files } = await browserBuild(architect, host, target, {
optimization: {
styles: false,
fonts: true,
},
});

const html = await files['index.html'];
expect(html).toContain('/*');
expect(html).toContain(' font-style: normal;\n');
});
});
12 changes: 9 additions & 3 deletions packages/angular_devkit/build_angular/src/dev-server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { BuildBrowserFeatures, normalizeOptimization } from '../utils';
import { findCachePath } from '../utils/cache-path';
import { checkPort } from '../utils/check-port';
import { I18nOptions } from '../utils/i18n-options';
import { getHtmlTransforms } from '../utils/index-file/transforms';
import { IndexHtmlTransform } from '../utils/index-file/write-index-html';
import { generateEntryPoints } from '../utils/package-chunk-sort';
import { createI18nPlugins } from '../utils/process-bundle';
Expand All @@ -40,7 +41,6 @@ import { normalizeExtraEntryPoints } from '../webpack/configs';
import { IndexHtmlWebpackPlugin } from '../webpack/plugins/index-html-webpack-plugin';
import { createWebpackLoggingCallback } from '../webpack/utils/stats';
import { Schema } from './schema';
const open = require('open');

export type DevServerBuilderOptions = Schema & json.JsonObject;

Expand Down Expand Up @@ -189,6 +189,8 @@ export function serveWebpackBrowser(
});
}

const normalizedOptimization = normalizeOptimization(browserOptions.optimization);

if (browserOptions.index) {
const { scripts = [], styles = [], baseHref, tsConfig } = browserOptions;
const { options: compilerOptions } = readTsconfig(tsConfig, context.workspaceRoot);
Expand All @@ -210,14 +212,17 @@ export function serveWebpackBrowser(
deployUrl: browserOptions.deployUrl,
sri: browserOptions.subresourceIntegrity,
noModuleEntrypoints: ['polyfills-es5'],
postTransform: transforms.indexHtml,
postTransforms: getHtmlTransforms(
normalizedOptimization,
buildBrowserFeatures,
transforms.indexHtml,
),
crossOrigin: browserOptions.crossOrigin,
lang: browserOptions.i18nLocale,
}),
);
}

const normalizedOptimization = normalizeOptimization(browserOptions.optimization);
if (normalizedOptimization.scripts || normalizedOptimization.styles) {
context.logger.error(tags.stripIndents`
****************************************************************************************
Expand Down Expand Up @@ -257,6 +262,7 @@ export function serveWebpackBrowser(
`);

if (options.open) {
const open = require('open');
open(serverAddress);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as cacache from 'cacache';
import { createHash } from 'crypto';
import * as fs from 'fs';
import { copyFile } from './copy-file';
import { allowMangle } from './environment-options';
import { CacheKey, ProcessBundleOptions, ProcessBundleResult } from './process-bundle';

const cacache = require('cacache');
const packageVersion = require('../../package.json').version;

export interface CacheEntry {
Expand Down Expand Up @@ -98,7 +98,8 @@ export class BundleActionCache {
}
cacheEntries.push({
path: entry.path,
size: entry.size,
// tslint:disable-next-line: no-any
size: (entry as any).size,
integrity: entry.metadata && entry.metadata.integrity,
});
} else {
Expand Down
Loading