如何为Storybook 6.5.5版本通过@font-face添加自定义字体?
Storybook自定义字体无法加载的排查与解决
问题描述
尝试了多种为Storybook添加自定义字体的方案均未成功,目前在.storybook目录下配置了以下文件,字体文件存储在src/styles/目录,因已有main.js故未添加方案要求的config.js:
1. webpack.config.js
const path = require('path'); module.exports = async ({ config }) => { // fonts config.module.rules.push({ test: /\.(png|woff|woff2|eot|ttf|svg)$/, use: [ { loader: 'file-loader', options: { name: '[name].[ext]', }, }, ], include: path.resolve(__dirname, '../'), }); return config; };
2. preview.head.html
<style type="text/css"> @font-face { font-family: 'Eina'; src: url('../src/styles/Eina03-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Eina'; src: url('../src/styles/Eina03-SemiBold.ttf') format('truetype'); font-weight: 600; font-style: normal; } @font-face { font-family: 'Eina'; src: url('../src/styles/Eina03-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; } </style>
3. main.js
const path = require('path'); module.exports = { stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], staticDirs: ['../public', '../public/fonts'], addons: [ '@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions', { name: '@storybook/addon-postcss', options: { postcssLoaderOptions: { implementation: require('postcss'), }, }, }, ], framework: '@storybook/react', core: { builder: 'webpack5', }, webpackFinal: async config => { config.module.rules.push({ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'], include: path.resolve(__dirname, '../'), }); return config; }, };
解决方案
1. 移除冗余的webpack.config.js
你使用的是Webpack 5,Storybook的main.js中webpackFinal已可处理所有webpack配置,单独的webpack.config.js会导致规则冲突,直接删除该文件,将字体处理规则合并到main.js的webpackFinal中。
2. 适配Webpack5的字体资源规则
Webpack5内置资源模块,无需file-loader,改用asset/resource:
修改main.js的webpackFinal部分:
webpackFinal: async config => { // 处理scss config.module.rules.push({ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'], include: path.resolve(__dirname, '../'), }); // 处理字体资源 config.module.rules.push({ test: /\.(woff|woff2|eot|ttf|svg)$/i, type: 'asset/resource', generator: { filename: 'fonts/[name][ext]' }, include: path.resolve(__dirname, '../src/styles'), }); return config; },
3. 修正preview.head.html中的字体路径
Webpack会将字体打包到输出目录的fonts文件夹下,调整路径为相对Storybook预览页面的地址:
<style type="text/css"> @font-face { font-family: 'Eina'; src: url('./fonts/Eina03-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Eina'; src: url('./fonts/Eina03-SemiBold.ttf') format('truetype'); font-weight: 600; font-style: normal; } @font-face { font-family: 'Eina'; src: url('./fonts/Eina03-Bold.ttf') format('truetype'); font-weight: 700; font-style: normal; } </style>
4. 全局应用字体
在.storybook/preview.js中引入项目全局样式文件(若有),确保字体在所有Story中生效:
import '../src/styles/global.scss';
全局样式示例:
body { font-family: 'Eina', sans-serif; }
5. 清理缓存并重启Storybook
执行命令清理缓存后重启,避免旧配置干扰:
npx storybook --no-manager-cache
内容的提问来源于stack exchange,提问作者Anika
相关产品推荐
相关产品推荐

