Closed stereobooster closed 6 years ago
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;
}
};
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.
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
Interesting. Have to try this out myself
Ok I fixed it. Working code in the repo. @jaredpalmer do you want PR for that?
Yeah that’s be great to add as an example
I rushed to declare a victory. I fixed one problem with webpack, but CSS modules doesn't work :facepalm:
Opened PR. Closing issue #432
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?
Did you try #432?
I'll try it again now. Thanks for getting back :-)
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;
}
};`
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
It is import classes from './Navigation.module.css';
per c-r-a convention.
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");
Hm... have no idea, haven't see this before. Something with webpack config
Yeah very strange. I'll update if I get around it.
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 :-)
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.