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

Angular12+Webpack5导入CSS返回字符串而非对象,调用use方法报错

太长不看版

我在TypeScript模块中导入CSS文件,导入结果解析为字符串而非对象,请问为什么无法获取到对象?

示例代码
// preview.ts

import test from './src/assets/test.theme.css';

// 也尝试过该写法:
// import * as test from './src/assets/test.theme.css';

console.log('typeof test: ', typeof test);
console.log(test);

控制台输出
控制台截图

详细说明

我正在为我的Angular12组件库搭建Storybook。

为了提供多主题能力,我计划使用@etchteam/storybook-addon-css-variables-theme插件,其文档中使用了Webpack的内联loader语法:

import myTheme from '!!style-loader?injectType=lazyStyleTag!css-loader!./assets/my-theme.css';

我将该写法应用到自己的代码后,浏览器控制台抛出错误:

Error: myTheme.use is not a function

排查过程中我发现,导入的样式表不是可执行的JavaScript对象,而是包含style-loader生成的源码的字符串。
我还发现该问题并不局限于style-loader,css-loader、raw-loader等其他loader也会出现相同问题。
该问题也和内联loader语法无关,即便是在最简webpack配置中定义loader也可复现。

运行环境:

  • Angular 12
  • Webpack 5
复现仓库

我已搭建了复现该问题的GIT仓库,README文件中说明了复现步骤和问题详情。


问题原因

  1. Angular 12 默认在Webpack配置中加入了全局资源模块(Asset Modules)规则,所有.css后缀文件会被默认匹配到type: 'asset/source'规则,直接导出文件原始内容字符串,该规则优先级高于你自行配置的style-loader/css-loader处理链,导致你的loader没有实际生效。
  2. 你使用的双感叹号开头的内联loader语法会禁用所有前置/后置loader,和全局规则叠加后会把loader输出的JS代码再次当成纯文本导出,最终拿到的自然是字符串而非带use方法的对象。

解决方案

方案一:修改Storybook的Webpack配置(推荐)

打开.storybook/main.js,调整Webpack规则,给全局CSS规则添加排除项,单独处理主题类CSS文件:

module.exports = {
  // 其余配置保持不变
  webpackFinal: async (config) => {
    // 查找默认处理CSS的规则
    const cssRule = config.module.rules.find(rule => rule.test.toString().includes('.css'));
    // 排除你自定义的主题CSS文件,这里按你的文件名规则匹配.theme.css后缀
    cssRule.exclude = /\.theme\.css$/;

    // 新增专属主题CSS的处理规则
    config.module.rules.push({
      test: /\.theme\.css$/,
      use: [
        {
          loader: 'style-loader',
          options: {
            injectType: 'lazyStyleTag'
          }
        },
        'css-loader'
      ]
    });
    return config;
  }
}

配置完成后直接按普通方式导入即可,不需要写内联loader:

import test from './src/assets/test.theme.css';

此时导入的test对象会自带use()和unuse()方法,可直接调用切换主题。

方案二:调整内联loader写法

如果不想改全局配置,把内联loader开头的双感叹号改成单感叹号即可,单感叹号会禁用全局配置的默认资源规则,让你的loader链正常生效:

import myTheme from '!style-loader?injectType=lazyStyleTag!css-loader!./assets/my-theme.css';

补充TypeScript类型适配

添加类型声明文件避免TS报错,在项目根目录新建typings.d.ts:

declare module '*.theme.css' {
  interface LazyStyleSheet {
    use: () => void;
    unuse: () => void;
  }
  const styles: LazyStyleSheet;
  export default styles;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 19:48:01