Как предварительно загрузить шрифт CSS @font-face, который поставляется в комплекте с webpack4 babel?

#reactjs #babeljs #webpack-4 #preload

#reactjs #babeljs #webpack-4 #предварительная загрузка

Вопрос:

У меня есть настройка пакета webpack4 babel для веб-приложения react. В файле LESS я ссылаюсь на локальный шрифт. Этот шрифт копируется в dist папку при сборке, а его имя файла хэшируется. Я хочу иметь возможность предварительно загружать этот шрифт.

Вот мой файл LESS:

 @font-face {
    font-family: 'Test';
    src: url('../fonts/test.ttf') format('truetype');
    font-weight: 400;
}
  

Я пробовал следующие подходы, но пока безуспешно:

  1. Добавьте пользовательский импорт в основной JS-файл моего приложения.
 import(/* webpackPreload: true */ "../fonts/test.ttf");
  

Вот мой .babelrc файл:

 {
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ],
    "plugins": [
        "@babel/plugin-syntax-dynamic-import"
    ]
}
  

Запуск webpack нигде, насколько я могу видеть в выводимом html, не выдает указаний по предварительной загрузке — я просмотрел содержимое dist папки и ничего не нашел.

  1. предварительная загрузка-webpack-plugin

Я добавляю это в свой webpack.config.js файл:

 plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    as(entry) {
      if (/.css$/.test(entry)) return 'style';
      if (/.woff$/.test(entry)) return 'font';
      if (/.png$/.test(entry)) return 'image';
      return 'script';
    }
  })
]
  

Это создает предварительные загрузки для пакетов файлов JS script, но не для CSS и шрифтов.

Есть идеи о том, как заставить это работать?

Ответ №1:

удалось заставить его работать на webpack4, установив версию 3beta и используя опцию while list:

 yarn add -D preload-webpack-plugin@3.0.0-beta.3

new PreloadWebpackPlugin({
        rel: 'preload',
        as: 'font',
        include: 'allAssets',
        fileWhitelist: [/.(woff2?|eot|ttf|otf)(?.*)?$/i],

    }),
  

Ответ №2:

Публикую это, поскольку я думаю, что это может помочь кому-то в аналогичном положении — я понимаю, что это не решает описанную проблему.

Была та же проблема — не нужно было хэшировать мои файлы шрифтов, но была другая часть URL, которая не была статической. Немного по-хакерски, но решил мою проблему. Возможно, это может кому-то помочь. Теоретически вы можете создать свой собственный хэш-идентификатор и установить его в качестве переменной htmlWebpack-plugin.

В моем index.html

 <html>
  <head>
    <link rel="preload" href="<%= htmlWebpackPlugin.options.woffSrc %>" as="font" type="font/woff" crossorigin>
    <link rel="preload" href="<%= htmlWebpackPlugin.options.woff2Src %>" as="font" type="font/woff2" crossorigin>

    //rest of html
  

webpack.prod.conf.js — обновленный HtmlWebpackPlugin

 plugins: [
  new HtmlWebpackPlugin({
    ...config,
    woffSrc: `https://url.to.my.page.com/${ASSETS_FOLDER}/static/assets/fonts/GilroyRegular.woff`,
    woff2Src: `https://url.to.my.page.com/${ASSETS_FOLDER}/static/assets/fonts/GilroyExtraBold.woff2`
  })
]
  

Я рассудил, что файлам шрифтов не обязательно иметь хэш, поскольку он в основном используется для управления кэшем, и я не буду изменять файлы шрифтов, поэтому я включил хэш в моем загрузчике файлов webpack. Пожалуйста, поправьте меня, если я здесь ошибаюсь.

Наличие загрузчика:

 {
  test: /.(woff2?|eot|ttf|otf)(?.*)?$/,
  loader: 'url-loader',
  options: {
    limit: 2000,
    name: utils.assetsPath('assets/fonts/[name].[ext]')
  }
}
  

Не удалось запустить плагин preload-webpack из-за ошибок сборки и устал устранять неполадки через 2 дня.

Ответ №3:

Я нашел обходной путь для этого. Это неприятно, но я думаю, что это не лучше, чем ничего. здесь я хотел только предварительно загрузить woff и woff2 файлы.

 new PreloadWebpackPlugin({
      rel: 'preload',
      include: 'allAssets',
      fileBlacklist: [/.(js|ttf|png|eot|jpe?g|css|svg)/]
    }),
  

Ответ №4:

Я думаю, что смог исправить это, переместив файл шрифта в мою public папку, а затем переместив мое @font-face определение в <style> теги в моем index.html файле, где я мог бы использовать %PUBLIC_URL% для указания местоположения для Webpack:

 <head>
  
  <!-- Some stuff... -->

  <link rel="preload" href="%PUBLIC_URL%/my-font-file.ttf" as="font" />

  <style>
    @font-face {
      font-family: my-font-name;
      src: url('%PUBLIC_URL%/my-font-file.ttf');
    }
  </style>
</head>
  

(находится my-font-file.ttf в public папке моего проекта)

Ответ №5:

Я полагаю, что для предварительной загрузки файла шрифта вы можете просто вручную указать его <link /> в вашем index.html файле:

 <link rel="preload" href="../fonts/test.ttf" as="font" type="font/ttf">
  

Смотрите Это для получения некоторых подробностей.

Комментарии:

1. Спасибо за ответ, но моя проблема в том, что имена файлов шрифтов хэшируются webpack, и поэтому я не знаю, какими они будут после копирования в dist папку. Возможно, есть способ использовать заполнитель в HTML-файле?

2. Ваши файлы шрифтов будут часто меняться? Зачем вам нужно включать их в процесс компиляции вашего webpack? Я думаю, вы можете создать другую assets папку для размещения статических файлов, которые не нужно компилировать webpack параллельно с dist папкой, и также обслуживать статические файлы из этой папки

3. Это справедливое замечание. Шрифты не изменятся, и даже если они изменятся, копирование их после сборки webpack не потребует слишком больших усилий. Я полагаю, что ссылка на файлы шрифтов в HTML (для предварительной загрузки), а также ссылка с использованием @font-face в CSS (где они фактически будут использоваться) — это нормально, т. Е. Как только они будут предварительно загружены браузером, он не будет беспокоиться о повторном выполнении?

4. Я не думаю, что есть какой-либо другой способ предварительной загрузки шрифтов, кроме использования link . Таким образом, даже если вы использовали какое-либо решение для предварительной загрузки Webpack, оно просто вставило бы link с атрибутом предварительной загрузки, который загрузил бы ваш ресурс. Итак, да, я считаю, что браузеру не следует отправлять другой запрос, если он уже предварительно загрузил ресурс, однако я думаю, вы хотели бы поместить некоторые cache-control заголовки, чтобы браузер кэшировал ресурс.

5. Приветствия. Ваш рекомендуемый подход теперь внедрен и работает хорошо.