Article
2 comments

How to bundle and use custom web fonts in SPFx projects

There are multiple ways to add custom web fonts to SPFx projects. The best options are to load fonts from a CDN, your own, a commercial provider or via fonts.google.com.

Sometimes this is not enough cause our customer has their custom fonts or my want to use a custom font for a single web part only. Let me show the steps to get this accomplished in the SharePoint Framework.

Prepare the solution

For this demo webpart, I downloaded the font ‘Permanent Marker‘ from the Google Fonts. The right location for this font file is at first somewhere in the src folder. I chose to create a fonts folder directly in the root of src. This way, the font could be consumed by multiple web part in the solution.

Fonts placed under ‘src/fonts’

Two-stage build chain

The SharePoint Framework build chain happens in three steps. First, the code and assets in the ‘src’ folder will be transpiled to the ‘lib’ folder. From there webpack pick up the transpiled code and assets and bundle it with webpack.

Move font from ‘src’ to ‘lib’

When the font files only exist in the ‘src’ folder, we cannot make use in our web part of it. The first step is that those files also need to exist in the ‘lib’ folder.

One option is to copy the files manually. Other developers run into issues that cause the ‘lib’ folder is just an intermediate folder that won’t get checked in to your code repository.

A best and only stable approach is to let SPFx copy the files over to the ‘lib’ directory for us. Fonts files are real static assets in the overall solution. For static files, we need to create a ‘copy-static-assets.json’ in the config folder with the following content.

{
    "includeExtensions": [
        "ttf",
        "woff",
        "eot",
        "woff2"
        // optional use , "svg"
    ]
}

In the ‘includedExtension’ section contains all file extension for know font files. SPFx detects such a file and will copy it to the ‘lib’ folder automatically.

Preparing Webpack

The next step is to make webpack aware of our custom font files because it cannot handle files other than JavaScript by default. For custom font files, we need a simple file loader is enough. To install the webpack file loader add the following dependency.

npm install file-loader --save-dev

The next step is to make the SPFx build chain aware that we want to use and additional loader. For this edit the gulp file in the root of your project.

'use strict';

const build = require('@microsoft/sp-build-web');

build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);

// Font loader configuration for webfonts
const fontLoaderConfig = {
  test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
  use: [{
    loader: 'file-loader',
    options: {
      name: '[name].[ext]',
      outputPath: 'fonts/'
    }
  }]
};

// Merge custom loader to web pack configuration
build.configureWebpack.mergeConfig({
  additionalConfiguration: (generatedConfiguration) => {

    generatedConfiguration.module.rules.push(fontLoaderConfig);

    return generatedConfiguration;

  }

});

build.initialize(require('gulp'));

The fontLoaderConfig-variable define which files extensions we like to handle with the file-loader. In our case, only font files. In the ‘build.configureWebpart’ the section we merge then the configuration to the already SPFx predefined webpack configuration. We finished now the core setup to handle custom web fonts.

Make use of web fonts in the webpart

To use the fonts I placed already the font files in the src folder directly but now if we reference it directly from our web part we run into an error. All data in the ‘src’ folder that do not contain any code get ignored by the build chain.

To change that I created an additional folder named styles. This folder contains all global style definitions for all web parts in the solution.

Fonts placed under ‘src/fonts’

In this folder then I created a file name ‘_fonts.scss’. Files in SASS with an underscore up front are also known as partial files. Partial files only get compiled when referenced by another SASS file without the underscore prefix.

@font-face {
  font-family: 'Permanent Marker';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: local('Permanent Marker Regular'), 
       local('PermanentMarker-Regular'), 
       url(../fonts/PermanetMarker-Regular.woff2) format('woff2');
  unicode-range: 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, U+FFFD;
}

In this file, we add the @font-face definition for our web font. The critical part here is the ‘src’ section and more specific the ‘url’. The URL needs to point to our font file in the fonts folder. Your @font-face definition might look different depending on the font you use.

Add @font-face to web part

Now up to the webpart code. In the style sheet of the webpart, the use of this font definition, we need to ‘@import’ the partial file from ‘src/styles’.

@import '~office-ui-fabric-react/dist/sass/References.scss';

// imports @font-face definiton
@import '../../../styles/font';

.permanentMarker {

  // Make use of our custom font
  font-family: 'Permanent Marker';
  font-size: 2em;

}

The CSS of this demo webpart is just text with a single surrounding style sheet class, and we can assign the name of the web font to the font-family property.

Webpart renders custom font in local workbench

Webpart renders custom font in local workbench

That is all to get any custom font running.

The build and file location

Finally, let’s take a look at the file cycle of our font file.
First, we placed it in the ‘src’ folder.

font in src folder

font file in src folder

Via the ‘copy-static-assets.json’ file it will automatically move to the ‘lib’ folder.

Font file transferred to the lib folder

Font file transferred to the lib folder

The webpack file-loader pick up the font file and transfer it to the ‘dist’ folder.

Font file transferred by webpack

Font file transferred by webpack

Now when we bundle and package the solution, this font file also is part of our ‘.sppkg’ file.

Rendering of custom font in SharePoint Online

Rendering of custom font in SharePoint Online

Now we are ready to load any custom web font on any SharePoint page.

Personally, I think the best way still is to host web fonts from a CDN, a public or private one, but sometimes you have a specific need to add just a single font to your design. This way you can accomplish this without a problem.

CategoryUncategorized

2 Comments

  1. Hey, I liked your post, but following step by step i still got a error.
    When I bundle my solution this message is shown:
    Error – [webpack] ‘dist’:
    ./lib/webparts/customFontUsage/components/CustomFontUsage.module.css (./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/src??postcss!./lib/webparts/customFontUsage/components/CustomFontUsage.module.css)
    Module not found: Error: Can’t resolve ‘../fonts/sansr.woff’ in ‘C:/Repos/spfx/SpfxDemos/custom-font-usage/lib/webparts/customFontUsage/components’
    resolve ‘../fonts/sansr.woff’ in ‘C:/Repos/spfx/SpfxDemos/custom-font-usage/lib/webparts/customFontUsage/components’ using description file: C:/Repos/spfx/SpfxDemos/custom-font-usage/package.json (relative path: ./lib/webparts/customFontUsage/components)
    Field ‘browser’ doesn’t contain a valid alias configuration using description file: C:/Repos/spfx/SpfxDemos/custom-font-usage/package.json (relative path: ./lib/webparts/customFontUsage/fonts/sansr.woff)no extension

    And when I manually put the font file in the folder:
    Error – [copy-assets] Webpack-produced asset “fonts/ctgsansr.woff” does not appear to have a checksum in its filename, meaning that it
    is not safe to deploy to the CDN.

    Reply

  2. I followed this working fine on workbranch but when trying gulp bundle –ship has error like below

    Error – [copy-assets] Webpack-produced asset “fonts/Apercu-Regular.eot” does not appear to have a checksum in its filename, meaning that it is not safe to
    deploy to the CDN.

    please help what i have to do?

    Reply

Leave a Reply

Required fields are marked *.


This site uses Akismet to reduce spam. Learn how your comment data is processed.