Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Razzle and CSS modules #428

Closed
stereobooster opened this issue Dec 14, 2017 · 18 comments
Closed

Razzle and CSS modules #428

stereobooster opened this issue Dec 14, 2017 · 18 comments

Comments

@stereobooster
Copy link

I'm trying to make razzle work with CSS Modules. No Luck yet. Any advice?
As as I will manage to do it, can create PR to examples. Current code https://github.com/stereobooster/razzle-cssmodules

Thanks for awesome project.

@rafaelderolez
Copy link

rafaelderolez commented Dec 14, 2017

Trying to set up the exact same thing!

Edit: not the exact same thing. We're trying to achieve scss + cssmodules.

I was using the config from the with-scss pull request, added a couple of options to it and it works on initial load, but breaks after refreshing due to the classNames not matching between server and client.

proxyConsole.js:54 Warning: Prop `className` did not match. Server: "null" Client: "Component__classNameHere___1AxrA"

I've added the following in the dev css-loader options:

modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'

And the following in the production css-loader options:
modules: true

Not perfect but halfway there, I'd say. Here's the complete config so far:


const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  modify: (baseConfig, { target, dev }) => {
    const appConfig = Object.assign({}, baseConfig);
    const isServer = target !== 'web';

    const postCssLoader = {
      loader: 'postcss-loader',
      options: {
        ident: 'postcss', // https://webpack.js.org/guides/migrating/#complex-options
        sourceMap: dev,
        plugins: () => [
          autoprefixer({
            browsers: [
              '>1%',
              'last 4 versions',
              'Firefox ESR',
              'not ie < 9' // React doesn't support IE8 anyway
            ]
          })
        ]
      }
    };

    appConfig.module.rules.push({
      test: /.scss$/,
      // Handle scss imports on the server

      use: isServer
        ? ['css-loader', 'sass-loader']
        : // For development, include source map
          dev
          ? [
              'style-loader',
              {
                loader: 'css-loader',
                options: {
                  sourceMap: true,
                  modules: true,
                  localIdentName: '[name]__[local]___[hash:base64:5]'
                }
              },
              postCssLoader,
              {
                loader: 'sass-loader',
                options: {
                  sourceMap: true
                }
              }
            ]
          : // For production, extract CSS
            ExtractTextPlugin.extract({
              fallback: 'style-loader',
              use: [
                {
                  loader: 'css-loader',
                  options: {
                    importLoaders: 1,
                    modules: true
                  }
                },
                postCssLoader,
                'sass-loader'
              ]
            })
    });

    if (!isServer && !dev) {
      appConfig.plugins.push(
        new ExtractTextPlugin('static/css/[name].[contenthash:8].css')
      );
    }

    return appConfig;
  }
};

@jaredpalmer
Copy link
Owner

Razzle uses the same CSS setup as CRA. You would indeed need to replace the /.css/ module webpack rules in their entirety on the client. I'm pretty sure the server doesn't need to be touched at all.

@stereobooster
Copy link
Author

You would indeed need to replace the /.css/

Yes this is what I'm doing.

I'm pretty sure the server doesn't need to be touched at all.

I hopped so too. But I get same error as @rafaelderolez. There are no CSS Modules on server, so css import returns object without classes, when I do styles.className I get undefined on server and proper class name on the client, hence mismatch

@jaredpalmer
Copy link
Owner

Interesting. Have to try this out myself

@stereobooster
Copy link
Author

Ok I fixed it. Working code in the repo. @jaredpalmer do you want PR for that?

@jaredpalmer
Copy link
Owner

Yeah that’s be great to add as an example

@stereobooster
Copy link
Author

I rushed to declare a victory. I fixed one problem with webpack, but CSS modules doesn't work 🤦

@stereobooster
Copy link
Author

Opened PR. Closing issue #432

@wagnerjsilva
Copy link

Hi Guys,

Also trying to get CSS modules to work here, tried the example above but only getting an empty object in the front end.

Any ideas?

@stereobooster
Copy link
Author

Did you try #432?

@wagnerjsilva
Copy link

I'll try it again now. Thanks for getting back :-)

@wagnerjsilva
Copy link

wagnerjsilva commented Jun 25, 2018

Yeah, same thing. Just an empty object. No errors.

Here are my files:

Navigation.css

