如何在Webpack构建中包含Roboto字体以用于Material UI?

76
基于 Material UI(React)的渐进式 Web 应用程序,使用 Webpack 构建,我应该如何正确地包含 Roboto 字体,使应用程序不依赖于 Google 服务器,字体也可以离线工作?请保留 HTML 标签。
  • 安装页面只是引用Google字体页面, 但这显然会强制从Google服务器下载字体。

  • 关于Roboto字体存在一个类似的Material UI问题, 但仍然依赖于Google提供字体文件。

  • 我发现了一个NPM包提供Roboto字体文件, 但我不确定如何将这些文件包含进来,因为提供了许多样式和字体格式,我不知道Material UI真正需要哪些样式。而且,仅通过@import导入这些字体系列似乎会有性能问题

那么,有什么好的简单解决方案可以将适当的Roboto文件与我的应用程序捆绑在一起呢?


查看此链接以获取简单解决方案 - https://dev59.com/rGMl5IYBdhLWcg3wuI7p#61554849 - Manohar Reddy Poreddy
8个回答

64

以下是我的团队在 Webpack 项目中添加 Roboto 字体的具体步骤:

下载Roboto字体并在特定的字体文件夹中创建CSS文件

  • 创建一个文件夹(/fonts)。
  • Font Squirrel下载所有 Roboto 字体。转到Webfont Kit选项卡,然后按默认设置点击Download @font-face Kit按钮。
  • 将字体移至/fonts文件夹中。
  • 创建 CSS 文件 (/fonts/index.css),我们从这篇文章获取了该文件的内容

index.css:

* {
  font-family: Roboto, sans-serif;  
}

@font-face {
    font-family: 'Roboto';
    src: url('Roboto-Regular-webfont.eot');
    src: url('Roboto-Regular-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-Regular-webfont.woff') format('woff'),
         url('Roboto-Regular-webfont.ttf') format('truetype'),
         url('Roboto-Regular-webfont.svg#RobotoRegular') format('svg');
    font-weight: normal;
    font-style: normal;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-Italic-webfont.eot');
    src: url('Roboto-Italic-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-Italic-webfont.woff') format('woff'),
         url('Roboto-Italic-webfont.ttf') format('truetype'),
         url('Roboto-Italic-webfont.svg#RobotoItalic') format('svg');
    font-weight: normal;
    font-style: italic;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-Bold-webfont.eot');
    src: url('Roboto-Bold-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-Bold-webfont.woff') format('woff'),
         url('Roboto-Bold-webfont.ttf') format('truetype'),
         url('Roboto-Bold-webfont.svg#RobotoBold') format('svg');
    font-weight: bold;
    font-style: normal;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-BoldItalic-webfont.eot');
    src: url('Roboto-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-BoldItalic-webfont.woff') format('woff'),
         url('Roboto-BoldItalic-webfont.ttf') format('truetype'),
         url('Roboto-BoldItalic-webfont.svg#RobotoBoldItalic') format('svg');
    font-weight: bold;
    font-style: italic;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-Thin-webfont.eot');
    src: url('Roboto-Thin-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-Thin-webfont.woff') format('woff'),
         url('Roboto-Thin-webfont.ttf') format('truetype'),
         url('Roboto-Thin-webfont.svg#RobotoThin') format('svg');
    font-weight: 200;
    font-style: normal;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-ThinItalic-webfont.eot');
    src: url('Roboto-ThinItalic-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-ThinItalic-webfont.woff') format('woff'),
         url('Roboto-ThinItalic-webfont.ttf') format('truetype'),
         url('Roboto-ThinItalic-webfont.svg#RobotoThinItalic') format('svg'); (under the Apache Software License). 
    font-weight: 200;
    font-style: italic;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-Light-webfont.eot');
    src: url('Roboto-Light-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-Light-webfont.woff') format('woff'),
         url('Roboto-Light-webfont.ttf') format('truetype'),
         url('Roboto-Light-webfont.svg#RobotoLight') format('svg');
    font-weight: 100;
    font-style: normal;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-LightItalic-webfont.eot');
    src: url('Roboto-LightItalic-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-LightItalic-webfont.woff') format('woff'),
         url('Roboto-LightItalic-webfont.ttf') format('truetype'),
         url('Roboto-LightItalic-webfont.svg#RobotoLightItalic') format('svg');
    font-weight: 100;
    font-style: italic;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-Medium-webfont.eot');
    src: url('Roboto-Medium-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-Medium-webfont.woff') format('woff'),
         url('Roboto-Medium-webfont.ttf') format('truetype'),
         url('Roboto-Medium-webfont.svg#RobotoMedium') format('svg');
    font-weight: 300;
    font-style: normal;
}
 
