Fonts
Assets management story in webpack completes with fonts. Just like images, fonts are content assets with their own life cycle. The main difference is that fonts are referenced from CSS and used to alter font faces of the text displayed to the user.
Before we dive deep into fonts management, it is worth revisiting out folder structure of the final output to see how different types of assets fit together.
Destination folder structure
Our webpack journey started with JavaScript assets. The configuration was set up to save all of them into the js
folder under dist
. The rest of the folders were relative to the js
one. Now, with all the assets in place, the output structure looks like this:
project
└───dist
│ favicon.ico
│ index.html
| ...
|
└───css
| │ feature.css
| │ main.css
| │ ...
|
└───fonts
| │ open-sans-latin-300.woff
| │ open-sans-latin-700.woff
| │ ...
|
└───img
| | logo1.png
|
└───js
| feature.bundle.js
| feature.bundle.js.map
| main.bundle.js
| main.bundle.js.map
| ...
This structure has pros and cons. It makes the dist
directory look clean by having only necessary items and everything else in a separate sub-folder. On the other hand, all the webpack configs are relative to js
folder. That might be a bit confusing and also there are unnecessary relative path references in the generated index.html file.
<link href="/js/../css/main.css" rel="stylesheet"></head>
Let's fix the configuration in a way that all the assets are put in the appropriate folders as above but there is no relative path references involved in the final output. We are going to go with more standard webpack setup where JavaScript assets are placed under the root of the destination location.
project
└───dist
│ favicon.ico
| feature.bundle.js
| feature.bundle.js.map
│ index.html
| main.bundle.js
| main.bundle.js.map
| ...
|
└───css
| │ feature.css
| │ main.css
| │ ...
|
└───fonts
| │ open-sans-latin-300.woff
| │ open-sans-latin-700.woff
| │ ...
|
└───img
| | logo1.png
|
Webpack configuration
webpack/parts.ts
Change webpack/parts.ts
output: {
path: folders.dist(),
filename: '[name].bundle.js',
publicPath: '/'
} as Output
// ...
{
test: /\.(png|jpg|gif|bmp)$/,
exclude: /favicons/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: './img/[name].[ext]',
}
}]
}
In the output
section we changed the publicPath
to be the root of the project and the path
itself to point to the dist
folder. We also changed output paths for favicons and images from relative to js
to relative to /
. Similar change happened to the index.html
file path.
webpack/webpack.config.dev.ts
Change webpack/webpack.config.dev.ts
plugins: parts.plugins.concat(
new CopyPlugin([{
from: '../assets/fonts/**/*',
to: path.resolve(folders.dist(), 'assets')
}])
)
In a dev mode we are only making sure that font files are copied to the output folder from the assets
folder.
webpack/webpack.config.ts
Change webpack/webpack.config.ts
{
test: /\.(woff|woff2)$/,
use: [{
loader: 'file-loader',
options: {
name: './fonts/[name].[ext]'
}
}]
}
// ...
new MiniCssExtractPlugin({
filename: 'css/[name].css',
chunkFilename: 'css/[name].css',
}),
// ...
In production mode we are piping up font files via the file-loader with the specific font file extensions. We also changed CSS files output path to be root relative.
Sources
src/app/index.pcss
Change src/app/index.pcss
body {
background-color: azure;
font-family: Open Sans;
font-weight: 300;
}
@font-face {
font-family: Open Sans;
font-style: normal;
font-display: swap;
font-weight: 300;
src: url(../../assets/fonts/open-sans/open-sans-latin-300.woff2) format("woff2"), url(../../assets/fonts/open-sans/open-sans-latin-300.woff) format("woff");
}
@font-face {
font-family: Open Sans;
font-style: normal;
font-display: swap;
font-weight: 700;
src: url(../../assets/fonts/open-sans/open-sans-latin-700.woff2) format("woff2"), url(../../assets/fonts/open-sans/open-sans-latin-700.woff) format("woff");
}
We introduced two font faces. They both point to assets/fonts
folder for the respective font files for all the available formats. The last step is to introduce font families in the appropriate styles (in this case body styles).
font-face
references physical font file from the assets folder using relative path value for thesrc
property. The path is relative to the file where styles are defined, in this casesrc/app/index.pcss