I created the component and added a CSS file to it, let's say our developers write a lot of suboptimal code and forget to clean it up:

import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [
'./app.component.css',
'./materialize.css'
]
})
export class AppComponent {
title = 'app';
}
$ ng build --prod
chunk {0} polyfills.f20484b2fa4642e0dca8.bundle.js (polyfills) 59.4 kB [initial] [rendered]
chunk {1} main.9414139e8f04fe910b03.bundle.js (main) 351 kB [initial] [rendered]
chunk {2} styles.9c0ad738f18adc3d19ed.bundle.css (styles) 79 bytes [initial] [rendered]
chunk {3} inline.7d41986913723cd10387.bundle.js (inline) 1.45 kB [entry] [rendered]
PS: main.js 351Кb? Why? I usage one component and I expect that the collector will do everything for me as it should (removed unused CSS code).

If I were using assets, I probably would not need to delete the unused code. And so it turns out, not only that I was generated a huge CSS, so for him also added attributes for emulating Shadow DOM.

Why do not you set config up the .angular-cli.json for remove unused css?
You use webpack, but you do not use steep plugins (and loaders):
plugin: https://github.com/purifycss/purifycss (8k stars)
loader: https://github.com/webpack-contrib/purifycss-webpack
@IgorMinar Your team is chasing the decrease in the size of the bundle, but in the end, some novice developers may not be aware of such moments and do not believe that their applications may decrease in size.
$ ng -v
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ â–³ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 1.6.6
Node: 8.9.1
OS: win32 x64
Angular: 5.2.5
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router
@angular/cli: 1.6.6
@angular-devkit/build-optimizer: 0.0.42
@angular-devkit/core: 0.0.29
@angular-devkit/schematics: 0.0.52
@ngtools/json-schema: 1.1.0
@ngtools/webpack: 1.9.6
@schematics/angular: 0.1.17
typescript: 2.5.3
webpack: 3.10.0
https://github.com/splincode/css-unused-angular
https://stackblitz.com/github/splincode/css-unused-angular
In Angular 6, many people want to see the possibility to collect applications with the flag for removing unused CSS, or at least warnings (unused css, js, ..) so that the compiler can output.
Its an interesting feature that could be added. The question is how easy would it be to integrate with angular and dynamic addition/removal of classes.
@splincode did you use purifycss on your example application and saw any results?
I started working with angular from the second version, but I did not use the CLI. I used a webpack-starter. At Angular 5 could only go with Angular CLI.
But in our projects I used the purification of CSS directly without loaders. I pointed out that he analyzed the entire src/app/*.html directory with other files (+ jquery plugins or ts directives).
But we needed to use the encapsulation parameters (ViewEncapsulation.None), because angular generated attributes (for emulated shadow dom)
@jotatoledo @IgorMinar We were able to destroy unused styles at the component level
import * as path from 'path';
import * as ngcWebpack from 'ngc-webpack';
import * as fs from 'fs';
const cssDependants = {};
function extractCssDependants(componentPath, source) {
if (source.includes('@Component')) {
const decorator = source.match(/@Component\(([\s\S]*)\)/)[1].split('\n').join('');
const templateUrl = decorator.match(/templateUrl: '(.*?)'/)[1];
const styleUrls = decorator.match(/styleUrls: \[(.*?)\]/)[1].split(',').map(x => x.trim().slice(1, -1));
const templatePath = path.resolve(path.dirname(componentPath), templateUrl);
const stylePaths = styleUrls.map(x => path.resolve(path.dirname(componentPath), x));
stylePaths.forEach((v) => {
if (!cssDependants[v]) { cssDependants[v] = []; }
if (templateUrl) { cssDependants[v].push(templatePath); }
cssDependants[v].push(componentPath);
});
}
return source;
}
function purifyCSS(cssPath, source) {
if (cssDependants[cssPath]) {
const files = cssDependants[cssPath]
.map(f => fs.readFileSync(f, 'utf8'))
.reduce((a, b) => a + b);
console.log(cssPath);
return purify(files, beautify(source), {minify: true, info: true});
}
return source;
}
export function purifyIzolated(config: webpack.Configuration, options: WebpackConfigOptions<BuildOptions>) {
if (options.buildOptions.environment === 'prod' && options.buildOptions.aot) {
const root = path.resolve(options.projectRoot, options.appConfig.root);
const tsConfigPath = path.resolve(root, options.appConfig.tsconfig);
const mainPath = path.resolve(root, options.appConfig.main);
const mayBeComponentRegexp = new RegExp(`^${root}.*ts$`);
const ngc = new ngcWebpack.NgcWebpackPlugin({
AOT: options.buildOptions.aot,
tsConfigPath: tsConfigPath,
mainPath: mainPath,
readFileTransformer: {
predicate: mayBeComponentRegexp,
transform: extractCssDependants
},
resourceTransformer: purifyCSS
});
const compilerPluginIndex = config.plugins.findIndex(x => x.constructor.name === 'AngularCompilerPlugin');
config.plugins[compilerPluginIndex] = ngc;
}
return config;
}
https://github.com/Angular-RU/angular-cli-webpack/issues/9
monkey patching angular cli: https://github.com/Angular-RU/angular-cli-webpack
What about this must have feature? I completly agree. We need process to remove unused css even when it comes from styles.css file
Thanks @splincode
Agree with the part that software should check all that for us, but I'd argue that ideally we'd ALSO get warnings from the IDE about unused CSS (SASS, and even js), even before build time, so that we can clean up our codebase and improve maintainability. Just throwing it out there, although probably out of scope for angular-cli and even angular. Removing CSS during build is good, but that only benefits users.
Some modern CSS Frameworks such as TailwindCSS are tying on the use of a tool to remove unused CSS. The only option for that is to eject the app, but that could be avoided if such feature is added.
Need this feature!
Developers can manipulate elements directly using JavaScript which makes the automatic style removal in the general case impossible.
If we release such feature we'll break too many applications. The solution that @splincode shared will work in some cases when the ViewEncapsulation.None and no dynamic style manipulation.
Let's suppose we have:
@Component({
selector: 'my-app',
template: '<div class="foo"></div>',
styles: [`
.foo {
color: red;
}
.bar {
text-align: center;
}
`]
})
class AppComponent {
ngOnInit() {
fetch('https://example.com/styles.json')
.then(r => r.json())
.then(s => document.querySelector('.foo').classList.add(s.className));
}
}
If the content of styles.json is: { "className": "bar" }, there's no way we can know ahead of time that the .bar style is used, and we'd have dropped it, which will break the application.
The best you can do is use something like codelyzer to statically analyze your app and give suggestions.
I agree with @mgechev's statement; the very nature of CSS and JavaScript makes this impossible to fix for the general case.
That being said, there is three avenue you can use as a workaround to the default behavior:
@mgechev The ratio of css used dynamically, is way too low with respect to the static css.
The Good solution:
We can analyze the code to detect any style manipulation, then warn the developer to perform manual check on corresponding lines of code, so they can take responsibility.
The Better solution:
I think there is more value in automating the removal of "unused css". In case manual style manipulation is used, show the developer where this is happening in their project. Then there might be a place in the configuration to "white list" those styles and prevent removing them from final bundle.
Minimizing css is a great way to achieve small angular apps and translate better load times.
At least make it a setting inside angular.json
That's what I prototyped here http://codelyzer.com/rules/no-unused-css/.
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
That's what I prototyped here http://codelyzer.com/rules/no-unused-css/.