@font-face {
    font-family: 'Roboto';
    src: url('Roboto-MediumItalic-webfont.eot');
    src: url('Roboto-MediumItalic-webfont.eot?#iefix') format('embedded-opentype'),
         url('Roboto-MediumItalic-webfont.woff') format('woff'),
         url('Roboto-MediumItalic-webfont.ttf') format('truetype'),
         url('Roboto-MediumItalic-webfont.svg#RobotoMediumItalic') format('svg');
    font-weight: 300;
    font-style: italic;
}

使用 file-loader webpack 模块加载字体文件,这样 webpack 就能识别它们了

webpack.conf.js:

loaders: [
  ..., {
    test: /\.(woff|woff2|eot|ttf|svg)$/,
    loader: 'file-loader',
    options: { name: '[name].[ext]', outputPath: 'fonts/', }
  },
  ...
]

在应用程序的主入口导入字体 CSS 文件

App.js:

import './fonts/index.css';

就这样了。现在你的应用程序默认字体应该是Roboto了。

编辑:Material-UI实际使用哪些Roboto字体?

这个问题的一部分是确定在项目中包含哪些正确的 Roboto 字体,因为整个 Roboto 字体库几乎有 5MB 大小。

README中,包含 Roboto 的说明指向:fonts.google.com/?selection.family=Roboto:300,400,500。这里,300 = Roboto-Light,400 = Roboto-Regular,500 = Roboto-Medium。这些对应于在 typography.js 文件 中定义的字重。虽然这三种字重几乎涵盖了整个库中的使用,但在DateDisplay.js 中有一个与 Regular-Bold 相关的引用。如果您不使用 DatePicker,则可以安全地忽略它。斜体字样式除了 GitHub markdown 样式之外,在项目中没有任何使用。

此信息在撰写本文时是准确的,但可能在将来发生变化。


啊,我现在明白问题了。我不知道除了Roboto-Regular之外你需要任何其他字体。这取决于是否有使用“font-weight”或“font-style”样式的组件。我会尝试今晚验证这个问题。无论如何,我找到了一篇关于懒加载字体以提高性能的文章。你可以预先加载Roboto-Regular并稍后再懒加载其他变体吗? - Daniel Bank
有趣的文章。然而,由于这是一个PWA,我需要将所有字体文件离线可用(也就是说它们必须被下载)。我猜没有其他办法,只能删除不必要的样式(从而确定哪些是不必要的)。 - Udo G
请查看我的更新答案。Roboto-Light、Roboto-Regular和Roboto-Medium几乎完全在库中使用,尽管我在DatePicker代码中找到了一个对Roboto-Bold的引用。我没有找到任何有意义的斜体字体样式引用。 - Daniel Bank
2
现在,行 " loader: 'file?name=fonts/[name].[ext]' " 已被替换为 " loader: 'file-loader?name=fonts/[name].[ext]' "。 - voice
1
你能否在关于fontsquirrel的教程中添加一些内容,告诉大家需要前往该网站,然后进入“Webfont kit”选项卡,接着按下“Download @font-face kit”按钮并使用默认设置?这似乎不是很明显。另外,在最新的webpack中,你需要提供以下代码:{ test: /\.(woff|woff2|eot|ttf|svg)$/, loader: 'file-loader', options: { name: '[name].[ext]', outputPath: 'fonts/', }, },否则可能会出现问题。 - Ser
显示剩余3条评论

60

也适用于 Gatsby! - Arnold Schrijver
2
这是因为上述项目已经默认支持字体。OP 询问如何在“ejected”或手动配置的 webpack 模式下设置字体。 - Mbrevda
2
@kimomat,您能否提示如何指定要导入的确切字体与 import typeface-roboto?例如,如果我只想要300和400字体。 - vogdb
1
据我所知,这个npm包包含所有字重。请参阅git存储库:https://github.com/KyleAMathews/typefaces/blob/master/packages/roboto/index.css - kimomat
这是否意味着应用程序中的所有文本都将使用Roboto字体,还有其他任务要完成吗? - Oamar Kanji
尝试了这些指令,但出现了以下错误:模块解析失败:意外字符'@'。您可能需要一个适当的加载器来处理此文件类型,目前没有配置任何加载器 - 425nesp

