What is the best way to preload a font with a hashed filename and style hosted on a CDN?

Is there a way to preload the Material Icons font in advance?

<link rel="preload" href="https://fonts.gstatic.com/s/materialicons/v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2" as="font" type="font/woff2" crossorigin="anonymous">

It seems to be effective!

However, the issue arises when the filename includes a hash or UUID like:

v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc
. This means that if Google releases a new version with a different filename such as
v126/sjboabchdiamblq-Abf-abvichef
, then the preload won't work.

To provide more context, I am utilizing their CDN using this method:

<link
  href="https://fonts.googleapis.com/icon?family=Material+Icons"
  rel="stylesheet"
/>

This retrieves the following CSS:

@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/materialicons/v125/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2');
}

.material-icons {
  font-family: 'Material Icons';
  [...]
}

Note: I am working within Angular and aiming for the font loading process to commence immediately without waiting for the application to load. Even though the CSS file loads promptly, the font itself does not initiate loading until a Material Icon is displayed.

Answer №1

I was able to solve the issue by leveraging https://www.npmjs.com/package/@angular-builders/custom-webpack and utilizing a library for Material Icons (https://www.npmjs.com/package/material-icons)

This custom builder enables post-processing of index.html after the build.

  1. The first step is to include preloading in index.html (works during development):
<link rel="preload" href="/material-icons.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="/material-icons-outlined.woff2" as="font" type="font/woff2" crossorigin="anonymous">
  1. Add the following line in angular.json under "configurations":
"indexTransform": "index-html-transform.js"
  1. Create a new file named index-html-transform.js:
const fs = require("fs");

/**
 * @param {string} indexHtmlSource
 * @return {string}
 */
const setMaterialIconsFontsPreloading = (indexHtmlSource) => {
  const allOutputFilenames = fs.readdirSync("./dist/essai-preload-mat-icons");

  const requiredMatIconsFontsMatches = indexHtmlSource.matchAll(/(material-icons.*)\.woff2/g);

  /**
   * @example `['material-icons', 'material-icons-outlined']`
   */
  const requiredIconTypes = [...requiredMatIconsFontsMatches].map((match) => match[1]);

  return requiredIconTypes.reduce((previousIndexHtml, requiredIconType) => {
    /**
     * @example `'material-icons-outlined.woff2'`
     */
    const inputFilename = `${requiredIconType}.woff2`;

    /**
     * @example `'material-icons-outlined.125af8545b6.woff2'`
     */

    const outputFilename = allOutputFilenames.find((outputFilenameItem) => outputFilenameItem.match(`^${requiredIconType}\\.\\w+\\.woff2$`));

    return previousIndexHtml.replace(inputFilename, outputFilename);
  }, indexHtmlSource);
}

/**
 *
 * @param {{ configuration?: string; project: string; target: string;}} targetOptions
 * @param {string} indexHtmlSource
 * @returns {string} The final index.html to serve.
 */
