webpack/sass无法加载自定义字体

5
我们有一个大项目,正在尝试实现ITCSS模式(这个模式运行良好),并添加由我们的图形设计师创建的自定义图标字体。
以下是文件夹结构(不全):
.
├── build
│   └── webpack.config.js
└── src
    ├── components                           # Using React
    │   ├── test.jsx
    │   └── test.scss
    └── styles
        ├── _objects                         # Components style reusable
        │   ├── _all.scss
        │   └── table.scss
        ├── _settings                        # Global variables
        │   ├── _all.scss
        │   ├── _custom-icons.scss           # Define icon font (see below)
        │   ├── _custom-icons-variables.scss # Define icon codes
        │   ├── _colors.scss                 # Define colors
        │   ├── _predefined-colors.scss      # Define brand colors
        │   └── _theme.scss                  # Define specific theme
        ├── _tools                           # Mixins / helpers
        │   ├── _all.scss
        │   ├── _animation.scss
        │   ├── _breakpoints.scss
        │   └── _transition.scss
        ├── _wins                            # Overrides
        │   ├── _all.scss
        │   ├── _display.scss
        │   ├── _position.scss
        │   └── _text.scss
        ├── assets
        │   └── fonts
        │       ├── custom-icons.eot
        │       ├── custom-icons.svg
        │       ├── custom-icons.ttf
        │       └── custom-icons.woff
        ├── _base.scss                       # HTML Selectors
        ├── _generic.scss                    # Reset (normalize)
        └── main.scss                        # Loads everything

好的,这是一个相当复杂的文件结构,但它可以完成我们想要实现的目标!

我们基于davezuko的react-redux-starter-kit启动了我们的应用程序。我们调整了webpack配置文件以满足我们的需求,但没有改变样式部分,因此您可以参考GitHub上的webpack.config.js

现在,这是我们的文件:

_custom-icons-variables.scss

$fontPath: "./assets/fonts" !default;

$aw-happy: "\e9df";
$aw-smile: "\e9e1";
$aw-tongue: "\e9e3";
$aw-sad: "\e9e5";
$aw-wink: "\e9e7";
$aw-grin: "\e9e9";
$aw-cool: "\e9eb";
$aw-angry: "\e9ed";
…

_custom-icons.scss

定制图标字体依赖于Semantic-UI字体图标样式。
@import "custom-icons-variables";

$fontName: 'custom-icons';

$fallbackSRC: url("#{$fontPath}/#{$fontName}.eot");
$src:
  url("#{$fontPath}/#{$fontName}.eot?#iefix") format('embedded-opentype'),
  url("#{$fontPath}/#{$fontName}.woff") format('woff'),
  url("#{$fontPath}/#{$fontName}.ttf") format('truetype'),
  url("#{$fontPath}/#{$fontName}.svg?##{$fontName}") format('svg')
;

@font-face {
  font-family: $fontName;
  src:  $fallbackSRC;
  src:  $src;
  font-weight: normal;
  font-style: normal;
}

i.icon.aw {
  font-family: $fontName !important;
}

.aw-happy {
  &:before {
    content: $aw-happy;
  }
}
.aw-smile {
  &:before {
    content: $aw-smile;
  }
}
.aw-tongue {
  &:before {
    content: $aw-tongue;
  }
}
.aw-sad {
  &:before {
    content: $aw-sad;
  }
}
.aw-wink {
  &:before {
    content: $aw-wink;
  }
}
.aw-grin {
  &:before {
    content: $aw-grin;
  }
}
.aw-cool {
  &:before {
    content: $aw-cool;
  }
}
.aw-angry {
  &:before {
    content: $aw-angry;
  }
}
…

main.scss

这里的所有内容都是全局的,因此我们避免webpack添加哈希值,并允许我们在组件中直接使用类名(请参见下面的示例)。