7

这是根据MUI文档所述的;我这样做了,它完美地运行了。

使用npm进行安装:

npm install @fontsource/roboto

... 或使用 yarn

yarn add @fontsource/roboto

然后,在你的应用程序入口点中包含这些导入项,例如 index.tsx

import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';

获取更多信息,请阅读文档


7

我尝试使用npm安装typeface-roboto,但它没有起作用。同时,使用material ui的CDN也无法正常工作。但是,使用npm安装webfontloader可以解决问题。以下是解决方案:

首先,

npm install webfontloader --save

然后,在您的entry.js文件(例如App.js或index.js)中从webfontloader中导入WebFont。

import WebFont from "webfontloader";
WebFont.load({google: {families: ["Roboto:300,400,500"]}});

1
唯一的解决方案,有无数其他的工作方式。重要的是导入必须在入口JavaScript文件中完成。 - arshbot

5
如果你使用 Angular,那么 import 'typeface-roboto' 不是最佳选择,也不太容易。你可以按照以下建议进行操作。
首先,按照其他人的描述安装这个很好的 npm 包:
npm install typeface-roboto --save

然后只需将此添加到你的 angular.json 文件中:
"styles": [
  "node_modules/typeface-roboto/index.css",
  [...],
  "src/styles.css"
],

3
给那位点了踩的人:您可以解释一下为什么要点踩吗?而不只是简单地点击“踩”按钮? - rugk

0

如果应用程序是使用create-react-app启动的,则没有[可见的]webpack配置文件。在这种情况下,您可以执行以下操作:

  1. 在/public中创建/fonts目录
  2. 创建/public/fonts/fonts.css,定义@font-faces

    @font-face { font-family: 'inglobal'; font-weight: normal; font-style: normal; src: url('./OperatorMono.ttf'); }

  3. 复制字体文件

  4. <link rel="stylesheet" href="%PUBLIC_URL%/fonts/fonts.css">添加到/public/index.html的

  5. 太棒了!

5/b. 如果由于任何原因仍然无法正常工作,请将字体扩展名更改为.css(也要在src: url('./OperatorMono.css')中)


1
我不是 Webpack 的专家,但我认为你不应该添加 HTML 标签来加载 CSS,Webpack 会作为其优化的一部分来处理它,所以我认为你正在绕过 Webpack。 - Luis Elizondo
没错,绕过是关键,因为你无法修改 webpack 配置文件,除非它被不可逆地弹出。 - sandorvasas

0

对于一个简单的 Material-UI / Create React App PWA,不需要所有的变体 - 你只需要:

yarn add @fontsource/roboto

index.js

import "@fontsource/roboto/latin-400.css";
import "@fontsource/roboto/latin-500.css";

theme.js(可选,但使其看起来更清晰、整洁)

overrides: {
  MuiCssBaseline: {
   html: {
    "-webkit-font-smoothing": "antialiased",
    "-moz-osx-font-smoothing": "grayscale",
    height: "100%",
    width: "100%"
  }
 }
}

您的字体将被捆绑并立即在线/离线提供

演示


0

虽然我目前在我的Vite/React/MUI项目中没有使用Webpack,但是这里是我如何以简单的方式集成Roboto字体的方法:

我发现你可以在这里下载字体的可变版本: https://fonts.google.com/specimen/Roboto+Flex

然后我只需像这样将它添加到我的主题中:

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { ThemeProvider } from '@emotion/react'
import { CssBaseline, createTheme } from '@mui/material'
import RobotoFlex from './fonts/Roboto_Flex/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf'

const theme = createTheme({
  typography: {
    fontFamily: 'Roboto',
  },
  components: {
    MuiCssBaseline: {
      styleOverrides: `
        @font-face {
          font-family: 'Roboto';
          font-style: normal;
          src: local('Roboto'), local('Roboto-Regular'), url(${RobotoFlex}) format('woff2');
          unicodeRange: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF;
        }
      `,
    },
  },
});

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <App />
    </ThemeProvider>
  </React.StrictMode>,
)

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