Post contents
While working on my company's shared component system, I got a request from our design team. They wanted to keep our branding consistent with internal documents and other assets. As such, they requested we use a font called "Stirling Foundry".
While we're prepping our shared component system for an open-source release to the public, we quickly acknowledged that we couldn't possibly ship this font with the package we intend for public publishing due to it's licensing and cost.
However, we have multiple teams that rely on our shared component system, and we don't want to have to copy+paste the relevant @font-face
definition or font files. What was our solution? Ship a second npm
package (in our internal npm
registry) that contained all of our private assets - including font files.
Let's walk through how we did that.
Setup Assets Package
As we're wanting to ship our packages separately, we opted for two Git repositories for the component system and private assets. In a new repository, I have the following for the package.json
:
{ "name": "ecp-private-assets", "version": "1.0.0", "main": "index.js", "scripts": { "release": "standard-version" }, "devDependencies": { "@commitlint/cli": "^11.0.0", "@commitlint/config-angular": "^11.0.0", "husky": "^4.3.0", "standard-version": "^9.0.0" }, "husky": { "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } }, "commitlint": { "extends": [ "@commitlint/config-angular" ] }}
While this package will not maintain code, I still believe it important to maintain a semver for the package. If a path of the package changes, the semver will communicate that with your package's consumers alongside the changeling. As such, this package.json
utilizes Conventional Commit and commitlint
to auto-generate changelogs and maintain history version.
Add Font Files
The "Foundry Stirling" font that I'm shipping is a combination of 7 .otf
files. I start by creating a fonts
directory. Inside that directory, I place the .otf
files in the fonts
directory.
Once done, your project repo should look something like this:
.
├── CHANGELOG.md
├── README.md
├── fonts
│ ├── foundry_sterling_bold.otf
│ ├── foundry_sterling_book.otf
│ ├── foundry_sterling_book_italic.otf
│ ├── foundry_sterling_demi.otf
│ ├── foundry_sterling_extra_bold.otf
│ ├── foundry_sterling_light.otf
│ └── foundry_sterling_medium.otf
├── index.js
├── package-lock.json
└── package.json
@font-face
CSS Definition
Now that we have the fonts in their place, we need to create a common foundry_stirling.css
file to access those fonts from CSS.
Because we're planning on using Angular CLI, we'll want to set the src
property to be prefixed with /assets/
, since that's where Angular sends it's assets.
/* foundry_stirling.css */@font-face { font-family: 'Foundry Sterling'; font-style: normal; /* Light */ font-weight: 300; src: local('Foundry Sterling Light'), local('FoundrySterling-light'), url("/assets/foundry_sterling_light.otf") format('opentype')}/* ... */@font-face { font-family: 'Foundry Sterling'; font-style: normal; /* Extra-Bold */ font-weight: 800; src: local('Foundry Sterling Extra Bold'), local('FoundrySterling-extra-bold'), url("/assets/foundry_sterling_extra_bold.otf") format('opentype')}
While we're using CSS here, if you wanted to set the
src
to a different location for non-Angular projects, you could use a SCSS@mixin
to define the@font-face
declarations with a customizable$base_path
.@mixin foundry_sterling($base_path) {@font-face { font-family: 'Foundry Sterling'; font-style: normal; /* Extra-Bold */ font-weight: 800; src: url("#{$base_path}/foundry_sterling_extra_bold.otf") format('opentype')}// ... Other @font-face declarations}
Then, when consuming the package in your client-side app, you'll want to use something like this:
@include foundry_sterling("/assets")
Font Name Value Mapping
Because our font had multiple files to declare the different CSS values weights, we had to declare the @font-face
for each of the font files. This is the mapping we used:
Value | Common weight name | Related File |
---|---|---|
100 | Thin / Hairline | N/A |
200 | Extra-Light / Ultra-Light | N/A |
300 | Light | foundry_sterling_light.otf |
400 | Normal / Regular | foundry_sterling_book.otf |
500 | Medium | foundry_sterling_medium.otf |
600 | Semi-Bold / Demi-Bold | foundry_sterling_demi.otf |
700 | Bold | foundry_sterling_bold.otf |
800 | Extra-Bold / Ultra-Bold | foundry_sterling_extra_bold.otf |
900 | Black / Heavy | N/A |
Consume Assets Package in Angular CLI
Now that we have our npm
package configured for usage, we'll start preparing for consuming that package by installing it into our app's package.json
:
npm i ecp-private-assets
Remember,
ecp-private-assets
is the name of our internal package. You'll need to replace thisnpm i
command with your own package name
angular.json
modification
Once this is done, two steps are required. First, add the following to angular.json
's assets
property. This will copy the files from ecp-private-assets
to /assets
once you setup a build.
{ "glob": "**/*", "input": "./node_modules/ecp-private-assets/fonts", "output": "./assets/"}
This way, when we use the CSS url('/assets/')
, it will point to our newly appointed fonts
files. Once this is added, your angular.json
should look like this:
{ "architect": { "build": { "builder": "@angular-builders/custom-webpack:browser", "options": { "customWebpackConfig": { "path": "./webpack.config.js" }, "outputPath": "www", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", "aot": true, "assets": [ "src/assets", { "glob": "**/*", "input": "./node_modules/ecp-private-assets/fonts", "output": "./assets/" } ], "styles": [ "src/main.scss" ], "scripts": [] } } }}
Import CSS
Now that we have our assets in place, we need to import the CSS file into our app.
If your app utilizes postcss
's import
plugin or if you're using vanilla CSS, add the following line to your main.scss
file:
@import "ecp-private-assets/fonts/foundry_sterling.css";
Remember to keep the
@import
s at the top of your file, as you will receive an error otherwise.
However, if you're not using postcss
and have SCSS installed, you can use the following:
@import '~ecp-private-assets/fonts/foundry_sterling.css';
Conclusion
Once you've added the file to your CSS imports and angular.json
, you should see your font loading as-expected. Because you've setup your fonts to use npm
to distribute them, you can now reuse your fonts across multiple apps.
If you'd like to learn more or have questions about this setup, feel free to leave a comment down below or join our Discord and ask questions there!