Closed matthewmueller closed 7 years ago
You mean this doesn't work on server ? I think we don't have workaround for this yet. cc @arunoda
oh right, i guess there'd need to be a way for the webpack config in next.config.js to work on both sides in order for this to work.
I've got a kind of ballpark similar issue in that I just can't seem to get Next to play nicely with CSS or SASS. I have a components
directory with standard React components in that I import into my pages but whenever I attempt to import in SASS (or CSS) files I get a ~"you need to use the appropriate loader for this file" type error message.
Generally in React I import SASS files and have Webpack compile using style, css and sass loaders. I've attempted to add these to the next.config.js
file (and NPM installed them) but still get the same error message.
My next.config.js
file:
module.exports = {
webpack: (config, { dev }) => {
config.module.rules.push({ test: /\.scss$/, loader: ['style-loader', 'css-loader', 'sass-loader'] });
return config;
}
}
Sorry if these questions sound dumb or I've missed something obvious in the docs that spell out the answers to them, but if anyone has a working example of importing / compiling SASS (or at the least CSS) into a component or a page with whatever's needed to add to the next.config.js
to load / compile them, I'd massively appreciate it. Thanks!
I'm using css-modules-require-hook to make css work.
@spacedragon Do you have an example how to integrate css-modules-require-hook with Next.js? I'm having problems with getting it working.
I'm still having issues with getting SASS to compile if anyone could shed some light on how to do this or just import a CSS file within Next it would be appreciated (via a code example).
Interesting that the README file has been updated to remove the SVG loader example and changed to say adding loaders for file like SVG, CSS and SASS is discouraged. I'm not sure why inlined CSS is OK but imported CSS isn't but I'm sure there's a good reason why. I'm just currently uncertain about the best strategy to handle none JS defined / inlined CSS and SASS.
@MikeDigitize See comment on #627 and #638 .
It's actually possible and pretty easy to process styles on server side.
directly in node:
require.extensions['.css'] = function(file) {
console.log(file.id)
return;
}
via babel register:
// from https://babeljs.io/docs/core-packages/babel-register/
require("babel-register")({
// Optional ignore regex - if any filenames **do** match this regex then they
// aren't compiled.
ignore: /regex/,
// Ignore can also be specified as a function.
ignore: function(filename) {
if (filename === '/path/to/es6-file.js') {
return false;
} else {
return true;
}
},
// Optional only regex - if any filenames **don't** match this regex then they
// aren't compiled
only: /my_es6_folder/,
// Setting this will remove the currently hooked extensions of .es6, `.es`, `.jsx`
// and .js so you'll have to add them back if you want them to be used again.
extensions: [".es6", ".es", ".jsx", ".js"]
});
via webpack loaders:
I personally use isomorphic-style-loader as it allows me to inline critical CSS while rendering on server. Hot reloading and other DX related stuff works too. I'm not really fan of CSS in JS as it complicates using 3rd party components and and somehow takes away the C from CSS.
@viktorbezdek Have you successfully used isomorphic-style-loader with next.js?
@noeljackson Not really, but I intend to. Next.js looks promising and could save me lot of time if I make it work. Will look into it in next one or two weeks and submit pull request if I'm successful.
@viktorbezdek I will put a bounty on this one, as it's really crucial to a project I'm working on. I know I'm not inept, but I do not understand how to debug the babel transformations enough to figure this out. I've tried permutation of these ideas and nothing works 100%. I have been able to get raw-loader to pull in a data-encoded stylesheet using babel-plugin-webpack-loaders, but none of the style loaders work. Thanks for chiming in! :) Much appreciated.
Is there a solution to this? I would like to see a solution so I don't have to include css globally.
FWIW, I've just been putting my CSS files in the /static
folder. Not great colocation, but not a huge deal either.
There will be a solution. I just didn't manage to finish it. I've locally very first prototype which seems to work, however it needs few hours to be finished. I'm pretty sure I'll be done after weekend. Stay tuned.
@matthewmueller You are using CSS modules?
@viktorbezdek Thanks for working on this! CSS Modules support (or similar) is important for this project IMO. Styled jsx, is ok for simple situations but is hard to read for heavily styled components.
Would a babel plugin like this be an option (server side as well)? https://github.com/gajus/babel-plugin-react-css-modules
I tried to get this to work but but no luck :/
I got CSS modules sort of working with babel-plugin-css-modules-transform
. See my hacky example in my fork.
The downside is you have to kill the server & restart it every time you make a change to the CSS.
Some React components expose default styling though a import
able static resource. For instance to import the default style of https://github.com/react-component/slider one would use:
import 'rc-slider/assets/index.css';
It sure is possible to copy paste this stylesheet in the static/
directory but it won't stay in sync with the upstream style on a future component update, and it doesn't match what this component documentation recommend.
The problem is that those CSS files introduce global effects. We need to be able to capture the CSS and put it inside the React lifecycle, so that it gets unmounted, server-rendered, etc.
Many libraries do that, but I don't think it's a good pattern.
I'm not familiar with Zeit Next internals, but could some static analysis of the import
be used to register/capture the CSS?
We could, but it would be really strange. Similar to something that's outside of render()
magically inserting itself inside your component lifecycle.
// Figured I'd share this for anyone else
Well... I just spent a bit too much time trying to hack CSS in here, BUT I landed on a solution that works (for me). Admittedly, it's a hack, but hot reloading works and so does server-side building.
Using (shudder) gulp, with this gulpfile (https://gist.github.com/auser/25e88e39d83413773c01f4c000ec2806) all **/*.scss
files get concatenated together and shoved into a Styles
component which I mount on the page as a "normal" element.
Hope this helps someone else until we can get true postcss support in next.
Thanks for the hack @auser, I've been looking at the webpack config all day with no luck!
Edit: Btw, you need to add a sass parser to the gulpfile!
Yes and no... I just use the .scss
extension as a way to differentiate pure css files from pre-compiled ones. Since postcss (with precss
) mimics sass well enough, I don't have one. Feel free to edit for yourself with a sass parser.
Seems like that is currently the best solution, using gulp to compile css file and build it inline or just even in /static if you don't mind not having hot reloading.
I got css import + hot reload working in a clean way. The css is imported as string and the user can inline it in the page just like any other string. Please have a look at this example, help me test and PRs are welcome!
https://github.com/davibe/next.js-css-global-style-test
I believe this example should make it into next.js official examples. Does it? @rauchg @arunoda @nkzawa (sorry if i tagged someone who's not directly involved)
@davibe thanks for your demo and babel-plugin-wrap-in-js
In the example I see use of a CSS file, and a SCSS file. Do you know if this would work with postcss & cssnext?
@khrome83 I don't see why not, I think its just a matter of adjusting .babelrc and next.config.js
@davibe I found that I was unable to deploy my app based on your configuration. The build was unable to read next/babel
in the .babelrc
file. I submitted an issue, but I'm really hopeful that a solution emerges from all this. Missing the ease of import file.css
from create-react-app
, but I know there must be a solution coming :)
The solution I want is likely along these lines:
https://github.com/zeit/styled-jsx/pull/100#issuecomment-277133969
We might support importing .css
(by means of simply transpiling it into a module that exports a string) (and likewise we might support .svg
by transpiling it into a pure react component)
and likewise we might support .svg by transpiling it into a pure react component
This is a pretty simple trick. I'll create a basic example showing how I handled this in another project =)
EDIT: see https://github.com/zeit/next.js/pull/982
Based on @davibe sample I've created https://github.com/moxystudio/next.js-style-loader that will hopefully ease out adding css files into next.js projects. It's similar to webpack's style-loader
in that it will add/remove stylesheets as the user navigates. It also supports SSR.
It does work well with css-loader
(with and without css modules), postcss-loader
, sass-loader
and possibly others. Note that when css-loader is used, its url
option must be set to false
beucase next.js images, fonts, etc must live /static
. You will find all this information in the README.
Enjoy and please give me feedback!
Thanks for the repo! It worked for importing the css files. I am trying blueprintjs and it seems like the css is loading correctly! However the @font-face rule that the css is including doesn't seems to work. :\
--------------------edit----------------------
It is actually working, my bad! However the icons are not being loaded because nextjs routing by default doesn't allow serving static content outside /static/ and relative path actually cause it to load with path that is not permitted.
@pencilcheck yes you must use paths pointing to /static, perhaps I will make that more clear in the README.
Is there any workaround regarding relative path included in the css files such as fonts atm? Or I simply have to copy the whole font files and css into static folder in order for it to work?
@pencilcheck the CSS files can stay outside of static. Your images and fonts must be inside static and you reference them with /static/file
.
I get it. However I'm using blueprint, which is an npm package, I would like to be able to not have to modify any files inside node_modules.
@pencilcheck That's not possible unfortunately. next.js is very strict in how it handles images and other assets. Lets not pollute this conversation and please create an issue in next-style-loader repo if you may.
@tgoldenberg can you describe the problem better or tell me how to reproduce ? please refer to my repository. It's easyer for me to track issues there.
@davibe, it ended up being a problem using yarn
over npm install
. Yarn was throwing some inexplicable errors, but once I removed it the example worked fine in production.
I just spent 4 hours trying to set this up and thought it might be of interest for anybody looking to save some time. It applies styles automatically on change (just like in the current example), runs the CSS through PostCSS and gives you local module names from css-loader
. The lack of the latter were major deal breakers for me in the current state of the “global css”/“css imports” examples.
component.js
import React from 'react';
import stylesheet from './styles.css';
const [css, className] = stylesheet;
const Component = () => (
<p className={className.paragraph}>
<Head><style dangerouslySetInnerHTML={{__html: css}} /></Head>
bazinga
</p>
);
.babelrc
{
"presets": [
"next/babel"
],
"plugins": [
["wrap-in-js", {
"extensions": ["css$"]
}]
]
}
next.config.js
Notice the amazing hack with exports-loader
. There's got to be a better way, surely???
module.exports = {
webpack: (config) => {
config.module.rules.push(
{
test: /\.css$/,
use: [
{
loader: 'emit-file-loader',
options: {
name: 'dist/[path][name].[ext]'
}
},
{
loader: 'raw-loader'
},
{
loader: 'val-loader'
},
{
loader: 'exports-loader',
options: {
0: 'exports[0][1]',
1: 'exports.locals'
}
},
{
loader: 'css-loader',
options: {
modules: true,
minimize: true
}
},
{
loader: 'postcss-loader'
}
]
}
);
return config;
}
};
I came up with a solution myself, which is very similar to what @satazor posted higher up in the thread: https://github.com/jozanza/next-css-json-loader.
Just add a few lines to your next.config.js
:
module.exports = {
webpack: config => {
config.module.rules.push({
test: /\.css$/,
loader: 'emit-file-loader',
options: {
name: 'dist/[path][name].[ext]',
}
}, {
test: /\.css$/,
loader: 'babel-loader!next-css-json-loader',
});
return config;
},
};
Styles are imported as js objects so it's very easy to use with glamor
and similar solutions:
// .css files now conveniently expose all styles as js objects
import styles from 'some-package/styles.css';
import { css } from 'glamor';
// ...
<div {...css(styles)}>
this is a nice box.
</div>
Cheers! 🍻 :)
Is there a way to make this work for importing markdown files as strings? I am currently using raw-loader, but as it is a webpack plugin it doesn't work on the server.
@kristojorg
I just wrote a babel plugin for markdown import. On my mobile right now, but if you view my GitHub you will see it.
@khrome83 that sounds awesome. Looking forward to trying it out
Thank you @khrome83! I'll give it a shot
I had to do this really quickly, so I did not update the readme. But you just include it as a babel plugin, and then use
import File from 'File.md';
I got it to work, thank you !! Very helpful
Sometimes it's nice to break out your CSS into a separate
.css
file. I've tried to do the following:Then in the index.js, I've tried to do:
And in next.config.js:
But unfortunately, it keeps giving me:
Seems like it's not resolving to the right place for some reason, the local
component.js
works though viaimport component from './component.js'
, so I'm not sure what's going on here.