Chrome dev tools network tab and base64 inlined fonts lag - asynchronous

For a site I'm building, I'm trying to get the absolute best performance possible via some inline font / async JS loading in the head. In order to get around the extra http requests and delayed load required by Typekit font loading, I've opted to base 64 encode my woff / woff2 fonts (FontAwesome, Lato, Lato Bold) in my LESS / CSS. When running locally, I've got my DOMContentLoaded (blue bar) down to 30 ms but the font inlining it appears is causing my actual load time (red bar) to be 280 ms.
index.html
<!DOCTYPE html>
<html lang="en" xmlns:ng="http://angularjs.org" ng-app="tix.app" ng-strict-di ng-cloak class="wf-loading">
<head>
<base href="/">
<!-- blocks to hide FOUT -->
<style>.wf-loading [class^="icon-"], .wf-loading [class*=" icon-"], .wf-loading h1, .wf-loading h2, .wf-loading h3, .wf-loading h4, .wf-loading div, .wf-loading p, .wf-loading span, .wf-loading a, .wf-loading ul, .wf-loading li .wf-loading i { visibility: hidden !important; }</style>
<!-- starts download of dependent libraries (angular / d3 / jquery..) -->
<script src="/app/depends.js.gz" async defer></script>
<!-- starts download of angular app, has a check to ensure depends is downloaded first -->
<script src="/app/tix.js.gz" async defer></script>
<meta charset="utf-8"/>
<title>Angular SPA</title>
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- blocks to download inline base64 fonts and bootstrap based styles -->
<link href="/assets/css/tix.min.css.gz" rel="stylesheet" />
<!-- script to tell the page that CSS has finished loading so show text (wf-active) -->
<script src="/app/tix.fast.js.gz" async defer></script>
</head>
<body>
<angular-stuff></angular-stuff>
</body>
</html>
depends.js
'use strict';
module.exports = require('angular');
require('./d3.min');
require('./jquery-1.9.1.min');
require('./jquery.signalR-2.2.0.min');
require('./socket.io-1.3.4.js');
require('./ui-bootstrap-tpls.js');
require('angular-route');
require('angular-bootstrap');
require('angular-animate');
require('angular-loading-bar');
require('./ngStorage');
window.dependsLoaded = window.dependsLoaded || function () {};
window.dependsLoaded();
tix.js
window.isDependsLoaded = false;
function dependsLoaded() {
// App code
}
window.dependsLoaded = dependsLoaded;
// If angular already exists and the dependencies haven't been loaded, depends.js must have finished loading first -> manually initialize
if(window.angular && !window.isDependsLoaded) {
window.dependsLoaded();
}
tix.fast.js
(function (d) {
d.documentElement.className = "wf-active";
}(document));
The tix.less (tix.css) imports all fonts via #font-face like so -
#font-face {
font-family: 'Lato';
src: url(data:application/font-woff2;charset=utf-8;base64,......) format('woff2'),
url(data:application/font-woff;charset=utf-8;base64,......) format('woff');
font-weight: normal;
font-style: normal;
}
As you can see I hide all text elements with my inline CSS and manual "wf-inactive" class on the html element. I then async load my main scripts prior to loading my CSS fonts (so that the downloads will start prior to css blocking). depends.js has all the external libraries I'm dependent on (AngularJS, jquery, signalr, etc.). tix.js contains all my app logic (the actual angular app, and is much smaller than depends.js, but will get updated more often so I split them to benefit from depends.js caching). After the async scripts, I then have my css file load (all styles bundled in one CSS file, including my inlined base 64 fonts) which blocks, after that finishes loading I then load tix.fast.js which simply updates the html class to "wf-active", setting the page text to visible (emulating Typekit).
I'm basically seeing additional network latency per each font that is inlined within the network tab. This confuses me for a few reasons:
Why are these inlined fonts considered network requests in the first place? They use the url(data....) tag, but the whole point in inlining them is to avoid a network request so what's going on here? To me, the network request was downloading the file they were embedded in but maybe there are more hops required when loading the font?
I am trying to minimize the number of http calls since chrome only allows 6 simultaneous. Is that the reason that my fonts are getting hung up? Is it because the DOM isn't trying to access them until closer to the red load point and #font-face is just lazy loading them at that time? What are my best options to instrument this?

Related

How to get SSR?