.NavLink { color: #ff0000; }

Navigation.js

import React from 'react';
import Aux from '../../hoc/Aux/Aux';
import { Link } from 'react-router-dom';
import classes from './Navigation.css';

const Navigation = () => {

    console.log(classes.NavLink);


    //@todo use react nav links, fetch data from props - no need for state here
    return (
        <Aux>
            <ul>
                <li className={classes.NavLink}><Link to="/">Home</Link></li>
                <li><Link to="/critical-illness-insurance/what-is-the-best-critical-illness-cover">Best CIC</Link></li>
                <li><Link to="/income-protection-insurance/what-is-the-best-income-protection-cover">Best IP</Link></li>
            </ul>
        </Aux>
    );
};


export default Navigation;

razzle.config.js

"use strict";

const autoprefixer = require("autoprefixer");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const path = require("path");

module.exports = {
  modify(config, { target, dev }, webpack) {
    const appConfig = Object.assign({}, config);
    const isServer = target !== "web";
    const postCSSLoaderOptions = {
      ident: "postcss", // https://webpack.js.org/guides/migrating/#complex-options
      plugins: () => [
        require("postcss-flexbugs-fixes"),
        autoprefixer({
          browsers: [
            ">1%",
            "last 4 versions",
            "Firefox ESR",
            "not ie < 9" // React doesn't support IE8 anyway
          ],
          flexbox: "no-2009"
        })
      ]
    };

    const cssConfig = modules =>
      [
        {
          loader: require.resolve("css-loader"),
          options: {
            importLoaders: 1,
            minimize: !dev,
            sourceMap: !dev,
            modules: modules,
            localIdentName: modules ? "[path]__[name]___[local]" : undefined
          }
        },
        isServer && {
          loader: require.resolve("postcss-loader"),
          options: postCSSLoaderOptions
        }
      ].filter(x => !!x);
    const css = cssConfig(false);
    const cssModules = cssConfig(true);

    const i = appConfig.module.rules.findIndex(
      rule => rule.test && !!".css".match(rule.test)
    );

    if (!dev && !isServer) {
      appConfig.module.rules[i] = {
        test: /\.css$/,
        exclude: /\.module\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: {
            loader: require.resolve("style-loader"),
            options: {
              hmr: false
            }
          },
          use: css
        })
      };
      appConfig.module.rules.push({
        test: /\.module\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: {
            loader: require.resolve("style-loader"),
            options: {
              hmr: false
            }
          },
          use: cssModules
        })
      });
      appConfig.plugins.push(
        new ExtractTextPlugin("static/css/[name].[contenthash:8].css")
      );
    } else if (!dev && isServer) {
      appConfig.module.rules[i] = {
        test: /\.css$/,
        exclude: /\.module\.css$/,
        use: css
      };
      appConfig.module.rules.push({
        test: /\.module\.css$/,
        use: [
          isServer && require.resolve("isomorphic-style-loader"),
          ...cssModules
        ].filter(x => !!x)
      });
    } else {
      appConfig.module.rules[i] = {
        test: /\.css$/,
        exclude: /\.module\.css$/,
        use: [!isServer && require.resolve("style-loader"), ...css].filter(
          x => !!x
        )
      };
      appConfig.module.rules.push({
        test: /\.module\.css$/,
        use: [
          isServer
            ? require.resolve("isomorphic-style-loader")
            : require.resolve("style-loader"),
          ...cssModules
        ].filter(x => !!x)
      });
    }

    return appConfig;
  }
};`

@wagnerjsilva
Copy link

Switching to Navigation.module.css returns:

ERROR in ./src/components/Navigation/Navigation.module.css (./node_modules/css-loader??ref--9-1!./node_modules/postcss-loader/lib??postcss!./node_modules/style-loader!./node_modules/css-loader??ref--10-1!./src/components/Navigation/Navigation.module.css)
Module build failed (from ./node_modules/postcss-loader/lib/index.js):
Syntax Error

(2:1) Unknown word

@stereobooster
Copy link
Author

stereobooster commented Jun 25, 2018

It is import classes from './Navigation.module.css'; per c-r-a convention.

@wagnerjsilva
Copy link

Yeah, I've been trying that :-(

ERROR in ./src/components/Navigation/Navigation.module.css (./node_modules/css-loader??ref--9-1!./node_modules/postcss-loader/lib??postcss!./node_modules/style-loader!./node_modules/css-loader??ref--10-1!./src/components/Navigation/Navigation.module.css)
Module build failed (from ./node_modules/postcss-loader/lib/index.js):
Syntax Error 

(2:1) Unknown word

  1 | 
> 2 | var content = require("!!../../../node_modules/css-loader/index.js??ref--10-1!./Navigation.module.css");

@stereobooster
Copy link
Author

Hm... have no idea, haven't see this before. Something with webpack config

@wagnerjsilva
Copy link

Yeah very strange. I'll update if I get around it.

@wagnerjsilva
Copy link

Ha! I'm kicking myself.

After banging my head against the keyboard a few times I noticed the module.css was being already processed, and when I added the duplicated rule things went bananas!

Thanks for the help though.

For prosperity it's worth noticing that css modules seem to be already being processed by Razzle/CRA without the need of a new razzle config. Unless I've done something really crazy with my local install :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants