Importing a stylesheet from a package is not possible in a page, because next throws with this error:
Global CSS cannot be imported from files other than your Custom <App>. Please move all global CSS imports to pages/_app.tsx.
Read more: https://err.sh/next.js/css-global
While I understand where this stems from, it makes code-splitting impossible. If I import a component from a component library, I need to import the CSS as well. There might be libraries that don't correctly scope their selectors, but that shouldn't stop me from overwriting this warning. CSS that is imported from a library isn't inherently "global".
import "my-library/index.css"
yarn dev
The file should be imported.
I see these possible solutions:
next.config.js
There have been previous discussions about this.
Since stylesheets are global by nature, they must be imported in the Custom
component. This is necessary to avoid class name and ordering conflicts for global styles.
I disagree with this statement, the reasoning being that an external library can use CSS modules and package them as a CSS file to import. Which is perfectly valid and common practice and does not have side effects.
This issue got closed because the global import in _app
is the correct choice there.
This comment describes the exact problem, but there hasn't been any response, as the issue is closed. The comment got a lot of positive reactions though, so I suppose I'm not the only one with this problem.
Seems to be unrelated.
Might be related, but I'm not sure.
I write long articles with a lot of custom artwork and interactive illustrations. Articles use private npm packages with react components that render SVG with quite a bit of CSS. These packages use CSS modules and export an index.js
and index.css
. Adding all the CSS files to _app
causes all the CSS to be loaded, even if people are on the home page, the contact form, or any other article, even though it's 100% unused. It also goes against having the file system take care of your pages because almost every page corresponds to a CSS import in _app
.
I'm facing this same problem simply trying to use Linaria, which scopes its own class names. Though the css files it produces don't end in .module.css
, they're "modules." I need an easy way to integrate with the library.
why did even switch to nextjs again?
I'd also like to be able to use GlobalCSS outside of node_modules. This would help us incrementally adopt CSS Modules
yeah this is very important! many npm packages are not working with nextjs but work with CRA, or other frameworks
For anyone else that's trying to use this with dart sass' js implementation for things like @use
support and sass modules, if you have -any- other node module that has a dependency on node-sass, the default next setup will use node-sass instead of sass. Locally I've fixed it by doing the following:
// example next.config.js
module.exports = {
webpack(config, options) {
config.module.rules.forEach(rule => {
if (rule.oneOf) {
const nestedScss = rule.oneOf.find((one) => {
return one.test
&& 'some.scss'.match(one.test)
&& one.issuer
&& one.issuer.include
&& one.issuer.include.includes('_app');
});
if (nestedScss) {
const sassLoader = nestedScss.use.find(u => u.loader.includes('sass-loader'));
// Set implementation to sass instead of node-sass here.
sassLoader.options.implementation = require('sass');
}
}
})
}
}
You'll then need to import your scss files in _app.js
.
@smurrayatwork this is hacking not coding sorry
Also the restriction on it being exclusively _app.js is a little cumbersome.
If we're not going to support CSS references everywhere then could we make it so CSS can also be referenced by direct dependencies of _app
(that are not referenced anywhere else)?
ie. It's fine if it's required by _app
(and nowhere else) which would give the CSS a deterministic order based off imports.
It's not ideal however the use case I have is that I have is one codebase shared by multiple applications that import a shared module which imports shared CSS. I'd hate to duplicate those shared CSS imports in _app.js for every application. Currently to get around that I'd have to do some fancy js metaprogramming because we can't require css in other modules.
Instead I would like my current approach to work which is I have an "App Factory" which imports all the shared CSS. _app then uses the factory and imports its own CSS on top of the shared ones.
I'm adding https://github.com/vercel/next.js/discussions/13991 as I think it relates to this issue.
+100 to this. I'm having to copy and paste node module css files into my project and adding a .module.css on them
Here's another example.
In the case of the package pdf-viewer-reactjs
its dependencies require CSS that need to be imported from _app.js
as well.
This is bloating the CSS for the whole app and I am not sure about conflicts at this stage.
import 'react-quill/dist/quill.snow.css';
import 'react-image-crop/dist/ReactCrop.css';
import '../../node_modules/material-design-icons/iconfont/material-icons.css';
import '../../node_modules/bulma/css/bulma.css';
import '../../node_modules/bulma-helpers/css/bulma-helpers.min.css';
Additionally the following is output to console:
warn - ./node_modules/material-design-icons/iconfont/material-icons.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
Location: node_modules/pdf-viewer-reactjs/dist/pdf-viewer-reactjs.js
./node_modules/bulma/css/bulma.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
Location: node_modules/pdf-viewer-reactjs/dist/pdf-viewer-reactjs.js
./node_modules/bulma-helpers/css/bulma-helpers.min.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
Location: node_modules/pdf-viewer-reactjs/dist/pdf-viewer-reactjs.js
./node_modules/material-design-icons/iconfont/material-icons.css
Module build failed: Error: Final loader (./node_modules/next/dist/build/webpack/loaders/error-loader.js) didn't return a Buffer or String
./node_modules/bulma/css/bulma.css
Module build failed: Error: Final loader (./node_modules/next/dist/build/webpack/loaders/error-loader.js) didn't return a Buffer or String./node_modules/bulma-helpers/css/bulma-helpers.min.css
Module build failed: Error: Final loader (./node_modules/next/dist/build/webpack/loaders/error-loader.js) didn't return a Buffer or String
Hi ! Do someone resolved this and how ? So many node modules that I can't import because of that.
Maybe using global styles in components could be activated via next.config.js
, or an ugly console warning against global styles could be shown, in case there is concern about breaking from NextJS' best practices / opinions.
But this is important for users converting from CRA > NextJS. It's a blocker for us b/c we can't switch & then incrementally adopt things like CSS modules.
Still unable to get around this. For my own needs I used a custom CSS handler, but this disables built-in CSS support but it may not be a good solution for all cases . The below is discouraged , use only until the package authors sort it out
next.config.js
const withCSS = require('@zeit/next-css');
const withPlugins = require('next-compose-plugins');
...
module.exports = withPlugins([
...
withCSS,
]);
@abdelrahmantoptal's Do you know how to get that working for SASS?
It appears it would work for CSS, but throws an error when encountering a SASS import:
error - ./src/components/layouts/Footer.scss 1:0
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> @import 'styles/vars';
|
| footer {
so I tried adding a SASS loader to the webpack config before using the withCSS plugin:
config.module.rules.push({
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader'
]
});
But that caused:
error - ./src/components/App.scss
ReferenceError: self is not defined
I also tried substituting @zeit/next-sass
, but that caused the same error:
error - ./src/components/App.scss
ReferenceError: self is not defined
Any suggestions on how to tweak your code to use SASS?
Somebody by any chance successfully implemented https://github.com/balena-io-modules/rendition ?
I've now thrown out Gatsby and soon Next.js because of their small, but very blocking, opinionated features such as this one. I am now unable to use the CodeBlock
plugin for CKEditor 5 because I can't get around this error. There should always be some way to circle these configurations.
It would be very helpful to have news from @Timer or someone from Vercel about this problem. This is a big problem with Next.js. Something is planned to fix this?
Agreed! It's incredibly common to have css in node modules. As a developer, I have no control over how other developers structure their node modules, and other developers don't expect that putting css in a node module would break a web framework.
@OssiPesonen have you seen this yet? This workaround isn鈥檛 ideal, but it solved the problem for me in the meantime.
@OssiPesonen have you seen this yet? This workaround isn鈥檛 ideal, but it solved the problem for me in the meantime.
I don't see how this helps? The problem is not me having to manually import some CSS files from node modules. The problem is npm packages doing the CSS importing in themselves. A package that includes a row like this:
import '../theme/stylesheet.css'
Will cause next.js to crash with a vengeance. And apparently the maintainer's advice is:
Reach out to the maintainer and ask for them to publish a compiled version of their dependency.
In what kind of fantasyland do people live in where they imagine you can just contact maintainers ask them to re-compile their package for you in a very fast pace? This will hinder anyone for weeks! This ticket has been open for 4 months. That's unacceptable when working on quickly moving projects.
We're going to be allowing importing CSS from node_modules
into any component file within the next week (on canary)! We'll post here when it's ready to test.
If anyone needs this prior to the release, I was able to use the next-transpile-modules plugin to transpile the module from node_modules
that was importing CSS. Worked like a charm for me.
@BrandonE seems that next-transpile-modules still needs to have the modules named *.module.css
. Did you find a way around that?
@rjoaopereira I can't say I have a deep understanding of how any of this works, but most of my node_modules
that imported CSS only worked with the @zeit/next-css
plugin. Only one did not, at which point transpiling fixed the issue. Far from an elegant solution, and I hope that future versions of Next.js allow us to spend less time on Babel / Webpack alchemy and more on making web applications.
I got this almost working with the following changes.
next 9.5.3
next-transpile-modules 4.1.0
1st party components with emotion.
3rd party components with a mix of css modules and global css
scopedcomponents
is to be replaced with the 3rd party components being used
//next.config.js
const withCustomWebpack = require("./webpack-custom.config");
const withNextCSSOverride = require("./next.config.css");
const withTM = require("next-transpile-modules")(["@scopedcomponents"]);
module.exports = withCustomWebpack(
withTM(
withNextCSSOverride({
poweredByHeader: false
})
)
);
///next.config.css.js
const {
getCssModuleLocalIdent
} = require("next/dist/build/webpack/config/blocks/css/loaders/getCssModuleLocalIdent");
const path = require("path");
/**
* Stolen from https://stackoverflow.com/questions/10776600/testing-for-equality-of-regular-expressions
*/
const regexEqual = (x, y) => {
return (
x instanceof RegExp &&
y instanceof RegExp &&
x.source === y.source &&
x.global === y.global &&
x.ignoreCase === y.ignoreCase &&
x.multiline === y.multiline
);
};
module.exports = (nextConfig = {}) => {
return Object.assign({}, nextConfig, {
webpack(config, options) {
const nextCssLoaders = config.module.rules.find(
rule => typeof rule.oneOf === "object"
);
if (nextCssLoaders) {
const nextCssLoader = nextCssLoaders.oneOf.find(
rule =>
rule.sideEffects === false &&
regexEqual(rule.test, /\.module\.css$/)
);
if (nextCssLoader) {
/***********************************************************
* change the rule to match all scopedcomponents css files
***********************************************************/
nextCssLoader.test = /(@scopedcomponents|react\-virtualized)\/.*\.css$/;
const cssLoader = nextCssLoader.use.find(({ loader }) =>
loader.includes("css-loader")
);
if (cssLoader) {
/***********************************************************
* Override the default behaviour for CSS modules discovery
* auto = true makes webpack search for *.module.css
* https://webpack.js.org/loaders/css-loader/#auto
***********************************************************/
cssLoader.options.modules.auto = /@scopedcomponents\/.*\.css$/;
/***********************************************************
* Nextjs overrides the default mode to "Pure"
* https://github.com/vercel/next.js/blob/v9.5.2/packages/next/build/webpack/config/blocks/css/loaders/modules.ts#L35
* Put it back to normal
***********************************************************/
cssLoader.options.modules.mode = "local";
/***********************************************************************************************************************
* There is a problem when using components built with css-modules with Nextjs. *
* NextJS will consume code from `lib` on the server side and from `es` on the client. *
* https://github.com/vercel/next.js/blob/v9.5.2/packages/next/build/webpack-config.ts#L374 *
* This raises a problem when generating the classes for different environments, *
* throwing an error of className mismatch due to the hash created being based on the file path *
* https://github.com/vercel/next.js/blob/v9.5.2/packages/next/build/webpack/config/blocks/css/loaders/modules.ts#L26 *
* https://github.com/webpack/loader-utils/blob/v1.4.0/lib/interpolateName.js#L39 *
* To solve this, when generating the classNames for 3rd party components, *
* we need to tell cssloader to always use the same path * *
* *
* https://github.com/zeit/next-plugins/issues/595 *
***********************************************************************************************************************/
cssLoader.options.modules.getLocalIdent = (
context,
localIdentName,
localName,
options
) => {
const newContext = { ...context };
if (newContext.resourcePath.includes("@scopedcomponents")) {
newContext.resourcePath = newContext.resourcePath.replace(
`${path.sep}es${path.sep}`,
`${path.sep}lib${path.sep}`
);
}
return getCssModuleLocalIdent(
newContext,
localIdentName,
localName,
options
);
};
}
}
}
if (typeof nextConfig.webpack === "function") {
return nextConfig.webpack(config, options);
}
return config;
}
});
};
Problems:
@Timer any update on this?
We're going to be allowing importing CSS from
node_modules
into any component file within the next week (on canary)! We'll post here when it's ready to test.
Will there be dynamic import of CSS from a component after this fix?
Thank you so much @Timer
next@^9.5.4-canary.10
now allows you to import Global CSS from node_modules
anywhere in your application. This improves interoperability with third-party React libraries that require you import their CSS, but don't want it to increase bundle size for your entire application.
@Timer Can't wait to have that release, really appreciated your work 馃挴 鉂わ笍
Thanks @Timer !
This has been a blocking issue for me currently, however when I tested this out today, still seeing the same error message. Is there anything more to it than simply upgrading to 9.5.4-canary-10? This example is trying to use 3rd party lib @rmwc
@johmike Are you importing using the following syntax??
import "@rmwc/avatar/avatar.css";
Did you tried restarting the dev server after installing the latest version of next
?
@Timer Thanks a lot for this feature. Works great for importing CSS file from node_modules
folder.
import 'prism-themes/themes/prism-darcula.css';
Any plans to support import of global css outside the node_modules
dir?
@sasivarnan
This is coming from another library that is importing the @rmwc components. That library is using @require("@rmwc/avatar/avatar.css")
. I am importing import {Avatar} from "library/Avatar"
and that is failing.
@sasivarnan
This is coming from another library that is importing the @rmwc components. That library is using
@require("@rmwc/avatar/avatar.css")
. I am importingimport {Avatar} from "library/Avatar"
and that is failing.
Got it. I thought it was imported directly in your application. My bad.
Judging from the comments here, this actually isn't resolved or it was resolved but many people here report a different issue. Many people still cannot import modules, which import CSS from the packge itself (an import style.css
statement inside a package file).
The fix seems to allow the app to import CSS from node_modules/
path, but there's a pretty easy way to go around this: just copy the CSS to your app for now until it's fixed. It's not a blocker level issue. So it did not really solve the blocker issue to which there is no easy solution. If you import a component which has an import statement to a CSS file the package itself contains, the app crashes.
@sasivarnan @OssiPesonen you both seem to be talking about a different issue than what was being discussed and fixed in this OP issue.
This specifically fixes libraries that require you import their CSS in your application, for example:
// components/MySlider.tsx
import { Slider } from "@reach/slider";
import "@reach/slider/styles.css";
function Example() {
return <Slider min={0} max={200} step={10} />;
}
What you're talking about is a duplicate of #706 and #13282, or the ability to treat node_modules
like first-party code.
@Timer I just tested the expected use case and it does indeed work fine.
When I import the css in a component directly as part of the next structure it works as expected, no errors.
However if I move that component into another package outside of the next structure, build, and then install that package, it fails back to the same error as before.
It's possible something else is going on, as I'm not even using the Avatar
component in this example, I am importing Button
and yet Avatar
is the failing error.
Also I added next-transpile-modules
as we are working from a monorepo, but that didn't seem to help this particular issue.
I got this working by a strange configuration file from digging through a bunch of other issues around next-transpile-modules
.
const withCSS = require("@zeit/next-css");
module.exports = withCSS();
require.extensions[".css"] = () => {
return;
};
I eliminated next-transpile-modules
and this works. I have no idea why, it seems like it shouldn't do anything?
I spoke too soon! While that does work for next dev
, next build
fails with an unknown token .
(dot) error from one of the CSS files.
@Timer Any thoughts? Should this work out of the box with a monorepo and multiple packages? Or is there something else I need to configure so that @team/packageA can import css from node_modules and then be imported into @team/packageB?
You can follow https://github.com/vercel/next.js/issues/13282 for that behavior.
Using [email protected] it is possible to import css anywhere in my application. But will the same be possible for scss files? I would like to import only the scss files that I am actually using on a page.
// pages/_app.tsx
import '../styles/common.scss'
// pages/index.tsx I use a Button
import '@mynpm/custom-ui/_Button.scss'
// pages/about.tsx I use a Carousel
import '@mynpm/custom-ui/_Carousel.scss'
The example at https://nextjs.org/docs/basic-features/built-in-css-support
Returns the error:
error - /Users/gp/dev/next-kolumbus/node_modules/@reach/dialog/styles.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
The example at https://nextjs.org/docs/basic-features/built-in-css-support
Returns the error:
error - /Users/gp/dev/next-kolumbus/node_modules/@reach/dialog/styles.css
Global CSS cannot be imported from within node_modules.
Read more: https://err.sh/next.js/css-npm
Make sure you're on the latest version of Next.js.
Sorry, I didn't specified it in the previous comment. I used version 9.5.5. just updated from npm.
I cleared all the .next cache and now it works as expected.
The error still there version 9.5.5, in _app
--> import "react-gauge-chart-nextjs-support/dist/GaugeChart/style.css";
Most helpful comment
We're going to be allowing importing CSS from
node_modules
into any component file within the next week (on canary)! We'll post here when it's ready to test.