Skip to content

Commit e9897de

Browse files
alan-agius4mgechev
authored andcommitted
fix(@angular-devkit/build-angular): change css optimizer from clean-css with cssnano
Closes #16123 and closes #13854
1 parent 30df147 commit e9897de

File tree

8 files changed

+754
-109
lines changed

8 files changed

+754
-109
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@
9393
"@types/babel__core": "7.1.3",
9494
"@types/browserslist": "^4.4.0",
9595
"@types/caniuse-lite": "^1.0.0",
96-
"@types/clean-css": "^4.2.1",
9796
"@types/copy-webpack-plugin": "^5.0.0",
97+
"@types/cssnano": "^4.0.0",
9898
"@types/express": "^4.16.0",
9999
"@types/find-cache-dir": "^2.0.0",
100100
"@types/glob": "^7.0.0",

packages/angular_devkit/build_angular/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
"browserslist": "4.8.3",
2222
"cacache": "13.0.1",
2323
"caniuse-lite": "1.0.30001020",
24+
"cssnano": "4.1.10",
2425
"circular-dependency-plugin": "5.2.0",
25-
"clean-css": "4.2.1",
2626
"coverage-istanbul-loader": "2.0.3",
2727
"copy-webpack-plugin": "5.1.1",
2828
"core-js": "3.6.2",

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ import { BuildBrowserFeatures } from '../../../utils';
3131
import { findCachePath } from '../../../utils/cache-path';
3232
import { cachingDisabled, manglingDisabled } from '../../../utils/environment-options';
3333
import { BundleBudgetPlugin } from '../../plugins/bundle-budget';
34-
import { CleanCssWebpackPlugin } from '../../plugins/cleancss-webpack-plugin';
3534
import { NamedLazyChunksPlugin } from '../../plugins/named-chunks-plugin';
35+
import { OptimizeCssWebpackPlugin } from '../../plugins/optimize-css-webpack-plugin';
3636
import { ScriptsWebpackPlugin } from '../../plugins/scripts-webpack-plugin';
3737
import { WebpackRollupLoader } from '../../plugins/webpack';
3838
import { findAllNodeModules, findUp } from '../../utilities/find-up';
@@ -363,7 +363,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
363363
const extraMinimizers = [];
364364
if (stylesOptimization) {
365365
extraMinimizers.push(
366-
new CleanCssWebpackPlugin({
366+
new OptimizeCssWebpackPlugin({
367367
sourceMap: stylesSourceMap,
368368
// component styles retain their original file name
369369
test: file => /\.(?:css|scss|sass|less|styl)$/.test(file),

packages/angular_devkit/build_angular/src/angular-cli-files/plugins/cleancss-webpack-plugin.ts renamed to packages/angular_devkit/build_angular/src/angular-cli-files/plugins/optimize-css-webpack-plugin.ts

+32-43
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import * as CleanCSS from 'clean-css';
8+
import * as cssNano from 'cssnano';
9+
import { ProcessOptions, Result } from 'postcss';
910
import { Compiler, compilation } from 'webpack';
1011
import { RawSource, Source, SourceMapSource } from 'webpack-sources';
1112

12-
export interface CleanCssWebpackPluginOptions {
13+
export interface OptimizeCssWebpackPluginOptions {
1314
sourceMap: boolean;
1415
test: (file: string) => boolean;
1516
}
@@ -22,19 +23,19 @@ function hook(
2223
) => Promise<void | void[]>,
2324
) {
2425
compiler.hooks.compilation.tap(
25-
'cleancss-webpack-plugin',
26+
'optimize-css-webpack-plugin',
2627
(compilation: compilation.Compilation) => {
27-
compilation.hooks.optimizeChunkAssets.tapPromise('cleancss-webpack-plugin', chunks =>
28+
compilation.hooks.optimizeChunkAssets.tapPromise('optimize-css-webpack-plugin', chunks =>
2829
action(compilation, chunks),
2930
);
3031
},
3132
);
3233
}
3334

34-
export class CleanCssWebpackPlugin {
35-
private readonly _options: CleanCssWebpackPluginOptions;
35+
export class OptimizeCssWebpackPlugin {
36+
private readonly _options: OptimizeCssWebpackPluginOptions;
3637

37-
constructor(options: Partial<CleanCssWebpackPluginOptions>) {
38+
constructor(options: Partial<OptimizeCssWebpackPluginOptions>) {
3839
this._options = {
3940
sourceMap: false,
4041
test: file => file.endsWith('.css'),
@@ -44,21 +45,6 @@ export class CleanCssWebpackPlugin {
4445

4546
apply(compiler: Compiler): void {
4647
hook(compiler, (compilation: compilation.Compilation, chunks: compilation.Chunk[]) => {
47-
const cleancss = new CleanCSS({
48-
compatibility: 'ie9',
49-
level: {
50-
2: {
51-
skipProperties: [
52-
'transition', // Fixes #12408
53-
'font', // Fixes #9648
54-
],
55-
},
56-
},
57-
inline: false,
58-
returnPromise: true,
59-
sourceMap: this._options.sourceMap,
60-
});
61-
6248
const files: string[] = [...compilation.additionalChunkAssets];
6349

6450
chunks.forEach(chunk => {
@@ -90,37 +76,40 @@ export class CleanCssWebpackPlugin {
9076
return;
9177
}
9278

93-
const output = await cleancss.minify(content, map);
94-
95-
let hasWarnings = false;
96-
if (output.warnings && output.warnings.length > 0) {
97-
compilation.warnings.push(...output.warnings);
98-
hasWarnings = true;
99-
}
100-
101-
if (output.errors && output.errors.length > 0) {
102-
output.errors.forEach((error: string) => compilation.errors.push(new Error(error)));
103-
104-
return;
105-
}
106-
107-
// generally means invalid syntax so bail
108-
if (hasWarnings && output.stats.minifiedSize === 0) {
109-
return;
79+
const cssNanoOptions: cssNano.CssNanoOptions = {
80+
preset: 'default',
81+
};
82+
83+
const postCssOptions: ProcessOptions = {
84+
from: file,
85+
map: map && { annotation: false, prev: map },
86+
};
87+
88+
const output = await new Promise<Result>((resolve, reject) => {
89+
// the last parameter is not in the typings
90+
// tslint:disable-next-line: no-any
91+
(cssNano.process as any)(content, postCssOptions, cssNanoOptions)
92+
.then(resolve)
93+
.catch(reject);
94+
});
95+
96+
const warnings = output.warnings();
97+
if (warnings.length) {
98+
compilation.warnings.push(...warnings.map(({ text }) => text));
11099
}
111100

112101
let newSource;
113-
if (output.sourceMap) {
102+
if (output.map) {
114103
newSource = new SourceMapSource(
115-
output.styles,
104+
output.css,
116105
file,
117106
// tslint:disable-next-line: no-any
118-
output.sourceMap.toString() as any,
107+
output.map.toString() as any,
119108
content,
120109
map,
121110
);
122111
} else {
123-
newSource = new RawSource(output.styles);
112+
newSource = new RawSource(output.css);
124113
}
125114

126115
compilation.assets[file] = newSource;

packages/angular_devkit/build_angular/src/angular-cli-files/plugins/webpack.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
// Exports the webpack plugins we use internally.
1010
export { AnyComponentStyleBudgetChecker } from './any-component-style-budget-checker';
11-
export { CleanCssWebpackPlugin, CleanCssWebpackPluginOptions } from './cleancss-webpack-plugin';
11+
export { OptimizeCssWebpackPlugin, OptimizeCssWebpackPluginOptions } from './optimize-css-webpack-plugin';
1212
export { BundleBudgetPlugin, BundleBudgetPluginOptions } from './bundle-budget';
1313
export { ScriptsWebpackPlugin, ScriptsWebpackPluginOptions } from './scripts-webpack-plugin';
1414
export { SuppressExtractedTextChunksWebpackPlugin } from './suppress-entry-chunks-webpack-plugin';

packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts

-24
Original file line numberDiff line numberDiff line change
@@ -40,30 +40,6 @@ describe('Browser Builder AOT', () => {
4040
await run.stop();
4141
});
4242

43-
it('shows warnings for component styles', async () => {
44-
const overrides = {
45-
aot: true,
46-
optimization: true,
47-
};
48-
49-
host.writeMultipleFiles({
50-
'src/app/app.component.css': `
51-
.foo { color: white; padding: 1px; };
52-
.buz { color: white; padding: 2px; };
53-
`,
54-
});
55-
56-
const logger = new logging.Logger('');
57-
const logs: string[] = [];
58-
logger.subscribe(e => logs.push(e.message));
59-
60-
const run = await architect.scheduleTarget(targetSpec, overrides, { logger });
61-
const output = await run.result;
62-
expect(output.success).toBe(true);
63-
expect(logs.join()).toContain('WARNING in Invalid selector');
64-
await run.stop();
65-
});
66-
6743
it('shows error when component stylesheet contains SCSS syntax error', async () => {
6844
const overrides = {
6945
aot: true,

packages/angular_devkit/build_angular/test/browser/styles_spec_large.ts

-19
Original file line numberDiff line numberDiff line change
@@ -585,23 +585,4 @@ describe('Browser Builder styles', () => {
585585
const { output } = await browserBuild(architect, host, target, overrides);
586586
expect(output.success).toBe(true);
587587
});
588-
589-
it('supports font names with spaces', async () => {
590-
host.writeMultipleFiles({
591-
'src/styles.css': `
592-
body {
593-
font: 10px "Font Awesome";
594-
}
595-
`,
596-
});
597-
598-
const overrides = { extractCss: true, optimization: true };
599-
const logger = new logging.Logger('font-name-spaces');
600-
const logs: string[] = [];
601-
logger.subscribe(e => logs.push(e.message));
602-
603-
const { output } = await browserBuild(architect, host, target, overrides, { logger });
604-
expect(output.success).toBe(true);
605-
expect(logs.join()).not.toContain('WARNING in Invalid font values ');
606-
});
607588
});

0 commit comments

Comments
 (0)