Webpack "OTS parsing error" 加载字体

Webpack "OTS parsing error" loading fonts

我的 webpack 配置指定应使用 url-loader 加载字体,当我尝试使用 Chrome 查看页面时,出现以下错误:

OTS parsing error: invalid version tag
Failed to decode downloaded font: [My local URL]

我配置的相关部分如下所示:

{
  module: {
    loaders: [
      // ...
      {
        test: /\.scss$/,
        loaders: ['style', 'css?sourceMap', 'autoprefixer', 'sass?sourceMap'],
      },
      {
        test: /images\/.*\.(png|jpg|svg|gif)$/,
        loader: 'url-loader?limit=10000&name="[name]-[hash].[ext]"',
      },
      {
        test: /fonts\/.*\.(woff|woff2|eot|ttf|svg)$/,
        loader: 'file-loader?name="[name]-[hash].[ext]"',
      }
    ],
  },
}

在 Safari 中不会发生,我还没有尝试过 Firefox。

在开发中,我通过 webpack-dev-server 提供文件,在生产中,它们被写入磁盘并复制到 S3;在这两种情况下,我在 Chrome.

中得到相同的行为

这也适用于较大的图像(大于图像加载器配置中的 10kB 限制)。

TL;DR 通过将 output.publicPath 设置为例如,使用资产的绝对路径(包括完整的主机名) “http://example.com/assets/”。

问题

问题是 URL 在从动态加载的 CSS blob 解析时由 Chrome 解析的方式。

当您加载页面时,浏览器会加载您的 Webpack 包条目 JavaScript 文件,该文件(当您使用 style-loader 时)还包含您的 [=61] 的 Base64 编码副本=],它被加载到页面中。

This is what it looks like in Chrome DevTools

这对于编码到 CSS 中作为数据 URI 的所有图像或字体都很好(即文件的内容嵌入在 CSS 中),但对于 CSS 引用的资产=51=]URL,浏览器必须找到并获取文件。

现在默认 file-loaderurl-loader 代表大文件)将使用 relative URLs 来引用资产 - 这就是问题所在!

These are the URLs generated by file-loader by default - relative URLs

当您使用相对 URL 时,Chrome 将相对于包含的 CSS 文件解析它们。通常这很好,但在这种情况下,包含文件位于 blob://... 并且任何相关的 URLs 都以相同的方式被引用。最终结果是 Chrome 试图从父 HTML 文件中加载它们,并最终试图将 HTML 文件解析为字体的内容,这显然是行不通的.

解决方案

强制 file-loader 使用绝对路径,包括协议("http" 或 "https")。

更改您的 webpack 配置以包含等同于以下内容的内容:

{
  output: {
    publicPath: "http://localhost:8080/", // Development Server
    // publicPath: "http://example.com/", // Production Server
  }
}

现在它生成的 URL 将如下所示:

Absolute URLs!

这些 URL 将被 Chrome 和所有其他浏览器正确解析。

使用extract-text-webpack-plugin

值得注意的是,如果您将 CSS 提取到单独的文件中,则不会出现此问题,因为您的 CSS 将位于正确的文件中,而 URLs 将被正确解析。

如@mcortesi here 所述,如果您从 css 加载程序查询中删除 sourceMaps,则 css 将在不使用 blob 的情况下构建,并且数据 url 将被正确解析

我遇到了同样的问题,但原因不同。

在 Will Madden 的解决方案没有帮助后,我尝试了通过 Intertubes 找到的所有替代解决方案 - 也无济于事。进一步探索,我恰好打开了一个有问题的字体文件。文件的原始内容以某种方式被 Webpack 覆盖以包含某种配置信息,这可能来自之前对文件加载器的修补。我用原始文件替换了损坏的文件,瞧,错误消失了(对于 Chrome 和 Firefox)。

与上面的 @user3006381 一样,我的问题不仅仅是相对 URL,而是 webpack 将文件作为 javascript 文件放置。他们的内容基本都是:

module.exports = __webpack_public_path__ + "7410dd7fd1616d9a61625679285ff5d4.eot";

在字体目录中,而不是真正的字体,字体文件在散列码下的输出文件夹中。为了解决这个问题,我不得不更改 url-loader(在我的例子中是我的图像处理器)上的测试,以不加载字体文件夹。我仍然必须在 webpack.config.js 中设置 output.publicPath 作为@will-madden 在他的出色回答中指出的那样。

