1

First, please note that I'm new to webpack and this is my first project with it.

I'm trying to include a simple webfont into my webpack application, but have difficulties to see it on my page.

My architecture looks like this :

|-- app
|  |-- images
|  |  `-- icons
|  |-- index.html
|  |-- index.js
|  |-- scripts
|  `-- styles
|     |-- fonts
|     |  |-- HEINEKEN Core.eot
|     |  |-- HEINEKEN Core.otf
|     |  |-- HEINEKEN Core.svg
|     |  |-- HEINEKEN Core.ttf
|     |  |-- HEINEKEN Core.woff
|     |-- index.styl
|     |-- _fonts.styl
|-- package.json
|-- README.md
`-- webpack.config.js

I use the stylus-loader, and both style-loader and css-loader for my CSS :

{
  test: /\.styl$/,
  exclude: /node_modules/,
  loader: [
            'style-loader',
            'css-loader' + (!production ? '?sourceMap' : ''),
            'postcss-loader',
            'stylus-loader'
          ].join('!')
}

and here's what I tried to include the "HEINEKEN" custom fonts (with the classic file-loader) :

{
  test: /\.(eot|svg|ttf|woff|woff2)$/,
  exclude: /node_modules/,
  loader: 'file-loader?name=[path][name].[ext]&context=app/'
}

When bundling, everything seems to look good. Font files are properly consumed and are part of the final bundle, but my fonts doesn't apply in the HTML, and I can't see why.

The webpack entry file is index.js :

import './index.html';
import './styles/index.styl';

Here's the ./styles/index.styl :

@import '_fonts';

html
  font-family 'Heineken Core', serif

... and the ./styles/_fonts.styl :

@font-face {
  font-family: 'Heineken Core';
  src: url('./fonts/HEINEKEN Core.eot');
  src: url('./fonts/HEINEKEN Core.eot?#iefix') format('embedded-opentype'),
       url('./fonts/HEINEKEN Core.woff') format('woff'),
       url('./fonts/HEINEKEN Core.ttf') format('truetype'),
       url('./fonts/HEINEKEN Core.svg#HEINEKENCore') format('svg');
  font-weight: normal;
  font-style: normal;
}

I've checked the fonts path, it's correct. I guess the problem is somewhere else, but can't manage to find what's going on.

Any help ?

Note : I'm using webpack-dev-server .. dunno if it can cause an issue.

By advance, thank you ! :)

[EDIT] Here's my full config :

const path              = require('path');
const webpack           = require('webpack');
const autoprefixer      = require('autoprefixer');

const production        = process.argv.indexOf("--production") > -1;

// Full Webpack Guide :
// https://medium.com/@dabit3/beginner-s-guide-to-webpack-b1f1a3638460#.olmn099wa
// and :
// https://julienrenaux.fr/2015/03/30/introduction-to-webpack-with-practical-examples/

var config = {
  entry: {
    vendor: ['jquery', 'jqvmap', 'gsap'],
    app: './app/index.js'
  },
  output: {
    path: path.join(__dirname, 'dist'),
    publicPath: !production ? 'http://localhost:8080/' : undefined,
    filename: 'bundle.js'
  },
  watch: !production,
  debug: !production,

  module: {
    preLoaders: [
      {
        test: /\.(js|es6)$/,
        exclude: /node_modules/,
        loader: 'jshint-loader'
      }
    ],
    loaders: [
      {
        test: /\.(js|es6)$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: { presets:[/*'react',*/'es2015'] } // Loader's options
      },
      {
        test: /\.styl$/,
        exclude: /node_modules/,
        loader: [
                  'style-loader',
                  'css-loader' + (!production ? '?sourceMap' : ''), // https://github.com/webpack/style-loader#recommended-configuration
                  'postcss-loader',
                  'stylus-loader'
                  // 'file-loader?name=[path][name].[ext]&context=app/'
                ].join('!')
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2)$/,
        exclude: /node_modules/,
        loader: 'file-loader?name=[path][name].[ext]&context=app/'
      },
      {
        test: /\.jpg$/,
        loader: 'file-loader?name=[path][name].[ext]&context=app/'
      },
      {
        test: /\.(png|gif)$/,
        loader: 'file-loader?name=[path][name].[ext]&context=app/' // 'url-loader?name=[path][name].[ext]&limit=150000' // filesize of < 150ko will be included as data URL
      },
      {
        test: /\.html$/,
        loader: [
                  'file-loader?name=[path][name].[ext]&context=app',
                  'extract-loader',
                  'html-loader'
                ].join('!')
      },

      // https://65535th.com/jquery-plugins-and-webpack/
      // https://github.com/webpack/expose-loader
      {
        test: require.resolve("jquery"),
        loader: [
                  'expose-loader?$',
                  'expose-loader?jQuery'
                ].join('!')
      }
    ]
  },

  resolve: {
    extensions: ['', '.js', '.es6'],

    //http://stackoverflow.com/a/28989476/1187888
    // alias: {
    //   jQuery: './node_modules/jquery/dist/jquery.js'
    // }
  },

  plugins: [
    // http://stackoverflow.com/a/28989476/1187888
    /*new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery"
    }),*/

    new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendor", /* filename= */"vendor.bundle.js"/*, Infinity*/)
  ],

  // http://stackoverflow.com/a/33384364/1187888
  devServer: {
    contentBase: "./app",
    hot: true
  },

  // https://github.com/postcss/autoprefixer#webpack
  postcss: [ autoprefixer({ browsers: ['last 5 versions'] }) ],

  jshint: { 'esversion' : 6 }
};


// Empêche UglifyJS de gueuler sur le bundle de prod
// ---
if (production) {
  // http://stackoverflow.com/a/34071566/1187888
  config.plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      exclude: /node_modules/
    })
  );
}


module.exports = config;
jmpp
  • 293
  • 1
  • 3
  • 17

1 Answers1

3

The issue comes from the way that CSS handles relative paths:

Relative URLs are resolved to full URLs using a base URL. RFC 3986, section 3, defines the normative algorithm for this process. For CSS style sheets, the base URL is that of the style sheet itself, not that of the styled source document.

CSS Values and Units Module Level 3

In our case style-loader adds styles to blob objects and injects it to DOM via <link> tag like this:

 <link rel="stylesheet" href="blob:http://localhost:8080/4f0dcf58-1e22-46b5-bc74-60c97c1ad923">

Relative URLs in our CSS are resolving using these blobs as a base, not host from which index.html was loaded. And expectedly nothing was found at these locations.

The solution of this issue is to use absolute URLs in CSS references, what can be easily done with the output.publicPath option in the webpack config:

 module.exports = {
   output: {
     publicPath: (!production ? "http://localhost:8080/" : "http://your-production-host.com/")
   },
   // rest of your config options
 }
kiurchv
  • 46
  • 3
  • Actually, I already had this ternary in my configuration's `publicPath` , but this aimed me to find the solution. The line in cause was the following loader for my .woff|.eot ... files : `loader: 'file-loader?name=[path][name].[ext]&context=app/'` , which I just rewrited in `loader: 'file-loader'`. This solved my problem. Thank you for pointing me on the right way :) – jmpp Dec 16 '16 at 00:11
  • 1
    Hmm, strange behavior, possibly it was caused by some bug in the file-loader or loader-utils. Anyway, I glad that problem was solved – kiurchv Dec 16 '16 at 07:17
  • I suspect webpack-dev-server to be in cause of my initial problem. While I couldn't see my fonts on screen, I noticed that the CSS bundle did contain the full URL `@font-face { src: url(http://localhost:8080/styles/fonts/HEINEKEN Core.woff) ... }` and this URL was 100% valid : I could browse on it and was able to download the font .. so it wasn't a problem of relative/absolute path. Strange indeed. – jmpp Dec 16 '16 at 11:37