angularwebpackcss-loaderwebpack-loader

import test from "css-loader!./test.css" returns string


Preface

I know close to zero about Webpack, Babel, Loaders and how they interact.

Problem description

I develop an Angular component library that I recently migrated to Angular 12. I am currently setting up Storybook for documentation. I wanted to use the Storybook plugin "@etchteam/storybook-addon-css-variables-theme" to switch between different CSS stylesheets.

Through the documentation of this plugin I found out about the webpack loader syntax, especially for lazy-loaded stylesheets, i.e.

import test from "!!style-loader?injectType=lazyStyleTag!css-loader!./test.css"

However, in the browser console I get Unhandled Promise rejection: file.use is not a function.

screenshot: browser console

I found out, that my main issue is not related to storybook, as even a simple css-loader import url returns a plain string instead of an object.

I have spent several days analysing this problem, but I'm really at my wits' end.

Environment

// tsconfig.json

// Please note: this part has been assembled from multiple files, it might contain typos...

{
  "compilerOptions": {
    "baseUrl": "./",
    "module": "es2020",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "target": "es2015",
    "allowSyntheticDefaultImports": true,
    "types": [
      "node"
    ],
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ]
  }
}

Repro

Unfortunately I was not able to setup a minimal repro with e.g. CodeSandbox. But I was able to reproduce it locally with a fresh Angular workspace:

$ npx -p @angular/cli@12 ng new css-loader-repro
$ npm i css-loader@6.4.0
// /typings.d.ts

declare module "*.css";
// /tsconfig.app.json

// notice: i've added "typings.d.ts" to "files" array!

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": []
  },
  "files": [
    "src/main.ts",
    "src/polyfills.ts",
    "typings.d.ts"
  ],
  "include": [
    "src/**/*.d.ts"
  ]
}
// /src/app/test.css

body {
  background-color: red;
}
// /src/app/app.component.ts

import testCss from 'css-loader!./test.css';
console.log(testCss);
console.log('type of testCss: ', typeof testCss);

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'css-loader-repro';
}

What I expected to see

When opening the console, I expected testCss to be printed as object (see screenshot)

What I saw instead

The transformation result of css-loader was returned as a string (see screenshot)

Limitations

I do not want to provide a custom webpack configuration. For experiments, this is fine but for my library I want to stay as close the the Angular standard, as possible.


Solution

  • My issue has been solved by @Akxe: import css file into es6 returns string instead of object

    Using import * as test from '...' solved my issue.