将 css 文件导入 es6 returns 字符串而不是对象

import css file into es6 returns string instead of object

TL;DR

我正在将 css 文件导入打字稿模块,但导入解析为字符串而不是对象。谁能告诉我为什么我没有得到对象??

例子

// preview.ts

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

// also tried this:
// 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的内联加载器语法。

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

将此应用到我的代码时,我的浏览器控制台开始抱怨

Error: myTheme.use is not a function

在我的研究过程中,我发现导入的样式表不是经过评估的 javascript 对象,而是作为包含样式加载器生成的源代码的字符串提供的。

我也认识到,这个问题不是特定于样式加载器,而是所有其他加载器都会发生,例如css-加载器、原始加载器等

这个问题也与内联加载器语法无关,因为它也与在简约的 webpack 配置中定义的加载器一起出现。

环境:

复制

我设置了一个GIT repo reproducing the issue

自述文件解释了重现和问题。

我认为您的 Webpack 配置有误。你嵌套了 rules 属性,而你应该嵌套 use:

{
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  }

https://webpack.js.org/loaders/css-loader/

对不起,但我必须恢复我的最后声明。 @Akxe 的评论没有解决我的问题。 现在我的导入语句 (import * as test from '...') 解析为一个对象,但它仍然不正确。

我设置了一个GIT Repo to reproduce the issuereadme.md 文件解释了重现和问题。

看起来 Webpack 不是 executing/evaluating 加载程序的 return 值。

顺便说一句。这不仅仅是 css-loader 的情况。 raw-loader、sass-loader、style-loader 等的结果保持不变

My final goal is to lazily load my theme files into a storybook. I try to follow the documentation of the @etchteam/storybook-addon-css-variables-> theme.

我的问题终于解决了!

分析

这里的主要问题是 @angular-devkit/build-angular 包生成的 webpack 配置。我能够通过调试一个新的 angular12 应用程序来分析它(你可以查看 here)。

通过在 /node_modules/@angular-devkit/build-angular/src/utils/webpack-browser-config.js 处设置断点,函数:generateWebpackConfig(...),我可以在调试器中检查最终的 webpackConfig 对象。

相关的 rule 看起来像这样:

The important part here is the rule setting the module type to asset/source, instructing webpack not to evaluate the loader's result.

解决方案概念 1:内联加载器

alexander-kait and his great hints at this issue的帮助下, 我能够找到一个内联加载器语法来覆盖 webpack 的模块声明:

import Test from 'test.css.webpack[javascript/auto]!=!!!style-loader?injectType=lazyStyleTag!css-loader!./test.css';

console.log(typeof Test); // output: object
console.log(Test); // output: Object { use: () => void, unuse: () => void }
Test.use(); // this should usually be called by a theme switcher...

我不太确定这里的 url 模式,因为它似乎是一个未记录的功能,但我认为它类似于 <query-pattern>.webpack[<module-type>]!=!<loaders><query>.

但是,由于这是一个未记录的功能,我不太愿意使用它。

解决方案概念二:webpackConfig自定义

由于我处于故事书上下文中,因此我决定根据 storybook documentation.

自定义 webpack 配置

我的解决方案需要设置命名约定(例如 *.theme.css)。

// .storybook/main.js

module.exports = {
  webpackFinal: async (config) => {

    // exclude *.theme.css from the *.css ruleset
    config.module.rules.find(rule => '.css'.match(rule.test)).exclude = [ /\.(?:theme\.css)$/i ];

    // add a rule for *.theme.css
    config.module.rules.push({
      test: /\.(?:theme\.css)$/i,
      use: [
        { loader: 'style-loader', options: { injectType: 'lazyStyleTag' } },
        'css-loader',
      ],
    });
  },
};

有了这些规则,我现在可以简单地执行以下操作:

// preview.js

import LightTheme from './light.theme.css';
import DarkTheme from './dark.theme.css';

setupThemeSwitcher(LightTheme, DarkTheme);

Please note that the setupThemeSwitcher function is just pseudocode merely there for the example. In reality I'm using the @etchteam/storybook-addon-css-variables-theme addon...

除了我正在加载 .scss 文件外,我在故事书和这个扩展中遇到了非常相似的问题。 我简单地调整了解决方案 2 以适合我的 .scss 案例,它就像一个魅力。 我无法使解决方案 1 起作用,但如前所述,这听起来很老套,而我认为解决方案 2 更简洁。 非常感谢分享这个解决方案,我苦苦挣扎了几个小时。