:global {
  @import "_settings/all";
  @import "_settings/custom-icons";
  @import "_tools/all";
  @import "generic";
  @import "base";
  @import "_objects/all";
  @import "_wins/all";
}

test.jsx

在这里,您可以看到我们使用全局和局部样式。
import React, { Component } from 'react'

import s from './test.scss'

export default class Test extends Component {
  render () {
    return (
      <div className={s['test']}>
        <i className='icon aw aw-happy'></i>
        <h1>Test</h1>
      </div>
    )
  }
}

test.scss

是的,对于每个使用我们品牌颜色的组件,我们需要重新导入Sass文件...我不知道这是否是一个坏事,但它有效 :)

@import "src/styles/_settings/all";

.test {
  background: $brown;
  color: $white_smoke;
}

现在背景已经介绍完毕,接下来是问题: aw-happy 图标被渲染成一个正方形(就像当你的字体没有加载时一样...),我无法使其工作,浏览了大量资源后,我尝试了所有可能的方法 :/
我们正在使用 Semantic-UI,它是通过webpack构建并捆绑的,因此我尝试将 @font-face 规则添加到 semantic.min.css 中,并将字体文件移动到 semantic 文件夹中。

semantic.min.css

@font-face {
   font-family: 'custom-icons';
   src:  url(themes/default/assets/fonts/custom-icons.eot);
   src:  url(themes/default/assets/fonts/custom-icons.eot?#iefix) format('embedded-opentype'),
   url(themes/default/assets/fonts/custom-icons.woff) format('woff'),
   url(themes/default/assets/fonts/custom-icons.ttf) format('truetype'),
   url(themes/default/assets/fonts/custom-icons.svg?#custom-icons) format('svg');
   font-weight: normal;
   font-style: normal;
 }
 // Semantic stuff…

而且……它有效了!

我在想,我是否应该像我们对待语义化一样构建和提供此自定义字体,但将所有过程与全局样式分离很麻烦。

有什么想法可以通过保留所有Sass/Webpack内容来解决这个问题吗?


我认为Webpack无法获取字体文件,因为在你的url()中使用了变量。尝试只使用简单字符串,我认为那样会起作用。 - Ambroos
我已经尝试过这种方法,但也没有起作用... :/ 我试过使用 url(assets/fonts/custom-icons.eot)url("assets/fonts/custom-icons.eot") 这两种方式!此外,我尝试将其保留在 $src$fallbackSrc 中,但也直接编写在 @font-face 定义中。 - Nicolas Goudry
我查看了Chrome Dev Tools的资源面板,但是没有看到我的字体被加载。此外,当我查看源代码面板并转到webpack://源时,我发现我的字体被导出为这样的形式module.exports = __webpack_public_path__ + "src/styles/assets/fonts/custom-icons.eot";(所有版本都相同,例如:eot/svg/ttf/woff)。 - Nicolas Goudry
1个回答

2

我在浏览react-redux-starter-kit项目的已关闭错误时找到了解决方法:

我将@font-face定义移到了main.scss文件中,在:global之前:

main.scss

$font-path: 'styles/assets/fonts';
$font-name: 'custom-icons';

$fallback-src: url("#{$font-path}/#{$font-name}.eot");
$src:
  url("#{$font-path}/#{$font-name}.eot?#iefix") format('embedded-opentype'),
  url("#{$font-path}/#{$font-name}.woff") format('woff'),
  url("#{$font-path}/#{$font-name}.ttf") format('truetype'),
  url("#{$font-path}/#{$font-name}.svg?##{$font-name}") format('svg')
;

@font-face {
  font-family: $font-name;
  src:  $fallback-src;
  src:  $src;
  font-weight: normal;
  font-style: normal;
}

当我将$font-path定义为../styles/assets/fonts时,它也能正常工作,但是不能定义为./assets/fonts

这是一个已知的错误,在GitHub上有相关记录,但此时davezuko没有深入研究它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接