对我来说,问题是我的正则表达式。下面的技巧让 bootstrap 工作:

{
    test: /\.(woff|ttf|eot|svg)(\?v=[a-z0-9]\.[a-z0-9]\.[a-z0-9])?$/,
    loader: 'url-loader?limit=100000'
},

如果您使用的是 Angular,您需要检查以确保您的

<base href="/"> 

标签位于您的样式 sheet 包之前。我从这个切换了我的代码:

 <script src="~/bundles/style.bundle.js"></script>
 <base href="~/" />

对此:

 <base href="~/" />
 <script src="~/bundles/style.bundle.js"></script>

问题已解决。 感谢this post让我大开眼界

我知道这不能回答 OP 的确切问题,但我带着同样的症状来到这里,但原因不同:

我像这样包含了 Slick Slider 的 .scss 文件:

@import "../../../node_modules/slick-carousel/slick/slick.scss";

仔细检查后发现它试图从无效位置 (<host>/assets/css/fonts/slick.woff) 加载字体,这是从样式表中引用它的方式。

我最终只是将 /font/ 复制到我的 assets/css/,问题就解决了。

自从您使用 url-loader:

The url-loader works like the file-loader, but can return a DataURL if the file is smaller than a byte limit.

因此,解决此问题的另一种方法是将限制设置得足够高,以便将字体文件包含为数据URL,例如 100000 或多或少 100Kb :

{
  module: {
    loaders: [
      // ...
      {
        test: /\.scss$/,
        loaders: ['style', 'css?sourceMap', 'autoprefixer', 'sass?sourceMap'],
      },
      {
        test: /images\/.*\.(png|jpg|svg|gif)$/,
        loader: 'url-loader?limit=10000&name="[name]-[hash].[ext]"',
      },
      {
        test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
        use: 'url-loader?limit=100000&mimetype=application/font-woff',
      },
      {
        test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
        use: 'url-loader?limit=100000&mimetype=application/font-woff',
      },
      {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        use: 'url-loader?limit=100000&mimetype=application/octet-stream',
      },
      {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        use: 'file-loader',
      },
      {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        use: 'url-loader?limit=100000&mimetype=image/svg+xml',
      },
    ],
  },
}

总是考虑到限制数字代表什么:

Byte limit to inline files as Data URL

这样您就不需要指定整个 URL 资产。当您希望 Webpack 不仅从本地主机响应时,这可能很困难。

只是最后一个考虑因素,不建议将此配置用于生产。这只是为了开发方便。

截至 2018 年,

use MiniCssExtractPlugin

for Webpack(> 4.0) 将解决这个问题。

https://github.com/webpack-contrib/mini-css-extract-plugin

在接受的答案中使用 extract-text-webpack-plugin 推荐用于 Webpack 4.0+。

最好最简单的方法是对字体文件进行base64编码。并在 font-face 中使用它。 对于编码,转到具有 font-file 的文件夹并在终端中使用命令:

base64 Roboto.ttf > basecodedtext.txt

您将得到一个名为 basecodedtext.txt 的输出文件。打开那个文件。删除其中的所有空格。

复制该代码并将以下行添加到 CSS 文件:

@font-face {
  font-family: "font-name";
  src: url(data:application/x-font-woff;charset=utf-8;base64,<<paste your code here>>) format('woff');
}  

然后您可以在 CSS 中使用 font-family: "font-name"

limit 是我的代码的线索,但我必须这样指定它:

use: [
  {
    loader: 'url-loader',
    options: {
      limit: 8192,
    },
  },
],

在我的例子中,将以下行添加到 lambda.js {my deployed is on AWS Lambda} 解决了这个问题。

 'font/opentype',
 'font/sfnt',
 'font/ttf',
 'font/woff',
 'font/woff2'

I just had the same issue with Font Awesome. Turned out this was caused by a problem with FTP. The file was uploaded as text (ASCII) instead of binary, which corrupted the file. I simply changed my FTP software to binary, re-uploaded the font files, and then it all worked.

https://css-tricks.com/forums/topic/custom-fonts-returns-failed-to-decode-downloaded-font/ 这最终帮助了我 我在 FTP 将文件作为文本

传输时遇到了同样的问题