Proper Way To Add Fonts To Sage 9 Theme

Hi Dan. I copied the font files into:

Resources > Assets > Fonts [here]

I wanted to post the error log but I’m only allowed a certain number of links as a new poster so all of the localhost links in the error log count against that.

I expected ‘Yarn Build’ to at least create a fonts folder under dist but as that isn’t happening I feel something is amiss? Maybe with webpack.

Hey Strarsis. Thank you. Are you saying I shouldn’t go the ‘local link’ route to files I’m using and instead combine wp_resource_hints with a link to the google hosted version of these fonts? Is there a singular recommended way to do this? Sorry, I’m new to Sage but I feel like I’m going a little crazy executing this super simple step and it still doesn’t seem to be working.

Locally hosted fonts can also improve performance of course. It depends.
So you planned to host the Google font files yourself? This is easy as all browsers support WOFF/WOFF2 now.

1 Like

I was planning on hosting them myself. But as someone who has learned web development the autodidact route I always have a sneaking suspicion that I’m not doing something “best practice” so like to get guidance from those who know more. I think a lot of folks out there have holes in the basics for similar reasons. But great to know about prefetch/reload resources in wp for hosting fonts from links.

Btw - I just resolved my issue! I think… Perhaps I missed something but it looks like webpack doesn’t understand local file paths like " …/ " and when I replaced those double dots simply with a tilda “~” it fixed the issue and compiled correctly. Elsewhere in this forum, everyone was advising the relative path for local font files. Like I said, I am far from an expert so maybe this was obvious to others. Dist folder is still not generating a “fonts” folder on ‘yarn build’ however.

laravel-mix which Sage 10 uses and that generates a webpack configuration process URLs by default:
https://laravel.com/docs/8.x/mix#url-processing
However, in Sage 10 this is disabled because of performance reasons and because it isn’t used as often:

You can re-enable it by commenting out that line for example.

It should copy the fonts to public by default:

So even without URL processing enabled you can use the right relative path (relative to the stylesheet) and it should also load properly.

1 Like

That’s good to know!

Any idea why ‘yarn build’ still isn’t creating a ‘fonts’ folder? I just checked and looks like I’m on a 9.0.10 version of Sage and not version 10. Sorry about that. Could have sworn I updated. I’m assuming this is an issue with the version i’m using, right?

If you’re using Sage 9, it doesn’t use mix so the above code isn’t relevant to you.

Sage 9 uses a webpack build process that will only compile assets that are used–i.e. they are referenced somewhere. From your description, you’ve only set up some font-face rules–you never actually reference those fonts in your SCSS, so when webpack runs it determines you aren’t actually using them and doesn’t build them. Try putting a font-family rule in your scss that references the fonts.

Thanks alwaysblank and again, apologies for the version mixup. I am currently referencing font-family in my main.scss file like so:

body { background: transparent; font-family: "Roboto", sans-serif; }

