Как добавить шрифты к проектам, основанным на создании-реагировании?

Я использую create-response-app и предпочитаю не eject.

Непонятно, куда должны идти шрифты, импортированные через @font-face и загруженные локально.

А именно, я загружаю

@font-face {
  font-family: 'Myriad Pro Regular';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Regular'), url('MYRIADPRO-REGULAR.woff') format('woff');
}

Есть предложения?

- РЕДАКТИРОВАТЬ

Включая суть, на которую ссылается Дэн в своем ответе

➜  Client git:(feature/trivia-game-ui-2) ✗ ls -l public/static/fonts
total 1168
[email protected] 1 maximveksler  staff  62676 Mar 17  2014 MYRIADPRO-BOLD.woff
[email protected] 1 maximveksler  staff  61500 Mar 17  2014 MYRIADPRO-BOLDCOND.woff
[email protected] 1 maximveksler  staff  66024 Mar 17  2014 MYRIADPRO-BOLDCONDIT.woff
[email protected] 1 maximveksler  staff  66108 Mar 17  2014 MYRIADPRO-BOLDIT.woff
[email protected] 1 maximveksler  staff  60044 Mar 17  2014 MYRIADPRO-COND.woff
[email protected] 1 maximveksler  staff  64656 Mar 17  2014 MYRIADPRO-CONDIT.woff
[email protected] 1 maximveksler  staff  61848 Mar 17  2014 MYRIADPRO-REGULAR.woff
[email protected] 1 maximveksler  staff  62448 Mar 17  2014 MYRIADPRO-SEMIBOLD.woff
[email protected] 1 maximveksler  staff  66232 Mar 17  2014 MYRIADPRO-SEMIBOLDIT.woff
➜  Client git:(feature/trivia-game-ui-2) ✗ cat src/containers/GameModule.css
.GameModule {
  padding: 15px;
}

@font-face {
  font-family: 'Myriad Pro Regular';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Regular'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-REGULAR.woff') format('woff');
}

@font-face {
  font-family: 'Myriad Pro Condensed';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Condensed'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-COND.woff') format('woff');
}

@font-face {
  font-family: 'Myriad Pro Semibold Italic';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Semibold Italic'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-SEMIBOLDIT.woff') format('woff');
}

@font-face {
  font-family: 'Myriad Pro Semibold';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Semibold'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-SEMIBOLD.woff') format('woff');
}

@font-face {
  font-family: 'Myriad Pro Condensed Italic';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Condensed Italic'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-CONDIT.woff') format('woff');
}

@font-face {
  font-family: 'Myriad Pro Bold Italic';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Bold Italic'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-BOLDIT.woff') format('woff');
}

@font-face {
  font-family: 'Myriad Pro Bold Condensed Italic';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Bold Condensed Italic'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-BOLDCONDIT.woff') format('woff');
}

@font-face {
  font-family: 'Myriad Pro Bold Condensed';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Bold Condensed'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-BOLDCOND.woff') format('woff');
}

@font-face {
  font-family: 'Myriad Pro Bold';
  font-style: normal;
  font-weight: normal;
  src: local('Myriad Pro Bold'), url('%PUBLIC_URL%/static/fonts/MYRIADPRO-BOLD.woff') format('woff');
}

Ответ 1

Есть два варианта:

Использование импорта

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

Как описано в "Добавление изображений, шрифтов и файлов", вам необходимо импортировать файл CSS из JS. Например, по умолчанию src/index.js импортирует src/index.css:

import './index.css';

CSS файл, подобный этому, проходит через конвейер сборки и может ссылаться на шрифты и изображения. Например, если вы поместите шрифт в src/fonts/MyFont.woff, ваш index.css может включать в себя следующее:

@font-face {
  font-family: 'MyFont';
  src: local('MyFont'), url(./fonts/MyFont.woff) format('woff');
}

Обратите внимание, как использовался относительный путь, начинающийся с ./. Это специальная запись, которая помогает конвейеру сборки (на основе Webpack) обнаружить этот файл.

Обычно этого должно быть достаточно.

Использование папки public

Если по какой-либо причине вы предпочитаете не использовать конвейер сборки, а вместо этого делаете это "классическим способом", вы можете использовать папку public и поместить туда свои шрифты.

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

