webpack sass-loader 如何正确加载 font字体

出现的问题

使用webpack一般会用到sass-loader,固然这不是重点。问题是引用font字体文件时会出现以下错误:css

xx路径引用不正确,致使资源找不到

再看看目录结构和引用方式:
图片描述webpack

@font-face {font-family: "iconfont";
    src: url('../../assets/fonts/iconfont.eot?t=1540697325659'); /* IE9*/
    src: url('../../assets/fonts/iconfont.eot?t=1540697325659#iefix') format('embedded-opentype'), /* IE6-IE8 */
    url('../../assets/fonts/iconfont.woff?t=1540697325659') format('woff'),
    url('../../assets/fonts/iconfont.ttf?t=1540697325659') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
    url('../../assets/fonts/iconfont.svg?t=1540697325659#iconfont') format('svg'); /* iOS 4.1- */
  }

而然文件引用层级和目录的结构又是正确的,为何加载字体文件的时候会出问题?git

官方解释

https://github.com/webpack-contrib/sass-loader#problems-with-urlgithub

图片描述

简单讲就是 sass-loader 这个加载器没有提供 url重写的功能,因此致使即便你文件路径是“正确的”,其实仍是引用不到。
再画个重点:其实经过 background之类用到url,仍是加载不到资源的,只是咱们可能一般会把font文件经过抽取到公共目录下,致使 url rewriting 的问题会被暴露出来。web

拿background举2个例子:chrome

index.scss //没有报错。引用和资源路径对象,其实只是误打误撞而已bootstrap

@import "./common/testSass.scss";
.image{
    width: 100px;
    height: 100px;
    border:1px solid green;
    background: url('../assets/images/logo.png') 100% 100%;
}

testSass.scss //报错。看似引用正确,其实和font的问题一致sass

.image{
    width: 100px;
    height: 100px;
    border:1px solid green;
    background: url('../../assets/images/logo.png') 100% 100%;
}

如何解决

理解上面问题出现的缘由,给出“能够”解决问题的方法:ide

把../../ 改为 ../svg

testSass.scss // success

.image{
    width: 100px;
    height: 100px;
    border:1px solid green;
    background: url('../assets/images/logo.png') 100% 100%;
}

iconfont.scss // success

@font-face {font-family: "iconfont";
    src: url('../assets/fonts/iconfont.eot?t=1540697325659'); /* IE9*/
    src: url('../assets/fonts/iconfont.eot?t=1540697325659#iefix') format('embedded-opentype'), /* IE6-IE8 */
    url('../assets/fonts/iconfont.woff?t=1540697325659') format('woff'),
    url('../assets/fonts/iconfont.ttf?t=1540697325659') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
    url('../assets/fonts/iconfont.svg?t=1540697325659#iconfont') format('svg'); /* iOS 4.1- */
  }

由于上面 出问题 的引用都是经过 css-loader ,因此根据上面的问题描述,得出:即便是子目录的文件仍是根据入口文件来作引用(即index.scss的位置)。

官方其实给出了2个方案:

  • Add the missing url rewriting using the resolve-url-loader. Place it before the sass-loader in the loader chain.
  • Library authors usually provide a variable to modify the asset path. bootstrap-sass for example has an $icon-font-path. Check out this working bootstrap example.

具体什么含义,能够参考webpack中文社区的解释。https://webpack.docschina.org/loaders/sass-loader/

最终方案

安装 relative-url-loader

module: {
        rules: [
            {
                test: /\.scss$/,
                use: ExtractTextPlugin.extract({
                        fallback: "style-loader",
                        use: ['css-loader', 'resolve-url-loader', 'sass-loader?sourceMap=true']
                        // use: ['css-loader', 'sass-loader']
                    })
            }

sass中的资源文件,按照“正确”的引用定义

@font-face {font-family: "iconfont";
    src: url('../../assets/fonts/iconfont.eot?t=1540697325659'); /* IE9*/
    src: url('../../assets/fonts/iconfont.eot?t=1540697325659#iefix') format('embedded-opentype'), /* IE6-IE8 */
    url('../../assets/fonts/iconfont.woff?t=1540697325659') format('woff'),
    url('../../assets/fonts/iconfont.ttf?t=1540697325659') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
    url('../../assets/fonts/iconfont.svg?t=1540697325659#iconfont') format('svg'); /* iOS 4.1- */
  }
.image{
    width: 100px;
    height: 100px;
    border:1px solid green;
    background: url('../../assets/images/logo.png') 100% 100%;
}

总结

这问题其实看到正确的文档内容,很快速可以解决,但愿能帮到各位。

相关文章
相关标签/搜索