Implementing a nextjs 13 app with the app directory and the Client and Server Component.
When displaying the source HTML, my body is empty and only contains scripts and JSON.
<!DOCTYPE html>
<html id="__next_error__">
<head>
<script src="/_next/static/chunks/polyfills.js" nomodule=""></script>
</head>
<body>
<script src="/_next/static/chunks/webpack.js" async=""></script>
<script src="/_next/static/chunks/main-app.js" async=""></script>
</body>
</html>
The JSON/script part is after this html and contains the whole page. As you can see, my body is empty, which I would like to avoid for SEO reasons.
When trying with the former manner with a page, I have the html displaying correctly in the body in an html tag.
Did I miss something that prevents SSR in nextjs 13?
In my Layout, I have a Client Component that wraps the whole App like that :
<AppWrapper appCurrentLang="{appCurrentLang}"> {children} </AppWrapper>;
I don't think it causes the SSR to fail, because even if I add a <p> tag on the root layout, it still doesn't display in the body tag in the source.
Here is the first part of the content displayed after the html :
<script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"M1:{\"id\":\"./node_modules/next/dist/client/components/app-router.js\",\"name\":\"\",\"chunks\":[\"app-client-internals:app-client-internals\"],\"async\":false}\nM2:{\"id\":\"./app/providers.jsx\",\"name\":\"Providers\",\"chunks\":[\"app/layout:app/layout\"],\"async\":false}\nM3:{\"id\":\"./node_modules/next/dist/client/components/layout-router.js\",\"name\":\"\",\"chunks\":[\"app-client-internals:app-client-internals\"],\"async\":false}\nM4:{\"id\":\"./node_modules/next/dist/client/components/render-from-template-context.js\",\"name\":\"\",\"chunks\":[\"app-cl"])</script><script>self.__next_f.push([1,"ient-internals:app-client-internals\"],\"async\":false}\n"])</script><script>self.__next_f.push([1,"J0:[\"$\",\"#1\",null,{\"assetPrefix\":\"\",\"initialCanonicalUrl\":\"/posts/teslas-biggest-threat\",\"initialTree\":[\"\",{\"children\":[\"posts\",{\"children\":[[\"postURL\",\"teslas-biggest-threat\",\"oc\"],{\"children\":[\"\",{}]}]}]},null,null,true],\"initialHead\":[\"$\",\"title\",null,{\"children\":\"My TEST Next.js App\"}],\"children\":[[],[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/app/layout.css?ts=1676839989010\",\"precedence\":\"high\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"data-test\":\"test\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"p\",null,{\"children\":\"okkk\"}],[\"$\",\"#2\",null,{\"langHeaders\":\"fr-FR\",\"children\":[\"$\",\"#3\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"hasLoading\":false,\"template\":[\"$\",\"#4\",null,{}],\"notFound\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"-apple-system, BlinkMacSystemFont, Roboto, \\\"Segoe UI\\\", \\\"Fira Sans\\\", Avenir, \\\"Helvetica Neue\\\", \\\"Lucida Grande\\\", sans-serif\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}]}],[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"\\n body { margin: 0; color: #000
Would anyone have an idea ?

Using Typekit / Adobe Fonts with #next/font

The current Next.js Font Optimization docs and the #next/font API Reference describe how to bring in Google Fonts as well as local font files, but the best practice for bringing in Typekit / Adobe Fonts is not described.
What is the best way to use Typekit / Adobe Fonts so that Next.js optimizations are applied?
#next/font has no support for Typekit yet and there isn't any related issue open on their GitHub repo (probably due to legal restrictions imposed by Typekit itself).
However, this doesn't mean that you cannot use Typekit fonts with Next.js. Prior to Next.js 13, it had a feature called automatic font optimization which still exists, and supports Typekit (added in vercel/next.js#24834).
It will basically inline your font CSS. So, if you have:
// pages/_document.tsx
import { Html, Head, Main, NextScript } from 'next/document'
const Document = () => {
return (
<Html>
<Head>
<link rel="stylesheet" href="https://use.typekit.net/plm1izr.css" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
export default Document
Then Next.js will generate your documents having some content like this in head (saves a request to Typekit):
<link rel="preconnect" href="https://use.typekit.net" crossorigin />
<!-- ... -->
<style data-href="https://use.typekit.net/plm1izr.css">
#import url('https://p.typekit.net/p.css?s=1&k=plm1izr&ht=tk&f=32266&a=23152309&app=typekit&e=css');
#font-face {
font-family: 'birra-2';
src: url('https://use.typekit.net/af/23e0ad/00000000000000003b9b410c/27/l?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3')
format('woff2'),
url('https://use.typekit.net/af/23e0ad/00000000000000003b9b410c/27/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3')
format('woff'),
url('https://use.typekit.net/af/23e0ad/00000000000000003b9b410c/27/a?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3')
format('opentype');
font-display: auto;
font-style: normal;
font-weight: 700;
font-stretch: normal;
}
.tk-birra-2 {
font-family: 'birra-2', serif;
}
</style>
Here is the integration suite, you can check it out for different ways to add that stylesheet link: https://github.com/vercel/next.js/tree/canary/test/integration/font-optimization/fixtures/with-typekit (some of those methods are deprecated and will give you warnings).

Loading font-family into the web application will display the default one for the first 2 seconds

I'm trying to load the Ubuntu-Bold font-family to my web application (ASP.NET CORE API + Angular). The Ubuntu-Bold.ttf file is located on assets/fonts folder and I also added #font-face { font-family: 'Ubuntu-Bold'; src: url(assets/fonts/Ubuntu-Bold.ttf); } body { margin: 0; font-family: 'Ubuntu-Bold'; } in to the styles.scss file. The font-family its applied to my application but after 2 seconds after the application started running.
Default font-family appears first at the beginning of application:
After 2 second the desired font-family its applied:
As you can see there its a big difference between this two fonts so I'm trying to find a solution in order to apply my font Ubuntu-Bold before the application its displayed in order to not see that change of family fonts after 2 seconds after application started.
you can use preload on your link tag, it tells the browser to load this stylesheet before the main part of your web app.
it should look something like that:
<link rel="preload" href="your/path/xxx.woff" as="font" type="font/woff" crossorigin>
or if you want your entire styles to load first
<link rel="preload" href="style.css" as="style">
you can read about it here

How to Load CSS asynchronous in NextJS

I want my global CSS file to load asynchronous, i.e without render-blocking. My page is waiting for FCP until it gets CSS loaded.
So, How can I achieve this in next js.
What I am getting :
<link rel="stylesheet" href="/_next/static/css/eb4e3a560474a24ae771.css" data-n-g="">
What is Expected :
<link rel="stylesheet" href="/_next/static/css/eb4e3a560474a24ae771.css" data-n-g="" media="all" onload="this.media='all'">
NextJS documentation on Font Optimization https://nextjs.org/docs/basic-features/font-optimization says that they transform provided <link> to preconnect with added style:
// Before
<link
href="https://fonts.googleapis.com/css2?family=Inter&display=optional"
rel="stylesheet"
/>
// After
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<style data-href="https://fonts.googleapis.com/css2?family=Inter&display=optional">
#font-face{font-family:'Inter';font-style:normal...
</style>
Now, you just need to adapt GET parameter display=[value] to adapt to font-display standard https://developer.mozilla.org/en-US/docs/Web/CSS/#font-face/font-display. The list is:
/* Keyword values */
font-display: auto;
font-display: block;
font-display: swap;
font-display: fallback;
font-display: optional;
Many are for mostly non-blocking (small block) display. All of them are explained in the Mozilla link, but the one I prefer, font-display: swap that gives extremely small block for font to load and if not in time, infinite swap period to change the font everywhere when it's loaded:
swap
Gives the font face an extremely small block period and an
infinite swap period.
Font block period
If the font face is not loaded, any element
attempting to use it must render an invisible fallback font face. If
the font face successfully loads during this period, it is used
normally.
Font swap period
If the font face is not loaded, any element
attempting to use it must render a fallback font face. If the font
face successfully loads during this period, it is used normally.
This way we can chose what fits better for us. If it still blocks a lot, I guess you'll have to put the link at the bottom of page.

font not changed even though imported within css stylesheet?

I'm using a CMS and therefore can only amend the CSS file. I have the following code in that file:
<style>
#import url('https://fonts.googleapis.com/css2?family=Montserrat&display=swap');
.h1_section_hero {
Font-family: 'Montserrat';
}
</style>
However it's not changing in the browser. I'm assuming that I don't have to download the font as i'm importing it within the file? thanks
It looks like your google font link is invalid, you are missing a ? between css2 and the family key:
'https://fonts.googleapis.com/css2?family=Montserrat&display=swap'
If you were to open both urls into your browser you will see that your original url is broken, and that the correct one above shows the fonts.
Create a separate link to the stylesheet rather than trying to import. The markup below is taken from the Google Fonts API doc and works just fine in my browser:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Crimson+Pro">
<style>
body {
font-family: 'Crimson Pro', serif;
font-size: 48px;
}
</style>
</head>
<body>
<div>Making the Web Beautiful!</div>
</body>
</html>

Resources