It is a redundant issue I know, but I opened this issue intentionally. It's three days I'm setting up a next.js boilerplate(with redux, redux-saga, ...) and it's two days that I'm stucked in setting up loading external css and scss files. I've checked with-global-stylesheet and with-scoped-stylesheet-and-postcss examples, but each of them has major problems mentioned in prior issues. I've seen too many open and closed issues that are solving this problem with hacks... I think it's a good idea that instead of leaving the problem to find the best solution, solve it with current available solutions till find a better one. Because many have this problem now and want to see it solved now!
I agree, only styled-jsx has clean (incl. hot reloading) support and that's what keeping me from using Next.js for anything but when I need some rapid prototyping.
I think the solution to CSS' scoping issues of CSS Modules is a much cleaner one, plus with CSS Modules it's still possible to pass classes to child components (try putting a non-global class on an SVG imported with babel-plugin-inline-react-svg
with styled-jsx).
That and I prefer to have standardized .css
files to prevent framework lock-in as much as possible and an external CSS files in production for caching (and to make MQ polyfills like Respond.js work if you are unlucky enough to still have to support IE8).
Massive +1
It's a huge frustration that such a simple thing as external css/scss is almost impossible to achieve with next.js, which renders it useless for 90% of my applications.
I'm working with bootstrap, and I need a configuration where there will be one global bootstrap css import, with addition of external scoped css.
While we managed to get working external stylus with styled jsx 1 ( webpack for handling compilation ), having hard time figuring it out on styled jsx 2 since breaking change of handling separate css files introduced.
Current approach:
import ComponentStyles from './footer.styl';
...
<style jsx>
{ComponentStyles}
</style>
Would be great to see https://github.com/zeit/next.js/tree/master/examples/with-styled-jsx-scss working with external scss files.
We went through the same ordeal when setting up the environment.
Eventually we settled with a global stylesheet with scss+post css with lost-grid.
Hot reloading works, so while it's not an ideal solution (due to the global stylesheet being loaded all at once), it's an ok compromise.
Dependencies
"autoprefixer": "^7.1.6",
"babel-plugin-module-resolver": "^2.7.1",
"babel-plugin-wrap-in-js": "^1.1.1",
"node-sass": "^4.5.3",
"sass-loader": "^6.0.6",
"pixrem": "^4.0.1",
"postcss-easy-import": "^3.0.0",
"postcss-loader": "^2.0.8"
In package.json
...
"postcss": {
"plugins": {
"lost": {},
"postcss-easy-import": {
"prefix": "_"
},
"autoprefixer": {},
"pixrem": {}
}
}
...
In next.config.js
webpack: (config, { dev }) => {
config.module.rules.push(
{
test: /\.(css|scss)/,
loader: 'emit-file-loader',
options: {
name: 'dist/[path][name].[ext]'
}
}
,
{
test: /\.css$/,
use: ['babel-loader', 'raw-loader', 'postcss-loader']
}
,
{
test: /\.s(a|c)ss$/,
use: ['babel-loader', 'raw-loader', 'postcss-loader',
{ loader: 'sass-loader',
options: {
includePaths: ['styles', 'node_modules']
.map((d) => path.join(__dirname, d))
.map((g) => glob.sync(g))
.reduce((a, c) => a.concat(c), [])
}
}
]
}
)
return config
}
In pages/_document.js
...
import stylesheet from 'styles/main.scss'
...
<Head>
<style dangerouslySetInnerHTML={{ __html: stylesheet }} />
</Head>
...
And you can then manage your styles starting from /styles/main.scss
Hope it helps
My problem with each of these two style examples ( with-global-stylesheet and with-scoped-stylesheets-and-postcss ) is that none of them are simple to integrate with Jest and Snapshot testing with the CSS in the snapshot. There have been people who successfully get Jest to work with Webpack, but that's by specifically skipping the CSS.
Running a babel-jest
preprocessor file as described in this SO answer seems like such a bad hack.
It seems to get external CSS as with-global-stylesheet you must use Webpack, but to use Jest you can't rely on Webpack, only Babel.
Does anyone have ideas in this space?
I'm facing a similar problem. I'm new to nextjs and I can't make the example "with-external-scoped-css" work properly. Sometimes, my css is loaded and sometimes not. I don't know if it's the same issue you're talking about.
Resolved external styles issues with this loader https://github.com/coox/styled-jsx-css-loader
@ilionic I've checked your solution. It's great! Thank you :)
@arefaslani I don't think this issue is closed.
As of HTTP v1 it's still a horrible performance tax for tons of CSS to load, it increases the time to first draw dramatically.
Proper external style support would allow for importing CSS and it resulting in a not an inline ...
Also, this suggestion doesn't resolve use cases where a CSS framework like bootstrap needs to be included from node_modules. Including Bootstrap as an inline CSS on every page would be horrible. And would negate the benefits of browser caching, e.t.c
In short, I really don't think this issue can be closed... It's still very much an ongoing problem.
@israelidanny I know what you mean about bootstrap, it's not silver bullet solution. We are extracting core parts of bootstrap framework to separate css file so browsers could cache it. Not ideal, but this awkwardness of dealing with preprocessors and CSS frameworks pushing towards newer css-in-js approaches and cutting dependencies on CSS frameworks.
@ilionic I understand what you're saying, but still - having tons of inline CSS is bad for performance (specifically time to first frame). I had quite a few projects where we heavily optimized for that.
It's a shame to lose all that, especially given the fact that we can have server-rendered DOM.
Maybe close this issue, but open a new one, specifically for a solution that lets us link external CSS?
It would be odd to ignore a clearly prevalent development practice.
@israelidanny agree, we are still struggling with CSS performance and without major rewrites not clear how to solve it so indeed this issue goes deeper. Probably styled-jsx is more relevant repo in this case?
@ilionic hmm, I don't see how styled-jsx repo would be the right place.
The issue isn't with them, the issue is enabling next.js support of external css files, which may or may not involve anything to do with styled-jsx.
What do you think?
@israelidanny It was not the best solution, but it works anyway. But you're right. Having all the css inline in every page without caching is not best solution. Also I agree with you in this part:
The issue isn't with them, the issue is enabling next.js support of external css files, which may or may not involve anything to do with styled-jsx.
and absolutely disagree with @ilionic in:
Probably styled-jsx is more relevant repo in this case
I managed a solution with styled-jsx/css loader. You can see the code from https://github.com/P233/nextjs-with-scss
However, I noticed the @import
ed scss files are not watched and won't trigger hot reload, which really makes me frustrated.
I've created https://github.com/sheerun/extracted-loader to hotreload extracted stylesheet files. It works pretty nice even for development, so dangerouslySetInnerHTML
is not necessary.
You use it as so:
config.module.rules.push({
test: /\.css$/,
use: ['extracted-loader'].concat(ExtractTextPlugin.extract({
/* Your configuration here */
}))
})
config.plugins.push(new ExtractTextPlugin('index.css'))
@sheerun , thank you, but how i inject my css into the components?
You don't inject, you extract everything with ExtractTextPlugin and write following:
<Head>
<link rel='stylesheet' type='text/css' href="/static/index.css" />
</Head>
in your components something like
import './styles.scss'
should be enough
ok, but now i have an error:
./components/Home/Home.js
Module not found: Error: Can't resolve 'css-loader' in 'D:\Sites\work\VisualProposal'
@ ./components/Home/Home.js 13:0-22
@ ./pages?entry
@ multi ./pages?entry
my Home.js component:
import { observer } from 'mobx-react';
import './Home.scss'
import MainSection from './MainSection/MainSection'
import Sections from './Sections/Sections';
import Features from './Features/Features'
import Pricing from './Pricing/Pricing';
import Footer from './Footer/Footer'
const Home = () => {
return (
<div className="Home">
<MainSection/>
<Sections/>
<Features/>
<Pricing/>
<Footer/>
</div>
)
};
export default observer ( Home );
my next.config.js:
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
webpack: function ( config, { dev } ) {
config.module.rules.push({
test: /\.(sa|sc|c)ss$/,
use: ['extracted-loader'].concat(ExtractTextPlugin.extract({
use: [
"babel-loader",
{
loader: 'css-loader',
options: {
url: true,
minimize: !dev,
sourceMap: dev,
importLoaders: 2
}
},
{
loader: 'postcss-loader',
options: {
sourceMap: dev,
plugins: [
require('autoprefixer')({
/* options */
})
]
}
},
{
loader: 'sass-loader',
options: {
sourceMap: dev
}
}
]
}))
});
config.plugins.push(new ExtractTextPlugin('index.css'));
if ( config.resolve.alias ) {
delete config.resolve.alias['react'];
delete config.resolve.alias['react-dom']
}
for (let index = 0; index < config.plugins.length; index += 1) {
if (config.plugins[index].constructor.name === "UglifyJsPlugin") {
config.plugins.splice(index, 1, new UglifyJSPlugin({
sourceMap: true,
parallel: true,
}));
break;
}
}
return config
}
};
So what i`m doing wrong?
I've added pretty advanced example with SCSS, url() in stylesheet, img[src]. It should work of of the box with now.sh and has hot-reloading and exporting properly configured:
https://github.com/sheerun/extracted-loader/tree/master/examples/with-next
@psycura I see you use Windows so it might not work for you right away but please send fix PR
👎 shame to Nextjs that it does not allow to work with external css files. There a tons of ready-use packages with their own stylsheets which I'd like to use in my project. But I can't! I tried several options but no one really works: spent a day for this already.
@mkozhukharenko It works with css and scss files. I will add an example with https://github.com/coox/styled-jsx-css-loader. It loads external css as scoped or global styled-jsx. For general global scss, I suggest using node-sass and postcss.
@arefaslani I tried all options, neither worked for me. I'm totally disappointed with this framework. How on earth so easy task could be difficult? I will not use such opinionated framework framework again.
@mkozhukharenko Look at this example: https://github.com/arefaslani/next.js/tree/canary/examples/with-external-scoped-scss. I'm creating a pull request to add it to the main repo examples.
just try to add much more css to your file and you will see that styled-jsx
can't handle that. I'm getting 'jsx-undefind' cant be cound or 'jsx-4231512' can't be found errors
@arefaslani Is there any way to use this pattern with your example?
import classes from './styles.scss'
const MyComponent = () => (
<header className={classes.header}>Hello</header>
)
@protoEvangelion Unfortunately, currently it works only with styled-jsx.
Aww ok thanks for the quick response :)
It's a shame that the build of next.js doesn't think about reusing existing resource at first. What a waste of time setting up complex rules just for a css file.
I'm working on a solution for this issue that allows all webpack loaders to work.
I'd also like to point out that I personally don't like the tone people are having in this issue.
I totally understand you want to import css. And we're very aware of this request. That's why I've spent the past week working on the best possible solution 👍
More on this soon. Till then, please be kind and happy holidays 🎅😄
Hi, 各位, 我在別的 github 發現了一個解決方案,
使用skeleton-loader 遵照BEM規則 達到類似 css-modules 一樣的效果,
因為會需要產生 .scss.json, 之後再使用trash將產生的 .scss.json 刪除
雖然感覺不是很理想, 但給各位發想 看是否有其他更好的方法
Hi, everybody, I found a solution on another github,
Use skeleton-loader to comply with BEM rules to achieve the same effect as css-modules,
Because it will need to generate. Scss.json, then use the trash will be generated. Scss.json delete
Although it feels less than ideal, give it to you to see if there are any other better ways
@timneutkens How's it going with your solution?
I have created a Next boilerplate that support importing scss, css and many more features. Take a look at it and if you liked it, give it a star ;)
https://arefaslani.github.io/next-boilerplate
@Bobeta I've got it working, there's a few edge cases I want to fix before submitting a PR.
@timneutkens Great to hear! When do you expect it to be published?
@Bobeta I'm sure he'll post on this thread when it's published and ready for us to use.
@jthegedus I'm sure he will also, but I'm wondering about estimations so that folks can base decisions on that @timneutkens
Most helpful comment
I'd also like to point out that I personally don't like the tone people are having in this issue.
I totally understand you want to import css. And we're very aware of this request. That's why I've spent the past week working on the best possible solution 👍
More on this soon. Till then, please be kind and happy holidays 🎅😄