I think there is something fundamentally wrong with next-sass since Next.js 6.
The issue seems to be that ExtractTextPlugin extracts css for each bundle, but only keeps the css from the last bundle in /_next/static/style.css, resulting in only one page being styled correctly, while styles are broken in all other pages.
There are some issues filed here that i think all describe the same problem slightly differently:
I isolated the problem in a barebones project using Next 6.0.0 with next-sass and CSS Modules:
https://github.com/MadeInHaus/next-6-sass-example
One hacky solution is implemented in this branch:
https://github.com/MadeInHaus/next-6-sass-example/tree/solution
I give a custom ExtractTextPlugin instance in next.config.js with a contenthash filename:
const withSass = require('@zeit/next-sass');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extract = new ExtractTextPlugin({ filename: 'static/[contenthash].css' });
module.exports = withSass({
cssModules: true,
extractCSSPlugin: extract,
webpack: config => {
config.plugins.push(extract);
return config;
},
});
Then i pull in all generated css files in _document.js via this.props.buildManifest.css:
export default class MyDocument extends Document {
render() {
const { buildManifest } = this.props;
const { css } = buildManifest;
return (
<html>
<Head>
{css.map(file => {
return (
<link
rel="stylesheet"
href={`/_next/${file}`}
key={file}
/>
);
})}
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
This is a hack. There surely is a real solution but so far i wasn't able to come up with one.
When adding extractCSSPlugin you have to add the commonschunk config manually like this: https://github.com/zeit/next-plugins/issues/127#issuecomment-377905928
I'm planning to do a full rewrite of next-css etc.
@timneutkens Thanks, much appreciated! Anything we can do to help?
@claus did it work? 馃檹
@timneutkens you mean running commonsChunkConfig(config, /\.(sass|scss|css)$/)? No, that doesn't seem to fix the problem. Unless i am missing something
@timneutkens in fact, i'm not sure commonsChunkConfig is ever gonna do anything because there are no CommonsChunkPlugins with a filenameTemplate of either 'commons.js' or 'main.js' (at least in my test project). In the production build, there is a CommonsChunkPlugin with filenameTemplate of 'static/commons/main-[chunkhash].js'. In the dev build, there is a CommonsChunkPlugin with filenameTemplate of 'static/commons/main.js' and one with filenameTemplate of 'static/commons/manifest.js'.
Not sure if any of this is relevant to the original problem, which is that for each page bundle a css file is extracted, and as the files are all extracted into a file with the same name (static/style.css), they overwrite each other, so the final style.css only contains part of the app's css.
Or in other words, if you check out https://github.com/MadeInHaus/next-6-sass-example (the master branch, without that extractCSSPlugin hack) and npm i && npm run build && npm run start, the value of this.props.buildManifest.css in _document.js will be
[ 'static/style.css',
'static/style.css',
'static/style.css',
'static/style.css' ]
And the file /_next/static/style.css will only contain css for one of the four bundles.
@timneutkens Hey, actually, i got it to work with a slightly modified commonsChunkConfig, see source and comments below:
const withSass = require('@zeit/next-sass');
const commonsChunkConfig = (config, test = /\.css$/) => {
config.plugins = config.plugins.map(plugin => {
if (
plugin.constructor.name === 'CommonsChunkPlugin' &&
// disable filenameTemplate checks here because they never match
// (plugin.filenameTemplate === 'commons.js' ||
// plugin.filenameTemplate === 'main.js')
// do check for minChunks though, because this has to (should?) exist
plugin.minChunks != null
) {
const defaultMinChunks = plugin.minChunks;
plugin.minChunks = (module, count) => {
if (module.resource && module.resource.match(test)) {
return true;
}
return defaultMinChunks(module, count);
};
}
return plugin;
});
return config;
};
module.exports = withSass({
cssModules: true,
webpack: config => {
config = commonsChunkConfig(config, /\.(sass|scss|css)$/);
return config;
},
});
next-css also has this issue, but only in production. I hope others are seeing this?
edit: looks like it's just serving the first imported css file
@claus - thanks, your fix seems to work!
Please send a pull request @claus
@timneutkens https://github.com/zeit/next-plugins/pull/159
@claus thank you very much, commented.
I wonder if we could remove the commons chunk thing in the future.
Still having this issue as of [email protected] it seems 馃.
I'm unable to import two scss files in two different components, only the first one gets picked up and bundled
@claus 's workaround here https://github.com/zeit/next-plugins/issues/157#issuecomment-385885772 does make it work though !
Tell me if I can be of any help 馃槂
EDIT : I also have next-css enabled, here's my next config : https://gist.github.com/mininao/36d928f168a238d6dff3de0d4894b094
Most helpful comment
@timneutkens Hey, actually, i got it to work with a slightly modified
commonsChunkConfig, see source and comments below: