Next.js 全局 CSS 只能从 Custom <App> 以外的文件中导入。

65

我的React应用程序一直很好,也使用了全局CSS。

我运行了npm i next-images,添加了一个图片,编辑了next.config.js文件,运行了npm run dev,现在我收到了这个消息:

全局CSS不能从除您的自定义<App>之外的文件中导入。请将所有全局CSS导入移动到pages/_app.js。
阅读更多:https://err.sh/next.js/css-global

我已经查看了文档,但由于我是React新手,我觉得说明有点混乱。

此外,为什么会出现这个错误?你认为这与npm安装有关吗?

我尝试删除我添加的新文件以及它们的代码,但这并没有解决问题。我也尝试了“阅读更多”中建议的方法。

我的最高层组件:

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;

我的 next.config.js

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

我的 main.scss 文件
@import './fonts.scss';
@import './variables.scss';
@import './global.scss';

我的global.scss

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

我觉得最奇怪的是,这个错误出现时并没有更改任何与CSS或Layout.js有关的内容,而且之前它还能正常工作?
我已经将main.scss导入到pages/_app.js页面中,但样式仍然无法生效。以下是_app.js页面的代码:
import '../global-styles/main.scss'

export default function MyApp({ Component, props }) {
  return <Component {...props} />
}
13个回答

51

使用内置的Next.js CSS加载器(参见此处),而不是传统的@zeit/next-sass

  1. @zeit/next-sass包替换为sass
  2. 删除next.config.js。或者不要在其中更改CSS加载。
  3. 按错误消息建议移动全局CSS。

自Next.js 9.2以来,全局CSS必须在自定义<App>组件中导入。

// pages/_app.js

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

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

要仅将样式添加到特定组件或页面,可以使用内置的CSS模块支持(请参见此处)。

例如,如果您有一个名为Button.js的组件,则可以创建一个Sass文件button.module.scss并将其包含在该组件中。


嗨,我之前创建并移动了main.scss到那个文件,但它没有起作用。我已经尝试过了,但仍然没有应用它。我在那里有以下代码:import '../global-styles/main.scss'export default function MyApp({ Layout, props }) { return <Layout {...props} /> } - IndustryDesigns
1
@IndustryDesigns,请尝试使用node-sass代替@zeit/next-sass,我刚刚测试过并更新了答案。如果您在命令行或浏览器控制台中遇到任何特定错误,请告诉我。 - Nikolai Kiselev
1
这绝对有所改善。全局 CSS 现在在 _app.js 中起作用了。最后一件尚未生效的事情是之前有效的::global { .marginsContainer { width: 90%; margin: auto; } } - IndustryDesigns
3
我得出这个答案是因为我正在尝试在组件中使用 SCSS,现在显然需要将我的 SCSS 文件从 components/my-component/ 文件夹中分离出来并放在 pages 中?我很困惑。 - andrevenancio
1
@AntonDozortsev,自Next.js 9.2以来(请参见Next.js 9.2博客文章),已经支持内置CSS全局样式表。 - Nikolai Kiselev
显示剩余7条评论

19

Next.js 在你的文件名中包含 module 时,不再出现警告,例如将 import '../global-styles/main.scss'; 更改为 import '../global-styles/main.module.scss'; 将修复该警告,您可以在 global-styles 中拥有自己的样式,或者例如在您的 component 中。

无需在next.config.js中添加额外的依赖或配置。


谢谢,这很有帮助。我的文件名从todo.modules.scss改为了todo.module.scss,现在可以正常运行了。 - Tankiso Thebe

7
您可以用自己的方式替换NextJs CSS加载器,这可能会更符合您的想法(和更简单)?以下是一个适用于全局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
  },
}

另外,如果有字体需要导入,我们也可以将file-loader添加到规则中。 - Vipul Panth

4
将以下内容添加到您的_app.js文件中。
import '../styles/globals.css'

你的回答可以通过添加更多支持信息来改进。请[编辑]以添加更多细节,例如引用或文档,以便其他人可以确认您的答案是否正确。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Omatt

