Next.js Global CSS cannot be imported from files other than your Custom <App>

71,462

Solution 1

Use the built-in Next.js CSS loader (see here) instead of legacy @zeit/next-sass.

  1. Replace @zeit/next-sass package with sass.
  2. Remove next.config.js. Or do not change CSS loading in it.
  3. Move the global CSS as suggested in the error message.

Since Next.js 9.2 global CSS must be imported in Custom <App> component.

// pages/_app.js

import '../global-styles/main.scss'

export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

To add styles only to a specific component or page you can use built-in support of CSS modules. (see here)

For example, if you have a component Button.js you can create a Sass file button.module.scss and include it in the component.

Solution 2

Next.js stops complaining when your file has module in naming, e.g., changing import '../global-styles/main.scss'; to import '../global-styles/main.module.scss'; would fix the warning and you could have your styles in the global-styles, or for example, in your component.

No extra dependencies/configurations in next.config.js is required.

Solution 3

You can replace the opinionated (and overly-complex?) NextJs CSS loaders with your own. Here's a simple one for global css:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  reactStrictMode: true,
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    // Find and remove NextJS css rules.
    const cssRulesIdx = config.module.rules.findIndex(r => r.oneOf)
    if (cssRulesIdx === -1) {
      throw new Error('Could not find NextJS CSS rule to overwrite.')
    }
    config.module.rules.splice(cssRulesIdx, 1)

    // Add a simpler rule for global css anywhere.
    config.plugins.push(
      new MiniCssExtractPlugin({
        experimentalUseImportModule: true,
        filename: 'static/css/[contenthash].css',
        chunkFilename: 'static/css/[contenthash].css',
      })
    )

    config.module.rules.push({
      test: /\.css$/i,
      use: !isServer ? ['style-loader', 'css-loader'] : [MiniCssExtractPlugin.loader, 'css-loader'],
    })
    return config
  },
}

Solution 4

For me the problem was because I had used two module.exports in my next.config.js file like this

const withPlugins = require('next-compose-plugins')
const sass = require('@zeit/next-sass')
const css = require('@zeit/next-css')

const nextConfig = {
    webpack: function(config){
    config.module.rules.push({
        test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
        use: {
        loader: 'url-loader',
            options: {
            limit: 100000,
            name: '[name].[ext]'
        }}
    })
    return config
    }
}

module.exports = withPlugins([
    [css],
    [sass, {
        cssModules: true
    }]
], nextConfig)

module.exports = {
    env: {
        MONGO_URI = 'your uri'
    }
}

. 1I modified it to change the export module like this.

const nextConfig = {
    webpack: function(config){
    config.module.rules.push({
        test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
        use: {
        loader: 'url-loader',
            options: {
            limit: 100000,
            name: '[name].[ext]'
        }}
    })
    return config
    },
    env: {
        MONGO_URI: "your uri"
    }
}

2then I deleted the second module.exports

Solution 5

You did not need to do anything inside of next.config.js.

Let's assume you are using a global css like Bootstrap, meaning it contains css that is meant to be applied to your entire application and all the different pages inside of it.

Global css files have to be wired up to NextJS in a very particular fashion.

So inside of the pages/ directory you need to create _app.js.

It's critical that the file be named _app.js.

Then at the top of that file you would import Bootstrap css in the following manner:

import 'bootstrap/dist/css/bootstrap.css';

Then you would add the following:

export default ({ Component, pageProps }) => {
  return <Component {...pageProps} />;
};

So what is going on in that code?

Well, behind the scenes, whenever you try to navigate to some distinct page with NextJS, NextJS will import your component from one of the different files inside your pages/ directory.

NextJS does not just take your component and show it on the screen.

Instead it wraps it up inside of its own custom default component and that is referred to inside of NextJS as the App.

What you are doing by defining the _app.js is to define your own custom app component.

So whenever you try to visit a route inside a browser or your root route, NextJS is going to import that given component and pass it into the AppComponent as the Component prop.

So Component there is equal to whatever components you have in the pages/ directory. And then pageProps is going to be the set of components that you are intending to pass to your files inside of pages/.

So long story short, this thing is like thin wrapper around the component that you are trying to show on the screen.

Why do you have to define this at all?

Well, if you ever want to include some global css to the project, Bootstrap being a global css for example, you can only import global css into the _app.js file.

It turns out that if you try to visit other components or other pages, NextJS does not load up or even parse those files.

So any css you may have imported inside there will not be included in the final HTML file.

So you have a global css that must be included on every single page, it has to be imported into the app file because it's the only file that is guaranteed to be loaded up every single time a user goes to your application.

Don't forget that in addition to importing the css inside of _app.js, you also have to run an npm install bootstrap in your terminal.

You can read more on this here: https://nextjs.org/docs/messages/css-global

Share:
71,462
IndustryDesigns
Author by

IndustryDesigns

HTML, CSS, JS, PHP, SQL

Updated on February 06, 2022

Comments

  • IndustryDesigns
    IndustryDesigns about 2 years

    My React App was working fine, using global CSS also.

    I ran npm i next-images, added an image, edited the next.config.js, ran npm run dev, and now I'm getting this message

    Global CSS cannot be imported from files other than your Custom <App>. Please move all global CSS imports to pages/_app.js.
    Read more: https://err.sh/next.js/css-global
    

    I've checked the docs, but I find the instructions a little confusing as I am new to React.

    Also, why would this error happen now? Do you think it has anything to do with the npm install?

    I've tried to remove new files I've added along with their code, but this doesn't fix the problem. I've also tried what the Read more: suggests.

    My highest tier component.

    import Navbar from './Navbar';
    import Head from 'next/head';
    import '../global-styles/main.scss';
    
    const Layout = (props) => (
      <div>
        <Head>
          <title>Bitcoin Watcher</title>
        </Head>
        <Navbar />
        <div className="marginsContainer">
          {props.children}
        </div>
      </div>
    );
    
    export default Layout;
    

    My next.config.js

    // next.config.js
      const withSass = require('@zeit/next-sass')
      module.exports = withSass({
      cssModules: true
    })
    

    My main.scss file

    @import './fonts.scss';
    @import './variables.scss';
    @import './global.scss';
    

    my global.scss

    body {
      margin: 0;
    }
    :global {
      .marginsContainer {
        width: 90%;
        margin: auto;
      }
    }
    

    The thing I find the weirdest is that this error came without changing anything to do with CSS, or Layout.js, and it was previously working?

    I've moved my main.scss import to the pages/_app.js page, but the styles still aren't coming through. This is what the _app.js page looks like

    import '../global-styles/main.scss'
    
    export default function MyApp({ Component, props }) {
      return <Component {...props} />
    }