and importing the whole of fonts.scss (which I created under ‘resources’ containing this:

/* roboto-regular - latin */ @font-face { font-family: "Roboto", sans-serif; font-style: normal; font-weight: 400; src: url("~/fonts/roboto-v29-latin-regular.eot"); /* IE9 Compat Modes */ src: local(""), url("~/fonts/roboto-v29-latin-regular.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */ url("~/fonts/roboto-v29-latin-regular.woff2") format("woff2"), /* Super Modern Browsers */ url("~/fonts/roboto-v29-latin-regular.woff") format("woff"), /* Modern Browsers */ url("~/fonts/roboto-v29-latin-regular.ttf") format("truetype"), /* Safari, Android, iOS */ url("~/fonts/roboto-v29-latin-regular.svg#Roboto") format("svg"); /* Legacy iOS */ }

Then added @import "common/fonts"; to my main.scss file.

Am I doing this right? Still no fonts in dist.

I’m unclear why you’re doing this:

url("~/fonts/roboto-v29-latin-regular.ttf")

A tilde is going to resolve to either your user’s home directory or node_modules in your current project, neither of which are likely to contain your fonts. IIRC they should us some kind of relative file path, i.e. url('../fonts/roboto-v29-latin-regular.ttf'). I checked a couple old Sage 9 themes, and their font paths are ../fonts/font-name.ttf so that should work. If the tilde is silencing your error, it doesn’t seem to be because that provides a path to the font.

You are totally right. Strangely, the link in head started mysteriously working and displaying ‘Roboto’. At least i have a solution to move forward with a direct link to google fonts in the head. But I still don’t understand why using relative file path does not work and throws errors.

Can you post the text of the errors and your configuration? It’s difficult to debug w/o those things.

Yes - sorry about that. Initially, I couldn’t post many links due to new membership restrictions.

My configuration is:

{
  "name": "sage",
  "version": "9.0.10",
  "author": "Roots <team@roots.io>",
  "homepage": "https://roots.io/sage/",
  "private": true,
  "repository": {
    "type": "git",
    "url": "git://github.com/roots/sage.git"
  },
  "bugs": {
    "url": "https://github.com/roots/sage/issues"
  },
  "licenses": [
    {
      "type": "MIT",
      "url": "http://opensource.org/licenses/MIT"
    }
  ],
  "browserslist": [
    "last 2 versions",
    "android 4",
    "opera 12"
  ],
  "scripts": {
    "build": "webpack --progress --config resources/assets/build/webpack.config.js",
    "build:production": "webpack --env.production --progress --config resources/assets/build/webpack.config.js",
    "build:profile": "webpack --progress --profile --json --config resources/assets/build/webpack.config.js",
    "start": "webpack --hide-modules --watch --config resources/assets/build/webpack.config.js",
    "rmdist": "rimraf dist",
    "lint": "npm run -s lint:scripts && npm run -s lint:styles",
    "lint:scripts": "eslint resources/assets/scripts resources/assets/build",
    "lint:styles": "stylelint \"resources/assets/styles/**/*.{css,sass,scss,sss,less}\"",
    "test": "npm run -s lint"
  },
  "engines": {
    "node": ">= 8.0.0"
  },
  "devDependencies": {
    "autoprefixer": "^10.0.1",
    "browser-sync": "^2.26.13",
    "browsersync-webpack-plugin": "^0.6.0",
    "bs-html-injector": "~3.0",
    "buble-loader": "^0.4.1",
    "cache-loader": "~1.2.5",
    "clean-webpack-plugin": "^0.1.18",
    "copy-globs-webpack-plugin": "^0.2.0",
    "css-loader": "^0.28.11",
    "cssnano": "^4.0.5",
    "eslint": "~4.19.1",
    "eslint-loader": "^4.0.2",
    "eslint-plugin-import": "^2.14.0",
    "extract-text-webpack-plugin": "~3.0.2",
    "file-loader": "^6.2.0",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "imagemin-mozjpeg": "^9.0.0",
    "imagemin-webpack-plugin": "^2.4.2",
    "import-glob": "~1.5",
    "node-sass": "^5.0.0",
    "postcss-loader": "^4.0.4",
    "postcss-safe-parser": "^5.0.2",
    "resolve-url-loader": "^3.1.2",
    "rimraf": "^3.0.2",
    "sass-loader": "~6.0",
    "style-loader": "^0.23.1",
    "stylelint": "^13.7.2",
    "stylelint-config-standard": "^20.0.0",
    "stylelint-webpack-plugin": "^0.10.5",
    "uglifyjs-webpack-plugin": "^1.3.0",
    "url-loader": "^4.1.1",
    "webpack": "~3.10.0",
    "webpack-assets-manifest": "^1.0.0",
    "webpack-dev-middleware": "~2.0.4",
    "webpack-hot-middleware": "^2.22.3",
    "webpack-merge": "~4.1.4",
    "yargs": "^16.1.0"
  },
  "dependencies": {
    "bootstrap": "v4.3.1",
    "jquery": "^3.3.1",
    "popper.js": "^1.14.7"
  }
}

Here is what the error output is when I changed the relative paths back to “…/”

ERROR  Failed to compile with 5 errors                               2:40:27 PM

These relative modules were not found:

* ./fonts/roboto-v29-latin-regular.eot in ./node_modules/cache-loader/dist/cjs.js!./node_modules/css-loader?{"sourceMap":true}!./node_modules/postcss-loader/dist/cjs.js?{"postcssOptions":{"path":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets/build","ctx":{"open":true,"copy":"images/**/*","proxyUrl":"http://localhost:3000","cacheBusting":"[name]_[hash:8]","paths":{"root":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe","assets":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets","dist":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist"},"enabled":{"sourceMaps":true,"optimize":false,"cacheBusting":false,"watcher":true},"watch":["app/**/*.php","config/**/*.php","resources/views/**/*.php"],"entry":{"main":["./scripts/main.js","./styles/main.scss"],"customizer":["./scripts/customizer.js"]},"publicPath":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist/","devUrl":"http://localhost:8888/jameslanmandotcom","env":{"production":false,"development":true},"manifest":{}}},"sourceMap":true}!./node_modules/resolve-url-loader?{"sourceMap":true}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true,"sourceComments":true}!./node_modules/import-glob!./resources/assets/styles/main.scss
* ./fonts/roboto-v29-latin-regular.svg in ./node_modules/cache-loader/dist/cjs.js!./node_modules/css-loader?{"sourceMap":true}!./node_modules/postcss-loader/dist/cjs.js?{"postcssOptions":{"path":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets/build","ctx":{"open":true,"copy":"images/**/*","proxyUrl":"http://localhost:3000","cacheBusting":"[name]_[hash:8]","paths":{"root":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe","assets":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets","dist":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist"},"enabled":{"sourceMaps":true,"optimize":false,"cacheBusting":false,"watcher":true},"watch":["app/**/*.php","config/**/*.php","resources/views/**/*.php"],"entry":{"main":["./scripts/main.js","./styles/main.scss"],"customizer":["./scripts/customizer.js"]},"publicPath":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist/","devUrl":"http://localhost:8888/jameslanmandotcom","env":{"production":false,"development":true},"manifest":{}}},"sourceMap":true}!./node_modules/resolve-url-loader?{"sourceMap":true}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true,"sourceComments":true}!./node_modules/import-glob!./resources/assets/styles/main.scss
* ./fonts/roboto-v29-latin-regular.ttf in ./node_modules/cache-loader/dist/cjs.js!./node_modules/css-loader?{"sourceMap":true}!./node_modules/postcss-loader/dist/cjs.js?{"postcssOptions":{"path":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets/build","ctx":{"open":true,"copy":"images/**/*","proxyUrl":"http://localhost:3000","cacheBusting":"[name]_[hash:8]","paths":{"root":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe","assets":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets","dist":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist"},"enabled":{"sourceMaps":true,"optimize":false,"cacheBusting":false,"watcher":true},"watch":["app/**/*.php","config/**/*.php","resources/views/**/*.php"],"entry":{"main":["./scripts/main.js","./styles/main.scss"],"customizer":["./scripts/customizer.js"]},"publicPath":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist/","devUrl":"http://localhost:8888/jameslanmandotcom","env":{"production":false,"development":true},"manifest":{}}},"sourceMap":true}!./node_modules/resolve-url-loader?{"sourceMap":true}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true,"sourceComments":true}!./node_modules/import-glob!./resources/assets/styles/main.scss
* ./fonts/roboto-v29-latin-regular.woff in ./node_modules/cache-loader/dist/cjs.js!./node_modules/css-loader?{"sourceMap":true}!./node_modules/postcss-loader/dist/cjs.js?{"postcssOptions":{"path":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets/build","ctx":{"open":true,"copy":"images/**/*","proxyUrl":"http://localhost:3000","cacheBusting":"[name]_[hash:8]","paths":{"root":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe","assets":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets","dist":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist"},"enabled":{"sourceMaps":true,"optimize":false,"cacheBusting":false,"watcher":true},"watch":["app/**/*.php","config/**/*.php","resources/views/**/*.php"],"entry":{"main":["./scripts/main.js","./styles/main.scss"],"customizer":["./scripts/customizer.js"]},"publicPath":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist/","devUrl":"http://localhost:8888/jameslanmandotcom","env":{"production":false,"development":true},"manifest":{}}},"sourceMap":true}!./node_modules/resolve-url-loader?{"sourceMap":true}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true,"sourceComments":true}!./node_modules/import-glob!./resources/assets/styles/main.scss
* ./fonts/roboto-v29-latin-regular.woff2 in ./node_modules/cache-loader/dist/cjs.js!./node_modules/css-loader?{"sourceMap":true}!./node_modules/postcss-loader/dist/cjs.js?{"postcssOptions":{"path":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets/build","ctx":{"open":true,"copy":"images/**/*","proxyUrl":"http://localhost:3000","cacheBusting":"[name]_[hash:8]","paths":{"root":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe","assets":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/resources/assets","dist":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist"},"enabled":{"sourceMaps":true,"optimize":false,"cacheBusting":false,"watcher":true},"watch":["app/**/*.php","config/**/*.php","resources/views/**/*.php"],"entry":{"main":["./scripts/main.js","./styles/main.scss"],"customizer":["./scripts/customizer.js"]},"publicPath":"/Applications/MAMP/htdocs/jameslanmandotcom/wp-content/themes/Circe/dist/","devUrl":"http://localhost:8888/jameslanmandotcom","env":{"production":false,"development":true},"manifest":{}}},"sourceMap":true}!./node_modules/resolve-url-loader?{"sourceMap":true}!./node_modules/sass-loader/lib/loader.js?{"sourceMap":true,"sourceComments":true}!./node_modules/import-glob!./resources/assets/styles/main.scss

Have you made any changes to your webpack.config.js files? Is this a fresh Sage theme, or one you’ve been working on?

New install as of October 12th but one I have been working on. No changes made to webpack.config.js file!

Have you changed the discussion title so that it includes the Sage version now?
I didn’t know you are using Sage 9, I assumed you are using Sage 10.

Yes - Alwaysblank did. Again, apologies for the confusion - I thought I had upgraded.

  1. There is a Sage 9.x update branch that fixes lots of build issues:
    Sage "9.1": Please test

  2. When you host the font yourself you will want to minify and subset the font files.
    When you are using different weights and variants of the same font you should try to use a so called variable font, which is well-supported now.

  3. It is possible to add a webpack-loader for font files but I found it much easier to optimize the font files once and then use webpack copy to just copy them over to dist. There is already stuff copied in webpack, so you just have to duplicate that code in the webpack js and adjust the glob (regexp) so it matches font files.

1 Like

Thank you Starsis! Some of this is a bit above my head but this gives me a starting point at which to use track down the info I need. I appreciate it!

Variable fonts:

Font minification/subsetting:

Copying files (Sage 9 webpack):

Adjusting the glob in config.copy is the easiest way.

1 Like

This is wonderful. Thank you!