You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Storybook集成Quasar时字体加载路径出现undefined的问题求助

Storybook集成Quasar时字体加载失败问题

问题现象

开发者工具中字体请求路径包含undefined前缀:

http://localhost:6006/undefined/node_modules/@quasar/extras/roboto-font/web-font/KFOmCnqEu92Fr1Mu4mxM.woff

查看编译后的CSS文件,发现原相对路径被替换为undefined/node_modules/...:

import {createHotContext as __vite__createHotContext} from "/@vite/client";
import.meta.hot = __vite__createHotContext("/node_modules/@quasar/extras/roboto-font/roboto-font.css");
import {updateStyle as __vite__updateStyle, removeStyle as __vite__removeStyle} from "/@vite/client"
const __vite__id = "/var/www/html/node_modules/@quasar/extras/roboto-font/roboto-font.css"
const __vite__css = "@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 100;\n  src: url(undefined/node_modules/@quasar/extras/roboto-font/web-font/KFOkCnqEu92Fr1MmgVxIIzQ.woff) format('woff');\n}\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 300;\n  src: url(undefined/node_modules/@quasar/extras/roboto-font/web-font/KFOlCnqEu92Fr1MmSU5fBBc-.woff) format('woff');\n}\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 400;\n  src: url(undefined/node_modules/@quasar/extras/roboto-font/web-font/KFOmCnqEu92Fr1Mu4mxM.woff) format('woff');\n}\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 500;\n  src: url(undefined/node_modules/@quasar/extras/roboto-font/web-font/KFOlCnqEu92Fr1MmEU9fBBc-.woff) format('woff');\n}\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 700;\n  src: url(undefined/node_modules/@quasar/extras/roboto-font/web-font/KFOlCnqEu92Fr1MmWUlfBBc-.woff) format('woff');\n}\n@font-face {\n  font-family: 'Roboto';\n  font-style: normal;\n  font-weight: 900;\n  src: url(undefined/node_modules/@quasar/extras/roboto-font/web-font/KFOlCnqEu92Fr1MmYUtfBBc-.woff) format('woff');\n}\n"
__vite__updateStyle(__vite__id, __vite__css)
import.meta.hot.accept()
export default __vite__css
import.meta.hot.prune(()=>__vite__removeStyle(__vite__id))

而@quasar/extras/roboto-font/roboto-font.css原文件中字体路径为相对路径:

@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 100;
  src: url(./web-font/KFOkCnqEu92Fr1MmgVxIIzQ.woff) format('woff');
}
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 300;
  src: url(./web-font/KFOlCnqEu92Fr1MmSU5fBBc-.woff) format('woff');
}
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 400;
  src: url(./web-font/KFOmCnqEu92Fr1Mu4mxM.woff) format('woff');
}
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 500;
  src: url(./web-font/KFOlCnqEu92Fr1MmEU9fBBc-.woff) format('woff');
}
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 700;
  src: url(./web-font/KFOlCnqEu92Fr1MmWUlfBBc-.woff) format('woff');
}
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 900;
  src: url(./web-font/KFOlCnqEu92Fr1MmYUtfBBc-.woff) format('woff');
}

该问题仅在执行npm run storybook时出现,npm run dev环境下字体加载正常。

相关配置文件

.storybook/main.js

/** @type { import('@storybook/vue3-vite').StorybookConfig } */
const config = {
  stories: [
    "../**/*.mdx",
    "../**/*.stories.@(js|jsx|mjs|ts|tsx)",
  ],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  framework: {
    name: "@storybook/vue3-vite",
    options: {},
  },
  staticDirs: ['../node_modules'],
  docs: {
    autodocs: false,
  }
};
export default config;

.storybook/preview.js

import { setup } from '@storybook/vue3';
import { Quasar } from 'quasar';

// Import icon libraries
import '@quasar/extras/roboto-font/roboto-font.css'
import '@quasar/extras/material-icons/material-icons.css'
import '@quasar/extras/material-symbols-outlined/material-symbols-outlined.css'
import '@quasar/extras/fontawesome-v6/fontawesome-v6.css'
import '@quasar/extras/line-awesome/line-awesome.css'