3
这个 Node 包为 IT 技术提供了完美的解决方案。您可以在这里找到它。
修复步骤: 1. 添加包:
npm install next-remove-imports
or
yarn add next-remove-imports

2. 在你的next.config.js中添加这个包装变量。

const removeImports = require('next-remove-imports')({
   test: /node_modules([\s\S]*?)\.(tsx|ts|js|mjs|jsx)$/,
   matchImports: "\\.(less|css|scss|sass|styl)$"
 });

它所做的只是重新启用 tsx|ts|js|mjs|jsx 文件的全局样式导入规则。

3. 使用 next-remove-imports 包装器包装您的下一个配置导出。类似于以下内容:

module.exports = removeImports((nextConfig)

4. 现在重新启动你的React应用,你就可以在任何ts|js|js|jsx|mjs文件或组件中导入CSS文件了。


2

将所有的 .css /.scss 文件转换为 [filename].module.css / [filename].module.scss

在您的情况下,应将其重命名为

import '../global-styles/main.scss' 改为 import '../global-styles/main.module.scss'

在高级生产级项目中进行了测试。对我来说完美地工作了。


2

对我来说,问题是因为我在next.config.js文件中使用了两个module.exports,就像这样:

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'
    }
}

1我修改了它,将导出模块更改为以下内容。

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"
    }
}

2然后我删除了第二个module.exports


请阅读有关common.js模块如何工作的内容。第二个 module.exports 会覆盖第一个。您的第一个NextJS配置实际上不会被应用。 - HosseinAgha

1

尝试在scss文件名中包含".module"。

main.scss更改为main.module.scss

示例:

import styles from './todolist-profile-info.module.scss'

0

next.config.js 文件中不需要做任何事情。

假设您正在使用全局 CSS,例如 Bootstrap,这意味着它包含应用于整个应用程序及其中所有不同页面的 CSS。

必须以非常特定的方式将全局 CSS 文件连接到 NextJS 中。

因此,在 pages/ 目录中,您需要创建 _app.js

文件名为 _app.js 至关重要。

然后,在该文件顶部,您可以按以下方式导入 Bootstrap CSS:

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

接下来添加以下内容:

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

那么在这段代码中发生了什么呢?

实际上,当你试图使用NextJS导航到某个独特的页面时,它会从pages/目录中的不同文件之一中导入你的组件。

NextJS并不只是取出你的组件并在屏幕上显示它。

相反,它将其包装在自己的自定义默认组件中,NextJS称之为App。

通过定义_app.js,你正在定义自己的自定义应用程序组件。

所以,每当你尝试在浏览器或根路径中访问路由时,NextJS将导入给定的组件并将其作为Component属性传递到AppComponent中。

因此,在那里的Component等于你在pages/目录中拥有的所有组件。然后,pageProps将成为你要传递到pages/内文件中的组件集。

长话短说,这个东西就像是围绕着你试图在屏幕上显示的组件的薄包装。

为什么你必须这样定义呢?

如果您想要在项目中包含一些全局 CSS,例如 Bootstrap,您只能将全局 CSS 导入到 _app.js 文件中。

事实证明,如果您尝试访问其他组件或其他页面,NextJS 不会加载或解析这些文件。

因此,您可能已经导入的任何 CSS 都不会包含在最终的 HTML 文件中。

所以,如果您有一个必须在每个页面上都包含的全局 CSS,它必须被导入到 app 文件中,因为它是唯一保证在用户访问您的应用程序时每次都会加载的文件。

请不要忘记,在 _app.js 中导入 CSS 的同时,您还需要在终端中运行 npm install bootstrap

您可以在此处阅读更多信息: https://nextjs.org/docs/messages/css-global


所以每个 CSS 文件,你需要放在 _app.js 文件中,对吗? - undefined

0

这对我来说解决了问题, 现在我可以像这样使用: import Feed from "@components/Feed";

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接