Если вы хотите сделать это таким образом, поместите шрифты куда-нибудь в папку public, например, в public/fonts/MyFont.woff. Если вы следуете этому подходу, вы должны также поместить CSS файлы в папку public и не импортировать их из JS, потому что смешивание этих подходов будет очень запутанным. Так что, если вы все еще хотите это сделать, у вас будет файл типа public/index.css. Вам нужно будет вручную добавить <link> к этой таблице стилей из public/index.html:

<link rel="stylesheet" href="%PUBLIC_URL%/index.css">

И внутри вы бы использовали обычную нотацию CSS:

@font-face {
  font-family: 'MyFont';
  src: local('MyFont'), url(fonts/MyFont.woff) format('woff');
}

Обратите внимание, как я использую fonts/MyFont.woff в качестве пути. Это связано с тем, что index.css находится в папке public, поэтому он будет обслуживаться по общедоступному пути (обычно это корневой каталог сервера, но если вы развернете на GitHub Pages и установите для своего поля homepage значение http://myuser.github.io/myproject, оно будет быть поданным из /myproject). Однако fonts также находятся в папке public, поэтому они будут обслуживаться из fonts относительно (либо http://mywebsite.com/fonts, либо http://myuser.github.io/myproject/fonts). Поэтому мы используем относительный путь.

Обратите внимание, что поскольку в этом примере мы избегали конвейера сборки, он не проверяет, существует ли файл на самом деле. Вот почему я не рекомендую такой подход. Другая проблема заключается в том, что наш файл index.css не минимизируется и не получает хэш. Так что для конечных пользователей это будет медленнее, и вы рискуете, что браузеры кешируют старые версии файла.

Какой способ использовать?

Перейти с первым методом ("Использование импорта"). Я описал только второй, поскольку именно это вы и пытались сделать (судя по вашему комментарию), но у него много проблем, и он должен быть последним средством, когда вы решаете какую-то проблему.

Ответ 2

Вот несколько способов сделать это:

1. Импорт шрифта

Например, для использования Roboto установите пакет с помощью

yarn add typeface-roboto

или

npm install typeface-roboto --save

В index.js:

import "typeface-roboto";

Существуют пакеты npm для множества шрифтов с открытым исходным кодом и большинства шрифтов Google. Вы можете увидеть все шрифты здесь. Все пакеты из этого проекта.

2. Для шрифтов, размещенных у третьих лиц

Например, шрифты Google, вы можете перейти на fonts.google.com, где вы можете найти ссылки, которые вы можете поместить в свой public/index.html

screenshot of fonts.google.com

Это будет как

<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">

или

<style>
    @import url('https://fonts.googleapis.com/css?family=Montserrat');
</style>

3. Использование пакета web-font-loader

Установите пакет с помощью

yarn add webfontloader

или

npm install webfontloader --save

В src/index.js вы можете импортировать его и указать необходимые шрифты

import WebFont from 'webfontloader';

WebFont.load({
   google: {
     families: ['Titillium Web:300,400,700', 'sans-serif']
   }
});

Ответ 3

Вы можете использовать модуль WebFont, который значительно упрощает процесс.

render(){
  webfont.load({
     custom: {
       families: ['MyFont'],
       urls: ['/fonts/MyFont.woff']
     }
  });
  return (
    <div style={your style} >
      your text!
    </div>
  );
}

Ответ 4

  1. Перейти к Google Fonts https://fonts.google.com/
  2. Выберите свой шрифт, как показано на рисунке ниже:

enter image description here

  1. Скопируйте, а затем вставьте этот URL в новую вкладку, вы получите код CSS для добавления этого шрифта. В этом случае, если вы идете в

https://fonts.googleapis.com/css?family=Spicy+Rice

Он откроется так:

enter image description here

4. Скопируйте и вставьте этот код в ваш style.css и просто начните использовать этот шрифт следующим образом:

      <Typography
          variant="h1"
          gutterBottom
          style={{ fontFamily: "Spicy Rice", color: "pink" }}
        >
          React Rock
        </Typography>

Результат:

enter image description here

Ответ 5

Я делал такие ошибки.

@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i&amp;subset=cyrillic,cyrillic-ext,latin-ext";
@import "https://use.fontawesome.com/releases/v5.3.1/css/all.css";

Это работает правильно таким образом

@import url(https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i&amp;subset=cyrillic,cyrillic-ext,latin-ext);
@import url(https://use.fontawesome.com/releases/v5.3.1/css/all.css);

Ответ 6

Я потратил все утро на решение аналогичной проблемы после того, как попал в этот вопрос. Я использовал первое решение Дана в ответе выше в качестве отправной точки.

Проблема

У меня есть разработчик (это на моей локальной машине), подготовка и производственная среда. Мои промежуточные и производственные среды находятся на одном сервере.

Приложение развернуто в промежуточной версии через acmeserver/~staging/note-taking-app, а рабочая версия находится в acmeserver/note-taking-app (обвините ИТ).

Все медиафайлы, такие как шрифты, прекрасно загружались в dev (то есть, react-scripts start).

Однако когда я создавал и загружал промежуточные и производственные сборки, в то время как файлы .css и .js загружались правильно, шрифтов не было. Скомпилированный файл .css выглядел правильно, но http-запрос браузера получал очень неправильный путь (показано ниже).

Скомпилированный файл main.fc70b10f.chunk.css:

@font-face {
  font-family: SairaStencilOne-Regular;
  src: url(note-taking-app/static/media/SairaStencilOne-Regular.ca2c4b9f.ttf) ("truetype");
}

Запрос http браузера показан ниже. Обратите внимание, как он добавляется в /static/css/, когда файл шрифта просто находится в /static/media/, а также дублирует папку назначения. Я исключил конфиг сервера, являющийся виновником.

Referer тоже частично виноват.

GET /~staging/note-taking-app/static/css/note-taking-app/static/media/SairaStencilOne-Regular.ca2c4b9f.ttf HTTP/1.1
Host: acmeserver
Origin: http://acmeserver
Referer: http://acmeserver/~staging/note-taking-app/static/css/main.fc70b10f.chunk.css

В файле package.json свойство homepage установлено на ./note-taking-app. Это было причиной проблемы.

{
  "name": "note-taking-app",
  "version": "0.1.0",
  "private": true,
  "homepage": "./note-taking-app",
  "scripts": {
    "start": "env-cmd -e development react-scripts start",
    "build": "react-scripts build",
    "build:staging": "env-cmd -e staging npm run build",
    "build:production": "env-cmd -e production npm run build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
  //...
}

Решение

Это было долго, но решение состоит в том, чтобы:

  1. изменить переменную PUBLIC_URL env в зависимости от среды
  2. удалить свойство homepage из файла package.json

Ниже мой файл .env-cmdrc. Я использую .env-cmdrc поверх обычного .env, потому что он хранит все вместе в одном файле.

{
  "development": {
    "PUBLIC_URL": "",
    "REACT_APP_API": "http://acmeserver/~staging/note-taking-app/api"
  },
  "staging": {
    "PUBLIC_URL": "/~staging/note-taking-app",
    "REACT_APP_API": "http://acmeserver/~staging/note-taking-app/api"
  },
  "production": {
    "PUBLIC_URL": "/note-taking-app",
    "REACT_APP_API": "http://acmeserver/note-taking-app/api"
  }
}

Маршрутизация через react-router-dom тоже работает нормально - просто используйте переменную PUBLIC_URL env в качестве свойства basename.

import React from "react";
import { BrowserRouter } from "react-router-dom";

const createRouter = RootComponent => (
  <BrowserRouter basename={process.env.PUBLIC_URL}>
    <RootComponent />
  </BrowserRouter>
);

export { createRouter };

Конфигурация сервера настроена на маршрутизацию всех запросов в файл ./index.html.

Наконец, вот как выглядит скомпилированный файл main.fc70b10f.chunk.css после того, как обсуждаемые изменения были реализованы.

@font-face {
  font-family: SairaStencilOne-Regular;
  src: url(/~staging/note-taking-app/static/media/SairaStencilOne-Regular.ca2c4b9f.ttf)
    format("truetype");
}

Материал для чтения