Search code examples
angularwebpackwebpack-style-loader

Angular2/Webpack: how to load fonts that are imported inside css files?


I'm using Angular2 beta.15 and webpack 1.12.14.

I have one .css and one .scss file in app.component.ts as global patterns like this.

  @Component({
    selector: 'my-app',
    templateUrl: 'app/app.component.html',
    styles: [
      require('../stylesheets/css/main.min.css'),
      require('../sass/example.scss')
    ],
    encapsulation: ViewEncapsulation.None,
  })

And, inside .css file, some fonts are imported like below,

@font-face {
    font-family: 'Helvetica Neue';
    src: url(fonts/light/helvetica-neue-light.eot) format("eot"), 
         url(fonts/light/helvetica-neue-light.woff2) format("woff2"),   
         url(fonts/light/helvetica-neue-light.woff) format("woff"), 
         url(fonts/light/helvetica-neue-light.ttf) format("truetype");
    font-weight: 300;
    font-style: normal
}

In webpack.config.js, I have loaders for .css, .scss, and fonts like below

  {
    test: /\.scss$/,
    exclude: /node_modules/,
    loaders: ['raw-loader', 'sass-loader'] // sass-loader not scss-loader
  },
  {
       test: /.(png|woff(2)?|eot|ttf|svg)(\?[a-z0-9=\.]+)?$/,
       loader: 'url-loader'
  },
  {
    test: /\.css$/,
    loaders: ['style', 'css']
  },

When I ran webpack -display-error-details, there is no error at all, but when I launched the server to run my app, I got error as below

EXCEPTION: Error during instantiation of Token Promise<ComponentRef>!.
ORIGINAL EXCEPTION: Expected 'styles' to be an array of string

If I change the css loader to

  {
    test: /\.css$/,
    loader: 'url-loader'  //or use 'raw-loader'
  },

those exceptions disappeared and the app was start, but I got some 404 requests error for those fonts in browser's console, they're not loaded at all. So, could you give me some pointers? I suspect something wrong in my loader settings.


Solution

  • When you chain multiple loaders together, the order of their actions are completed from right to left.

    Then the resulting code from the loader is passed to the next one. In this case, you want to chain the raw-loader and url-loader like this to give you the desired result:

    loaders: ['raw-loader', 'url-loader']
    

    Since you need to first have your font urls, automatically converted to base64 encoded in the styles, you must first call url-loader in your chain. Then since you are looking to import this file as a module.exports, you call raw-loader.

    So in the chain the following happens:

    1. url-loader: Converts all of your url references to static assets into base64:data.
    2. raw-loader: Takes your file, and wraps its entire code with a string and then makes it importable by adding module.exports='string'