setup Font Awesome in Angular 2 with webpack

Font Awesome in Angular 2 with webpack Setup Guide

This is a guide for setting up Font Awesome in Angular 2 with webpack.

Although this guide is written at the time of Angular 2, it should also work for Angular 4 and future versions of Angular, according to the official Angular branding guideline.

Font Awesome is a hugely popular package for icons. Back in the days, you could just include css and font files in index.html. However, with so many new technologies, it has become increasing hard to integrate 3rd party library into our web app project.

Of course we can still use a CDN to serve static resources, but that’s not helpful when we need to test locally. It also adds external dependency which we have no control over. Hence, we need an idiomatic way to use Font Awesome in Angular 2 with webpack.

This guide is based on a fantastic gist for font awesome with webpack and assume that you have followed the official guide on Angular 2 with webpack.

Non-idiomatic Approaches (Not Recommended)

A simple way to add font awesome in Angular 2 is to include font-awesome.css in index.html. But that it is not idiomatic to Angular 2 as you are introducing global style sheets outside the Angular 2 framework.

There are also 3rd party wrappers for font-awesome but using them carries unnecessary risks as they are not officially supported by either webpack or font-awesome.

Idiomatic Approach, in 3 steps

Instead, I will describe a way to add font-awesome as a vendor library using only the official tools and packages. The complication is that font awesome includes many font files that are not typically included in an npm package, so we need to handle them properly in webpack configurations.

Step 1 – Install necessary npm packages:

  • official font-awesome on npm (yes, you can find everything on npm)

  • official url loader by webpack to load the font files that come with font awesome

Step 2 – Edit the webpack config file webpack.common.js:

The config file specifies how we are going to load the various static resource files that come with font awesome.

In particular we modify the original loader for various font files, woff, eot, svg, etc:

Original config:

We replace this with a bunch of new tests and loaders:

New config:

Webpack 2’s Mandatory -loader Suffix

Note that we use url-loader and file-loader instead of the usual url and file shorthand in the webpack config above. Otherwise, you will get an error:

The reason for the change is webpack 2’s new requirements for loaders, which disallows shorthand: https://github.com/webpack/url-loader/pull/55

Now we have all the necessary setup, all that’s left is to formally introduce font awesome into our project.

Step 3- Add Dependency Into Angular 2

The last step is to open vendor.ts and add the dependency here:

That’s it. Webpack will take care of the rest from here. Definitely more complicated than including the css file directly into html (which won’t work in production environment due to folder hierarchy issues), but not super complicated or hackish.

13 comments

  1. Hello, I think is better to use :

    import ‘font-awesome-sass-loader’; in vendors.ts

    And add package :

    npm install font-awesome-sass-loader –save

    Because, if you wanted to use ‘Bootstrap 4’, is not possible with your method.

    A beautiful error will appear with your solution.

  2. Thanks for taking the time to write this great and easy to understand post.
    I’m getting an error, do you have a clue what I should do?

    \loader-runner\lib\loadLoader.js:35
    throw new Error(“Module ‘” + loader.path + “‘ is not a loader (must have normal or pitch function)”);
    ^
    Error: Module ‘C:\Users\niceg\work\backoffice-site\node_modules\url\url.js’ is not a loader (must have normal or pitch function)
    at loadLoader (C:\Users\niceg\work\backoffice-site\node_modules\loader-runner\lib\loadLoader.js:35:10)
    at iteratePitchingLoaders (C:\Users\niceg\work\backoffice-site\node_modules\loader-runner\lib\LoaderRunner.js:164:2)
    at runLoaders (C:\Users\niceg\work\backoffice-site\node_modules\loader-runner\lib\LoaderRunner.js:357:2)
    at NormalModule.doBuild (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModule.js:131:2)
    at NormalModule.build (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModule.js:179:15)
    at Compilation.buildModule (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\Compilation.js:127:9)
    at C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\Compilation.js:306:10
    at C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleFactory.js:74:13
    at C:\Users\niceg\work\backoffice-site\node_modules\tapable\lib\Tapable.js:131:11
    at NormalModuleFactory. (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleReplacementPlugin.js:37:11)
    at C:\Users\niceg\work\backoffice-site\node_modules\tapable\lib\Tapable.js:133:14
    at NormalModuleFactory. (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleReplacementPlugin.js:37:11)
    at C:\Users\niceg\work\backoffice-site\node_modules\tapable\lib\Tapable.js:133:14
    at NormalModuleFactory. (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleReplacementPlugin.js:37:11)
    at C:\Users\niceg\work\backoffice-site\node_modules\tapable\lib\Tapable.js:133:14
    at NormalModuleFactory. (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleReplacementPlugin.js:37:11)
    at C:\Users\niceg\work\backoffice-site\node_modules\tapable\lib\Tapable.js:133:14
    at NormalModuleFactory. (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleReplacementPlugin.js:37:11)
    at NormalModuleFactory.applyPluginsAsyncWaterfall (C:\Users\niceg\work\backoffice-site\node_modules\tapable\lib\Tapable.js:135:13)
    at onDoneResolving (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleFactory.js:49:11)
    at onDoneResolving (C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleFactory.js:165:6)
    at C:\Users\niceg\work\backoffice-site\node_modules\webpack\lib\NormalModuleFactory.js:161:6

  3. This doesn’t work for me. I get error:
    ERROR in ./vendor.ts
    Module not found: Error: Can’t resolve ‘css?sourceMap’ in ‘C:\project\src’
    @ ./vendor.ts 11:0-44

    My common.config.js for webpack:

    module: {
    loaders: [
    {
    test: /\.ts$/,
    loaders: [‘awesome-typescript-loader?configFileName=’ + root(‘src/tsconfig.json’), ‘angular2-template-loader’]
    },
    {
    test: /\.html$/,
    loader: ‘html-loader’
    },
    {
    test: /\.scss$/,
    loaders: [‘style-loader’, ‘css-loader’, ‘resolve-url-loader’, ‘sass-loader?sourceMap’]
    },
    {
    test: /\.css$/,
    exclude: root(‘src’),
    loader: ExtractTextPlugin.extract({ fallback: ‘style’, use: ‘css?sourceMap’ })
    },
    {
    test: /\.(png|jpe?g|gif|ico)$/,
    loader: ‘file-loader?name=/assets/[name].[hash].[ext]’
    },
    {
    test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
    loader: ‘url-loader?limit=10000&mimetype=application/font-woff’
    },
    {
    test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
    loader: ‘url-loader?limit=10000&mimetype=application/font-woff’
    },
    {
    test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
    loader: ‘url-loader?limit=10000&mimetype=application/octet-stream’
    },
    {
    test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
    loader: ‘file-loader’
    },
    {
    test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
    loader: ‘url-loader?limit=10000&mimetype=image/svg+xml’
    },
    {
    test: /\.css$/,
    include: root(‘src’),
    loader: ‘raw-loader’
    },
    {
    test: /\.css$/,
    include: root(‘src/styles’),
    loader: extractCSS.extract([‘css-loader’])
    }
    ]
    }

    What am I doing wrong?

    1. Alternatively, it might just because webpack updated css loader’s name from css to css-loader, try changing that.

  4. Thanks for the instructions – I got past some pesky webpack errors.
    I am getting, ‘ Unexpected character ‘@” on the @font-face declaration, now – is that a css or sass file loader problem? I receive it no matter which I use.

Leave a Reply