Closed alexnault closed 6 months ago
I'd assume we'd have to create our own React Helmet component and ship them with each package? Simply pass in values such as the weight etc. We'd then be able to set the filepath and Webpack would handle the rest.
Would this be applicable to Vue or other frameworks?
I found the same problem at testing web vitals: Other fonts have no problem but this one affects the load time; how can we handle this kind of event?
Here's a barebones simple draft of the React Helmet Component I had in mind that we could export with each package. The props arrangement will likely be different, but the following is just something to roughly illustrate the approach.
function FontsourcePreload(props) {
return <link rel="preload" href="files/{props.fontFileName}.woff2" as="font" type="font/woff2" crossorigin>
}
I'm not sure if this approach would work. It's not something I've gotten around to test, but it's the only solution I have in mind that logically MIGHT makes sense. If there are other approaches to this though, I would be more than happy to look into it.
Alternatively, to resolve the FOUT issue - https://dev.to/fyfirman/how-to-fix-fout-flash-of-unstyled-text-in-react-1dl1
As a workaround you can do something like this
import React from "react";
import { Helmet } from "react-helmet";
import '@fontsource/montserrat/latin-500.css'
import '@fontsource/montserrat/latin-700.css'
import montserrat500 from '@fontsource/montserrat/files/montserrat-latin-500-normal.woff2'
import montserrat700 from '@fontsource/montserrat/files/montserrat-latin-700-normal.woff2'
export default function App() {
return (
<Helmet>
<link rel="preload" as="font" href={montserrat500} type="font/woff2" />
<link rel="preload" as="font" href={montserrat700} type="font/woff2" />
</Helmet>
);
}
@albv, thank you for the suggestion. Quite frankly, I think this should be the proper step forward rather than be treated as a 'workaround'.
I think it'd be fair to add this method in the official documentation.
Ran into this issue with NextJS today. Importing woff2 doesn't work out of the box.
I am struggling to get this to work in the way I expect.
I set up this minimal repo using Next, Fontsource, and the next-fonts
"plugin" to import woff2 directly into the JS.
https://github.com/teauxfu/next-fontsource-test
The resource http://localhost:3001/_next/static/chunks/fonts/montserrat-latin-500-normal-ade7985dfab42940651537039e999ad9.woff2 was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally.
It seems like the font does preload (loads twice, in fact 😞), but is not being used. SO has several posts around the warning appearing in Chromium, but I didn't see anything immediately helpful after a cursory look around.
Unfortunately, the above suggestion does not solve the problem. Both fonts are loaded, but the preload one is not used.
was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate
as
value and it is preloaded intentionally.
The problem is, that you are attempting to preload to preload the original file URL ([...]/montserrat-latin-500-normal.woff2
), but not the hashed one ([...]/montserrat-latin-500-normal-ade7985dfab42940651537039e999ad9.woff2
).
I ended up doing everything myself. While the fontsource package is pretty neat, preloading and font-display
are somewhat inflexible, or at least hard to implement, compared to putting a file in the public folder, and adding a small piece of CSS:
@font-face {
/* Copyright: Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter) */
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-weight: 100 900;
src: url(/font/families/Inter/Inter.woff2) format('woff2 supports variations'),
url(/font/families/Inter/Inter.woff2) format('woff2-variations'),
url(/font/families/Inter/Inter.woff2) format('woff2');
font-display: swap;
}
I ended up doing everything myself. While the fontsource package is pretty neat, preloading and
font-display
are somewhat inflexible, or at least hard to implement
Hopefully, #234 addresses some of those flexibility concerns you may be facing.
I ended up doing everything myself. While the fontsource package is pretty neat, preloading and
font-display
are somewhat inflexible, or at least hard to implementHopefully, #234 addresses some of those flexibility concerns you may be facing.
Maybe. But the preloading issue remains unresolved, as it currently requires a loader to be configured (webpack/next config), and further steps, to preload the correct file/url. Doing everything manually takes roughly two minutes :) And it doesn't produce any overhead.
But the preloading issue remains unresolved, as it currently requires a loader to be configured (webpack/next config), and further steps, to preload the correct file/url.
If the outdir is configured to the public directory, it's pretty much the same as doing it manually. Preloading framework agnostically would be possible since nothing gets bundled and hashed.
Doing everything manually takes roughly two minutes :) And it doesn't produce any overhead.
True. That's always been the case for anyone who wanted to self-host. The only difference at that point is the ease of installing and updating packages via NPM, which still seems to be the preferable option for a lot of developers and I don't see that changing.
If the outdir is configured to the public directory, it's pretty much the same as doing it manually. Preloading framework agnostically would be possible since nothing gets bundled and hashed.
Until now, I wasn't able to make it work properly, and I haven't found a working example, based on a newer next.js version :/
Until now, I wasn't able to make it work properly, and I haven't found a working example, based on a newer next.js version :/
I meant for when #234 is finished, then it would be an option ^^
I don't have a solution but I also wanted to point out that this makes it difficult for Canvas / Context2D users to use fontsource as the font is stored as a bitmap, so we need to know when the font has loaded in order to proceed. As far as I can tell, there is no preloading or event handlers that help with this case..
As a workaround you can do something like this
import React from "react"; import { Helmet } from "react-helmet"; import '@fontsource/montserrat/latin-500.css' import '@fontsource/montserrat/latin-700.css' import montserrat500 from '@fontsource/montserrat/files/montserrat-latin-500-normal.woff2' import montserrat700 from '@fontsource/montserrat/files/montserrat-latin-700-normal.woff2' export default function App() { return ( <Helmet> <link rel="preload" as="font" href={montserrat500} type="font/woff2" /> <link rel="preload" as="font" href={montserrat700} type="font/woff2" /> </Helmet> ); }
I have absolutely no idea how you are able to import this line. Gives error on typescript.
> import montserrat500 from '@fontsource/montserrat/files/montserrat-latin-500-normal.woff2'
> import montserrat700 from '@fontsource/montserrat/files/montserrat-latin-700-normal.woff2'
For those that have an index.html
that you control such as when using Vite or similar you can simply add the preload to the page. For example when using the Lexend
font:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<link
rel="preload"
as="font"
crossorigin="anonymous"
href="/node_modules/@fontsource/lexend/files/lexend-latin-variable-wghtOnly-normal.woff2"
type="font/woff2"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My page</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
And then in main.tsx
:
// Import the font before anything else
import "@fontsource/lexend/variable.css";
Couldn't find any help for Vue users and it's kinda similar, but it might still help someone!
import { useHead } from '@unhead/vue'
import '@fontsource/roboto/latin-400.css'
import '@fontsource/roboto/latin-500.css'
import '@fontsource/roboto/latin-700.css'
import roboto400 from '@fontsource/roboto/files/roboto-latin-400-normal.woff2'
import roboto500 from '@fontsource/roboto/files/roboto-latin-500-normal.woff2'
import roboto700 from '@fontsource/roboto/files/roboto-latin-700-normal.woff2'
useHead({
link: [
{
rel: 'preload',
href: roboto400,
as: 'font',
crossorigin: 'anonymous',
type: 'font/woff2'
},
{
rel: 'preload',
href: roboto500,
as: 'font',
crossorigin: 'anonymous',
type: 'font/woff2'
},
{
rel: 'preload',
href: roboto700,
as: 'font',
crossorigin: 'anonymous',
type: 'font/woff2'
}
]
})
If you use a bundler (which most of you probably do), there’s an easy solution: https://github.com/cssninjaStudio/unplugin-fonts
If you use a bundler (which most of you probably do), there’s an easy solution: https://github.com/cssninjaStudio/unplugin-fonts
Is not enough the current font package?
It’s enough if you’re confident you can add and manually maintain the preload tags.
I suggested the plugin as a way to have the preload tags inserted automatically.
Using
fontsource
, how can one preload a font as to prevent a flash of faux-text?This issue is similar to another issue faced by typeface.