arrow-rightgithublinkedinscroll-to-topzig-zag

How to remove unnecessary CSS in your Angular project

Last Updated On

Table of contents

Foreword

I'll be using purifyCSS for that purpose. It has plugins for the most popular task runners and module bundlers - Grunt, Gulp and Webpack. Even though, you might think that Webpack will be the tool of choice that is not necessarily true. Because of the fact that internal mechanics of Angular CLI are hidden, it might be a good idea to use a separate task runner like Gulp or Grunt to avoid ejection.

In on of mine projects I use Semantic IU, where full minified version is around 623 KB. After running purifyCSS, I've got the following output:

General approach

Under the hood purifyCSS reads content of file (HTML/JS/PHP/etc) and returns only theĀ used CSS. Saying that, in a case of Angular, we need to check all *.ts and *.html files for used CSS classes and remove the unused ones.

Gulp task

There are some dev dependencies that needed to be installed:

npm i -D gulp gulp-purifycss

In the root of Angular project create gulpfile.js and add the following code:

const gulp = require('gulp');
const purify = require('gulp-purifycss');

gulp.task('purifyCSS', () => {
  return gulp.src('./dist/styles.*.css')
    .pipe(
      purify(
        ['./src/app/**/*.ts', './src/app/**/*.html'],
        {
          info: true, // Outputs reduction information (like in the screenshot above)
          minify: true, // Minifies the files after reduction
          rejected: false, // Logs the CSS rules that were removed
          whitelist: ['*transition*', '*dimmer*'] // Ignored css classes
        }
      ),
    )
    .pipe(gulp.dest('./dist/'));
});

As the a final step, run Angular CLI build and created gulp task:

ng build --env=prod --prod=true --aot=true --sourcemap=false --output-hashing=all
gulp purifyCSS

As I already mentioned, in my specific case, purifyCSS was able to reduce the bundle by ~60.2%.

Grunt task

Since grunt is used as a primary build tool for many production codebases I think it's worth to implement the same functionality using that build tool.

As always, let's install required dependencies first:

npm i -D grunt glob grunt-purifycss

In the root of Angular project create gruntfile.js and add the following code:

var grunt = require('grunt');
var glob = require('glob');
grunt.loadNpmTasks('grunt-purifycss');

var cssSource = glob.sync('./dist/styles.*.css').toString();

grunt.initConfig({
  purifycss: {
    options: {
      info: true,
      minify: true,
      rejected: false, // Logs the CSS rules that were removed
      whitelist: ['*transition*', '*dimmer*']
    },
    target: {
      cwd: '.',
      src: ['./src/app/**/*.ts', './src/app/**/*.html'],
      css: [cssSource],
      dest: cssSource
    },
  },
});

Implementation notes: considering that Angular CLI dynamically adds generated hash to js files during the production build and grunt-purifycss plugin can't read/write dynamic file names we have to use separate variable cssSource for that purpose.

The final step will be run Angular build and grunt task in the pipeline:

ng build --env=prod --prod=true --aot=true --sourcemap=false --output-hashing=all
grunt purifycss

Side note about purifyCSS API

As you might notice, in both cases the same options object was used for gulp and grunt task. You might read about it more in the official documentation.

In my case, too much CSS was removed and that's a reason I needed to explicitly whitelist CSS classes that did contain transition and dimmer string.

Conclusion

In this example, I had a giant framework where I was using only small fraction of it which made it possible to decrease CSS size by 60.2%. However, in some other project, where CSS is written from scratch, this number should be really small, probably close zero. In any case, it's worth to try it as it doesn't require too much effort to implement this functionality.

In addition to that, this trick can also be applied to any type of framework, such as React, Vue, etc. or even non-framework Multipage Applications, CMSes as it builds on top of framework's internal build pipeline.