CSS Module gets bundled but is not referenced using TSDX which uses Rollup underhood

Viewed 1995

I have created a React library using TSDX → https://github.com/deadcoder0904/react-typical

It uses CSS Modules & attaches styles to the React library.

The bundle correctly outputs CSS file into the dist/ folder but it never really references it as it should.

This causes my styles to not show up at all.

Here's my complete tsdx.config.js:

const postcss = require('rollup-plugin-postcss');
const { terser } = require('rollup-plugin-terser');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');

module.exports = {
  rollup(config, options) {
    config.plugins.push(
      postcss({
        modules: true,
        plugins: [
          autoprefixer(),
          cssnano({
            preset: 'default',
          }),
        ],
        inject: false,
        // only write out CSS for the first bundle (avoids pointless extra files):
        extract: !!options.writeMeta,
        minimize: true,
      }),
      terser()
    );
    return config;
  },
};

If you see the dist/ folder at https://yarnpkg.com/package/@deadcoder0904/react-typical?files, then you'll notice it has index.js file but it doesn't reference the .css file at all.

Same thing with every .js file in dist/ folder. No file references .css file & the CSS code isn't bundled at all so it just doesn't use styles.

How do I solve this?

2 Answers

From my understanding, normally a library usually introduce the component & styles separately and let the users know in the document if they want to use default style then let import css file too such as:

import ReactTypical from "react-typical"
import "react-typical/dist/react-typical.cjs.development.css"

That is as same as your case I guess

Or you would set your style by default without asking them to import manually which means you have to refine your config by setting inject: true, it will import your css context into your js file then execute at runtime to append the script in the <head /> of the document. Then your changing config would look like:

postcss({
  modules: true,
  plugins: [
    autoprefixer(),
    cssnano({
      preset: 'default',
    }),
  ],
  // Append to <head /> as code running
  inject: true,
  // Keep it as false since we don't extract to css file anymore
  extract: false,
})

In order to work with storybook, add following css rules to your webpack storybook config ./story/main.js:

// Remove the existing css rule
config.module.rules = config.module.rules.filter(
  f => f.test.toString() !== '/\\.css$/'
);

config.module.rules.push(
  {
    test: /\.css$/,
    use: [
      'style-loader',
      'css-loader',
    ],
    include: path.resolve(__dirname, "../src"),
  }
)

But you miss them in your package dependency, just remember to add them:

npm i -D style-loader css-loader
Related