yoyo
yoyo

Reputation: 583

Selector ":root" is not pure (pure selectors must contain at least one local class or id) - NextJS with SASS modules

I've recently been switching to using modules in my next.js project, but I keep receiving this error in my newly created .module.scss files: "Selector ":root" is not pure (pure selectors must contain at least one local class or id)". I know this is because I'm not using pure css selectors as I've seen elsewhere online, and the only problem is the imports that I'm using, but I need those imports for variables like $cl-light-gray as seen below in this example file:

@import "src/common/styles/global-styles.scss";
@import "node_modules/bootstrap/scss/bootstrap";
@import "src/common/styles/palette.scss";
@import "src/common/styles/typography.scss";

.dashboard-dropdown-hover {
  @extend .px-1;
  @extend .py-2;
  @extend .mt-3;
  border: 1px solid transparent;
  border-radius: 8px;
  transition: 200ms;
  background-color: transparent;
}
.dashboard-dropdown-hover:hover {
  background-color: $cl-light-gray;
}

Does anyone have a solution to how I should fix this import problem? I know that if I switch back to .scss it will work, but I'm trying to avoid importing all the .scss files in _app.tsx because that would be at least 30 imports and also these styles aren't intended to be global. Lastly, why does Next.js expect me to use pure css selectors when I'm using Sass, which is used because of its non-pure elements?

Upvotes: 12

Views: 22063

Answers (4)

Alfredows
Alfredows

Reputation: 91

In my particular case i was having the same headache with that issue, and was because i was trying to import the file with the path:

/node_modules/bootstrap/scss/bootstrap-utilities.scss

and that file was importing another file called _root.scss which was defined a selector in this style.

:root{

 }

for solution that error i simply import the specific files used for my requirements

Another resources could help you:

Upvotes: 0

Abel Wenning
Abel Wenning

Reputation: 651

Any global styles (e.g., :root or any HTML elements/CSS classes that you want to have the same style absolutely everywhere in your app) should be placed into a global CSS file that you import into _app.js (which you just can add to the root folder of your project, if it doesn't already exist). This global CSS file is also where you want to import any fonts that you will use app-wide.

Step-by-step instructions here: https://nextjs.org/docs/basic-features/built-in-css-support

Upvotes: 3

Yair Kukielka
Yair Kukielka

Reputation: 11406

As pointed out here, there is another option: you can import those styles in the global.css file. If you do that, Nextjs will be happy.

Upvotes: 5

yoyo
yoyo

Reputation: 583

After scouring the internet for a few hours I found a great solution from here: https://dhanrajsp.me/snippets/customize-css-loader-options-in-nextjs

EDIT: If you're using Next.js 12, check the bottom of the article above, because the solution is a little different.

You'll want to change your next.config.js file to include the following:

/** @type {import('next').NextConfig} */
require("dotenv").config();
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
  );
};
// Overrides for css-loader plugin
function cssLoaderOptions(modules) {
  const { getLocalIdent, ...others } = modules; // Need to delete getLocalIdent else localIdentName doesn't work
  return {
    ...others,
    localIdentName: "[hash:base64:6]",
    exportLocalsConvention: "camelCaseOnly",
    mode: "local",
  };
}
module.exports = {
  webpack: (config) => {
    const oneOf = config.module.rules.find(
      (rule) => typeof rule.oneOf === "object"
    );
    if (oneOf) {
      // Find the module which targets *.scss|*.sass files
      const moduleSassRule = oneOf.oneOf.find((rule) =>
        regexEqual(rule.test, /\.module\.(scss|sass)$/)
      );

      if (moduleSassRule) {
        // Get the config object for css-loader plugin
        const cssLoader = moduleSassRule.use.find(({ loader }) =>
          loader.includes("css-loader")
        );
        if (cssLoader) {
          cssLoader.options = {
            ...cssLoader.options,
            modules: cssLoaderOptions(cssLoader.options.modules),
          };
        }
      }
    }
    return config;
  },
};

I'm not seasoned with webpack or how it exactly works, but this solution worked for me. You can also change the regex to include css by doing (scss|sass|css) if you want.

Upvotes: 6

Related Questions