使用 webpack 处理自定义 webfont(使用手写笔)

Handle custom webfont with webpack (using stylus)

首先,请注意我是 webpack 的新手,这是我使用它的第一个项目。

我正在尝试将一个简单的 webfont 包含到我的 webpack 应用程序中,但很难在我的页面上看到它。

我的架构是这样的:

|-- 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

我使用 stylus-loaderstyle-loadercss-loader 用于我的 CSS :

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

这是我尝试包含的 "HEINEKEN" 自定义字体(使用经典 file-loader):

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

捆绑时,一切看起来都很好。字体文件已正确使用并且是最终包的一部分,但我的字体不适用于 HTML,我不明白为什么。

webpack入口文件是index.js:

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

这是 ./styles/index.styl :

@import '_fonts';

html
  font-family 'Heineken Core', serif

... 和 ./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;
}

我检查了字体路径,是正确的。我想问题出在其他地方,但无法找到发生了什么事。

有帮助吗?

注意:我正在使用 webpack-dev-server .. 不知道它是否会导致问题。

提前,谢谢! :)

[编辑] 这是我的完整配置:

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'],

    //
    // alias: {
    //   jQuery: './node_modules/jquery/dist/jquery.js'
    // }
  },

  plugins: [
    // 
    /*new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery"
    }),*/

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

  // 
  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) {
  // 
  config.plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      exclude: /node_modules/
    })
  );
}


module.exports = config;

问题来自 CSS 处理相对路径的方式:

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

在我们的例子中,style-loader 将样式添加到 blob 对象,并通过 <link> 标签将其注入到 DOM,如下所示:

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

我们 CSS 中的相对 URL 正在使用这些 blob 作为基础进行解析,而不是从中加载 index.html 的主机。预计在这些位置没有发现任何东西。

这个问题的解决方案是在 CSS 引用中使用绝对 URL,这可以通过 webpack 配置中的 output.publicPath 选项轻松完成:

 module.exports = {
   output: {
     publicPath: (!production ? "http://localhost:8080/" : "http://your-production-host.com/")
   },
   // rest of your config options
 }