// Import Quasar css
import 'quasar/src/css/index.sass'

import '../resources/css/app.css'

/** @type { import('@storybook/vue3').Preview } */
const preview = {
  parameters: {
    actions: { argTypesRegex: "^on[A-Z].*" },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
};

export default preview;

setup((app) => {
    app.use(Quasar, {config: {}, directives: {}})
    app.config.globalProperties.$storybook = true;
});

package.json

{
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  },
  "devDependencies": {
    "@inertiajs/vue3": "^1.0.0",
    "@quasar/vite-plugin": "^1.3.0",
    "@storybook/addon-essentials": "^7.5.0",
    "@storybook/addon-interactions": "^7.5.0",
    "@storybook/addon-links": "^7.5.0",
    "@storybook/blocks": "^7.5.0",
    "@storybook/testing-library": "^0.2.2",
    "@storybook/vue3": "^7.5.0",
    "@storybook/vue3-vite": "^7.5.0",
    "@vitejs/plugin-vue": "^4.0.0",
    "autoprefixer": "^10.4.12",
    "axios": "^1.1.2",
    "laravel-vite-plugin": "^0.7.2",
    "lodash": "^4.17.19",
    "postcss": "^8.4.18",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "sass": "^1.32.12",
    "storybook": "^7.5.0",
    "vite": "^4.0.0",
    "vue": "^3.2.41"
  },
  "dependencies": {
    "@quasar/extras": "^1.16.7",
    "quasar": "^2.13.0",
    "vue-i18n": "^9.2.2"
  }
}

解决方案

方案1:配置Quasar Vite插件到Storybook

修改.storybook/main.js,添加viteFinal配置,引入Quasar的Vite插件,确保资源路径被正确解析:

/** @type { import('@storybook/vue3-vite').StorybookConfig } */
import { quasar, transformAssetUrls } from '@quasar/vite-plugin';

const config = {
  stories: [
    "../**/*.mdx",
    "../**/*.stories.@(js|jsx|mjs|ts|tsx)",
  ],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  framework: {
    name: "@storybook/vue3-vite",
    options: {},
  },
  staticDirs: ['../node_modules'],
  docs: {
    autodocs: false,
  },
  viteFinal: async (config) => {
    // 添加Quasar Vite插件
    config.plugins.push(
      quasar({
        // 若有自定义Quasar变量文件可配置,无则删除此行
        sassVariables: 'src/quasar-variables.sass'
      })
    );
    // 配置Vue的资源转换规则
    config.vue = {
      template: {
        transformAssetUrls,
      },
    };
    return config;
  },
};
export default config;

方案2:修改字体导入为绝对路径

在.storybook/preview.js中,将字体CSS的导入改为从静态资源根路径引入:

// 替换原有的字体导入语句
import '/node_modules/@quasar/extras/roboto-font/roboto-font.css'
import '/node_modules/@quasar/extras/material-icons/material-icons.css'
import '/node_modules/@quasar/extras/material-symbols-outlined/material-symbols-outlined.css'
import '/node_modules/@quasar/extras/fontawesome-v6/fontawesome-v6.css'
import '/node_modules/@quasar/extras/line-awesome/line-awesome.css'

确保.storybook/main.js中的staticDirs已配置为['../node_modules'],Storybook会将node_modules作为静态资源目录,字体文件可被正确访问。

方案3:配置Vite路径别名

在.storybook/main.js的viteFinal中添加路径别名,帮助Vite正确解析Quasar资源路径:

viteFinal: async (config) => {
  config.resolve = config.resolve || {};
  // 添加路径别名
  config.resolve.alias = {
    ...config.resolve.alias,
    '@quasar/extras': '../node_modules/@quasar/extras'
  };
  return config;
}

验证

修改配置后重启Storybook,查看开发者工具中的字体请求路径,正常路径应为:

http://localhost:6006/node_modules/@quasar/extras/roboto-font/web-font/KFOmCnqEu92Fr1Mu4mxM.woff

此时字体应能正常加载。


内容的提问来源于stack exchange,提问作者prodigy7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 13:49:51