module.exports = (targetOptions, indexHtmlSource) => {
    return setMaterialIconsFontsPreloading(indexHtmlSource);
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Choose the data attributes you want to include and attach them to input elements using plain JavaScript

Creating a User Information form with a select element containing four options, each with data attributes. Under the select are input types to populate the data attributes when selected. Looking for help in achieving this using plain JS and onchange event. ...

Expand the <canvas> element to completely fill the flex item without any scrollbars

I am currently utilizing Bootstrap 5 and experimenting with setting up a nested flex layout that occupies the entire window. One of the flex items should be filled by a "stretchy" canvas element, ensuring there are no scrollbars present. However, when I a ...

"Why is it that only one of the two similar spans with onclick event is not functioning properly

Encountering a perplexing issue that has me stumped. Here's the code in question: js: function Test() { alert("test"); } html: <span id='bla' onclick='Test()'> Click me </span> <hr> <span id='bla2& ...

Tips for hiding the initial value in an HTML Select tag

My HTML Select Program is very basic. By default, it displays "Volvo" as the first value. Is there a way to not display any initial value and allow the user to make a selection? <!DOCTYPE html> <html> <body> <form action="demo_form ...

Error Icon Displayed Incorrectly in Dynamically Generated List Items in Phonegap Android App

My attempt to dynamically create a list item with JSON response and set the data-icon to "check" is not working as expected. The result always shows "arrow-r" data-icon instead. This is how I generate the list item: function CallvarURL(url) { var res ...

Arranging nested divs in relation to one another in a specific position

This code represents a chart in HTML. The goal is to have the second (middle) div start where the first (top) div ends, which has a width of 75px. To achieve this, the margin-left for the middle div is set to 75px in the following styles. Following the sam ...

Experiencing challenges during the creation of a NUXT build

Trying to build a Nuxt SSR app, but encountering an error related to the css-loader during the build command execution. The issue seems to be with Invalid options object. ERROR in ./node_modules/vue2-google-maps/dist/components/streetViewPanorama.vue (./no ...

Tips for enhancing the transition effect of animated gifs on a webpage using JavaScript

In my code, I have an interval set to run every seven seconds. Within this interval, there are two gifs that each last for seven seconds. My goal is to display one of the gifs in a div (referred to as "face") based on certain conditions - for example, if t ...

Import files from local directory to iframe in Electron application

I am currently working on an application using Electron that allows users to preview HTML5 banner ads stored locally on their computer. At this point, I have enabled the ability to choose a folder containing all the necessary files. Once a directory is s ...

Tips for keeping two row headers in place on a table while scrolling:

Check out my fiddle here: https://jsfiddle.net/oed1k6m7/. It contains two td elements inside the thead. thead th { position: -webkit-sticky; /* for Safari */ position: sticky; top: 0; } The code above only makes the first row fixed. How can I make b ...

Events related to SVG elements

I have a unique situation where a div containing multiple SVG elements that act as buttons is added to the page after the user interacts with it. I am trying to add events to these SVG elements using event delegation, where I inspect the target of the even ...

execute the function after the animation has finished

Is it possible to trigger a function once an animation is complete using jQuery? Here's the code I'm working with: $('html, body').animate({scrollTop:$("body > .addAccountForm1").offset().top }, 'slow'); I want to execut ...

I am having trouble retrieving images from the backend API. Can someone assist me in resolving this issue?

I am facing an issue while trying to upload an image along with its details. I am able to retrieve all the information but the image is not displaying in the browser. My backend API is built using PHP Laravel and the images are stored in the Storage/app/ap ...

Change the position of an HTML image when the window size is adjusted

My web page features a striking design with a white background and a tilted black line cutting across. The main attraction is an image of a red ball that I want to stay perfectly aligned with the line as the window is resized, just like in the provided gif ...

Difficulty encountered when trying to update a re-updated HTML DOM using Flask

I have a flask dropzone for file uploads, and after each upload I want to display a log text on the website. While it currently works, there is an issue where the log text does not update after the second upload. The website continues to show the text from ...

Cease the audio from playing unless you are actively hovering over the image

Is there a way to make the sound stop playing when you are not actively hovering over the picture? Any suggestions on how to achieve this would be greatly appreciated! imgarr[i].onmouseout=function(){ this.setAttribute('src',this.getAttribu ...

Adjust the styling of CSS classes within an ExtJS application

I've been trying to customize the appearance of my calendar panel using extjs. In my EHR application, I have implemented the extjs calendarpanel and datepicker similar to the setup showcased in this link: When a date is selected from the datepicker a ...

I'm having an issue with my Bootstrap tabs - they seem to be unresponsive when clicked

I've been working on a Bootstrap website and have run into some issues that I can't seem to resolve. One problem I encountered was with a set of tabs that were supposed to be interactive, but for some reason, they weren't working as expected ...

Column that adjusts to different screen sizes

In the realm of responsive web design, what methods are suggested to achieve the specified CSS display? My main requirement is to have a maximum of three columns. The content should be divided evenly among these three columns. I prefer using SCSS and wel ...

What steps can I take to guarantee that my grid always accommodates its child without being too small?

My current setup involves utilizing a grid layout to arrange elements in the z-direction. However, I have encountered an issue where a child element extends beyond the boundaries of the grid element: #z-stack { display: grid; border: 5px solid ...