csswebpackcss-modulesrescript

CSS won't load when using CSS modules


I am trying to write a simple react component in rescript and have a CSS file for the component. I am trying to do this with Webpack.

Here is my entire project code

Webpack.config.js

const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const outputDir = path.join(__dirname, "build/");

module.exports = {
  mode: "development",
  entry: "./src/Index.bs.js",
  output: {
    path: outputDir,
    filename: "index.js"
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      inject: false
    })    
  ],
  devServer: {
    compress: true, 
    static: outputDir,
    port: 8000
  },
  module: {
    rules: [
      {
        test: /\.css/,
        use: [
          'style-loader', 
          { 
            loader: "css-loader",
            options: {
              importLoaders: 1,
              modules: true,
            }
          }
        ]
      }
    ]
  }
}

My component

%%raw("import './Tutorial.css'")

@react.component
let make = () => {
  <div>
    <h1>{"Welcome to my app" -> React.string}</h1>
    <ul className="menu">
      <li className="menu-item">{"Company2" -> React.string}</li>
      <li className="menu-item">{"Mission" -> React.string}</li>
      <li className="menu-item">{"Values" -> React.string}</li>
      <li className="menu-item">{"Leadership" -> React.string}</li>
    </ul>
  </div>
}

The CSS file I am trying to load

.menu {
  list-style-type: none;
}

.menu-item {
  display: inline;
  color: red;
  padding: 0 20px 0 20px;
}

my bsconfig.json

{
  "name": "react-tutorial",
  "version": "0.1.0",
  "sources": {
    "dir" : "src",
    "subdirs" : true
  },
  "package-specs": {
    "module": "es6",
    "in-source": true
  },
  "suffix": ".bs.js",
  "jsx": {"version": 4, "mode": "classic"},
  "bs-dependencies": ["@rescript/react"],
  "reason": {"react-jsx": 3}
}

Here is package.json

{
  "name": "react-tutorial",
  "version": "0.1.0",
  "scripts": {
    "clean": "npx rescript clean -with-deps",
    "build": "npx rescript build && webpack",
    "watch": "npx rescript build -w",
    "server": "webpack-dev-server"
  },
  "keywords": [
    "ReScript"
  ],
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "css-loader": "^6.7.3",
    "html-webpack-plugin": "^5.5.0",
    "rescript": "^10.0.1",
    "style-loader": "^3.3.1",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1"
  },
  "dependencies": {
    "@rescript/react": "^0.10.3"
  }
}

However it just won't load the CSS. I think I followed the documentation and the steps to configure webpack correctly but it just doesn't work.

Here is my full code if anyone is interested. https://github.com/abhsrivastava/react-tutorial


Solution

  • You have CSS modules enabled, but you're not importing it as a CSS module. The CSS is being loaded, but the point of CSS modules is module isolation, which means the CSS class names need to be mangled. Instead of using the class names directly you need to do so via a lookup table, which is returned when you're importing the CSS module.

    So you need to do two things:

    1. Import the CSS module as a module, binding the lookup table to a name:
    @module("./Tutorial.css") @val external css: {..} = "default"
    
    1. Use the lookup table to get the mangled class name. That is, instead of className="menu", use className=css["menu"].

    The full working code is this:

    @module("./Tutorial.css") @val external css: {..} = "default"
    
    @react.component
    let make = () => {
      <div>
        <h1>{"Welcome to my app" -> React.string}</h1>
        <ul className=css["menu"]>
          <li className=css["menu-item"]>{"Company2" -> React.string}</li>
          <li className=css["menu-item"]>{"Mission" -> React.string}</li>
          <li className=css["menu-item"]>{"Values" -> React.string}</li>
          <li className=css["menu-item"]>{"Leadership" -> React.string}</li>
        </ul>
      </div>
    }