Skip to content
This repository has been archived by the owner on Jul 6, 2021. It is now read-only.

Unable to have both SASS Modules and Global Stylesheets #149

Closed
1 task done
eugeneross opened this issue Apr 20, 2018 · 34 comments
Closed
1 task done

Unable to have both SASS Modules and Global Stylesheets #149

eugeneross opened this issue Apr 20, 2018 · 34 comments

Comments

@eugeneross
Copy link

  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

I want to expect styles from my modules to be compiled into the same stylesheet as my global styles. Please see demo setup below to understand where styles are being pulled from.

├── pages
│   ├── index.js
├── components
│   ├── Button
│   │   ├── index.js
│   │   ├── index.sass
├── styles
│   ├── index.sass (Global stylesheet with @imports)

Current Behavior

Can't get both modules and global styles to work together in parallel. Only one of them can be used while the other cannot. Please see my comments in this demo repo in the files, _document.js and styles/index.sass

Steps to Reproduce

  1. Clone this repo
  2. yarn && yarn dev
  3. View comments in _document.js and styles/index.sass to turn on and off behaviors.
  4. If you inspect the styles you'll see that the global styles are only being applied.
  5. Comment out line 5 in _document.js, save, and you'll notice that module styles will be applied but not the global styles.

Context

As stated in the above, I want the ability to use SASS modules within my components folder AND global styles in my styles folder together. As of right now I can either have styles from modules and NOT from my global stylesheet OR have styles from global stylesheet and not my modules.

The only work around I've found is including the path of a component's style inside my styles/index.sass file, like so:

@import '../components/Button/index'

The only issue with this is that the global stylesheet is imported into the _document.js and therefore reloads the page on save for those styles intstead of injecting those changes. That's not the biggest deal in the world, but not ideal.

I'm not sure if the issue is due to the way modules and _document.js work together, or if there needs to be a specific way to allow this within the next.config.js setup.

Your Environment

Tech Version
next 6.0.0-canary.4

Issue is persistant for stable releases too.

@EvHaus
Copy link

EvHaus commented Apr 30, 2018

+1 I'm having the exact same issue. As soon as you import a CSS Module from _document.js, all other scoped modules stop being bundled.

@jbsmith731
Copy link

I'm seeing the same thing in _app.js as well.

@mrshll
Copy link

mrshll commented May 1, 2018

This is the case for the stylus plugin as well.

@eugeneross
Copy link
Author

Wanted to add an update to this. @claus's solution found here works for my case. I was able to add a reference to the global stylesheet in my _document.js file while also having SASS modules enabled. It's a solid workaround👍

@mrshll
Copy link

mrshll commented May 7, 2018

@eugeneross solved it for me as well! Thank you for sharing.

@Silvercast
Copy link

but his solution will add all available CSS files into the head , right? For example I have pages A,B,C,D and each has its own SCSS file. Does it only load A and global style when I go to page A? otherwise it will be super heavy bundle.

@Grsmto
Copy link

Grsmto commented Jun 15, 2018

Hey,
This is not specifically for Sass but I think it's probably the same issue, so I created a Gist of a workaround for this based on @eugeneross solution: https://gist.github.com/Grsmto/8e7ade37862f1c8b4d019da8dd423450

It provides the same behaviour as CRA (Create React App) by allowing css-modules files (file.module.css) and normal css files (file.css) to work together and be extracted in the same stylesheet.

@andrewsosa
Copy link

Did this get any better with the release of Next 7? I'm really interested in applying a framework stylesheet globally but scoping my own stylesheets.

@bekliev
Copy link

bekliev commented Jan 5, 2019

Doesn't work with next 8.0.0-canary.2

TypeError: Cannot read property 'css' of undefined

@OndeVai
Copy link

OndeVai commented Feb 26, 2019

I ended up tweaking the "getLocalIdent" of the css loader options:

const path = require('path')
const loaderUtils = require('loader-utils')

cssLoaderOptions: {
    localIdentName: '[local]--[hash:base64:5]',
    getLocalIdent: (loaderContext, localIdentName, localName, options) => {
      const { resourcePath, rootContext } = loaderContext
      if (resourcePath.indexOf('.module.') < 0) return localName

      if (!options.context) {
        // eslint-disable-next-line no-param-reassign
        options.context = rootContext
      }

      const request = path
        .relative(rootContext, loaderContext.resourcePath)
        .replace(/\\/g, '/')

      // eslint-disable-next-line no-param-reassign
      options.content = `${request}+${localName}`

      // eslint-disable-next-line no-param-reassign
      localIdentName = localIdentName.replace(/\[local\]/gi, localName)

      const hash = loaderUtils.interpolateName(
        loaderContext,
        localIdentName,
        options
      )

      return hash
        .replace(new RegExp('[^a-zA-Z0-9\\-_\u00A0-\uFFFF]', 'g'), '-')
        .replace(/^((-?[0-9])|--)/, '_$1')
    }
  }

@adamjw3
Copy link

adamjw3 commented Jul 9, 2019

I'm having this issue when i have global variables that i want to access in modules, i get variable undefined. Anyone managed to fix this?

i have a global scss that i add in _app.js

@import "settings/all";
@import "bootstrap/bootstrap-grid";
@import "tools/all";
@import "generic/generic.reset";
@import "elements/elements.headingspara";
@import "elements/elements.images";
@import "elements/elements.links";
@import "elements/elements.page";

The in index.js i'm adding the following style sheet and $color-brand-primary is coming up as undefined. Do i need to add a loader?


div {
	background-color: $color-brand-primary;
}

@wedneyyuri
Copy link

I ended up using the solution described here: https://spectrum.chat/next-js/general/import-bootstrap-scss-and-enable-cssmodules-both~eb9113e1-f1f7-4427-bcd0-fe72c1a4d259

This is my _app.js:

import App, { Container } from 'next/app';
import React from 'react';
import { Provider } from 'react-redux';
import withReduxStore from '../lib/with-redux-store';

import './App.global.scss'; // Used to import bootstrap or any other global stylesheet.

import styles from './styles.scss'; // CSS modules can be imported as usual.

class MyApp extends App {
  render() {
    const { Component, pageProps, reduxStore } = this.props;
    return (
      <Container>
        <Provider store={reduxStore}>
          <Component {...pageProps} />
        </Provider>
      </Container>
    );
  }
}

export default withReduxStore(MyApp);

This is my next.config.js:

const withSass = require('@zeit/next-sass');

module.exports = withSass({
  cssModules: true,
  cssLoaderOptions: {
    importLoaders: 2,
    localIdentName: '[local]___[hash:base64:5]',
  },
  webpack: config => {
    config.module.rules.forEach(rule => {
      if (rule.test.toString().includes('.scss')) {
        rule.rules = rule.use.map(useRule => {
          if (typeof useRule === 'string') {
            return { loader: useRule };
          }

          if (useRule.loader.startsWith('css-loader')) {
            return {
              oneOf: [
                {
                  test: new RegExp('.global.scss$'),
                  loader: useRule.loader,
                  options: { ...useRule.options, modules: false },
                },
                {
                  loader: useRule.loader,
                  options: useRule.options,
                },
              ],
            };
          }

          return useRule;
        });

        delete rule.use;
      }
    });
    return config;
  },
});

@zachary95
Copy link

This workaround of using *.global.scss files should be set as a convention into this package for next major release.

@ckken
Copy link

ckken commented Aug 14, 2019

can use *.module.less instand ? @wedneyyuri

@wedneyyuri
Copy link

@ckken I don't know for sure, but using @zeit/next-less instead of @zeit/next-sass should work.

@ckken
Copy link

ckken commented Aug 15, 2019

no work for me !~ sad

@ghost
Copy link

ghost commented Sep 1, 2019

Here is my solution based on @wedneyyuri answer.

By default css-modules is off. If you want to enable it you just need to add '.module'
at the end of file name.

using global styles:
import './your/file/path/name.sass'

using scoped styles:
import styles from './your/file/path/name.module.sass'

here's my next.config.js :

const withSass = require('@zeit/next-sass');

module.exports = withSass({
    cssModules: true,
    cssLoaderOptions: {
        importLoaders: 2,
        localIdentName: '[local]___[hash:base64:5]',
    },

    webpack: config => {
        config.module.rules.forEach(rule => {
            if (rule.test.toString().includes('.sass')) {
                rule.rules = rule.use.map(useRule => {
                    if (typeof useRule === 'string') {
                        return { loader: useRule };
                    }

                    if (useRule.loader.startsWith('css-loader')) {
                        return {
                            oneOf: [
                                {
                                    test: new RegExp('.module.sass$'),
                                    loader: useRule.loader,
                                    options: useRule.options
                                },
                                {
                                    loader: useRule.loader,
                                    options: {},
                                },
                            ],
                        };
                    }
                    return useRule;
                });
                delete rule.use;
            }
        });
        return config;
    },
});

If you using .scss just change '.sass' => '.scss' in code.

@rkgrep
Copy link

rkgrep commented Dec 19, 2019

A better way to use oneOf is with resourceQuery - it won't limit the rule by single filename only

// next.config.js
// ...
oneOf: [
  {
    resourceQuery: /plain/,
    //.... no modules config
  },
  {
    // ... default config
  },
],
//...

And then import with ?plain query

// some_component.js
import 'assets/styles/style.scss?plain';
import { class1, class2 } 'assets/styles/my-modules.scss';
import 'assets/styles/another-global-style.scss?plain';

@Soundvessel
Copy link

@strunoder24 works great for scss but appears to have a bug related to use of :global in a module file. We use this in a few rare instances like layout components because they need to apply CSS to the base <html>, <body>, and base __next div. It appears these global styles are not flushed if you leave the page where a component uses them.

@webdeb
Copy link

webdeb commented Jan 3, 2020

I've had the same issues, so I created a small package to deal with it. (css + sass + modules + globals)
https://github.com/webdeb/next-styles

@SZharkov
Copy link

I've found global SCSS + modules still don't work by default even after updating to Next.js 9.2, where built-in CSS modules/global was introduced.

@timneutkens
Copy link
Member

When you add any of the css plugins it'll disable built-in support.

@EvHaus
Copy link

EvHaus commented Jan 16, 2020

This is fixed for me in 9.2, however, I'm not using SASS so that might be why others are still having issues.

For me, I import my global styles from _app.js (like this) without using CSS modules.

And then import all other CSS files as modules via the *.module.css syntax. 👍

@pixelkritzel
Copy link

@webdeb

I've had the same issues, so I created a small package to deal with it. (css + sass + modules + globals)
https://github.com/webdeb/next-styles

Thank you so much! It works!

@webdeb
Copy link

webdeb commented Jan 18, 2020

@pixelkritzel thank you, its good to know, that it works well for you!

@jamius19
Copy link

So, there's no way to use both SASS global and module stylesheets?
Does anyone have any workaround and solution?

@SZharkov
Copy link

SZharkov commented Feb 15, 2020

@jamius19 this workaround worked well for me - #403 (comment) (change css to scss/sass)

@jamius19
Copy link

@SZharkov Thank you very much. Working for me.

@Audelweiss
Copy link

I've had the same issues, so I created a small package to deal with it. (css + sass + modules + globals)
https://github.com/webdeb/next-styles

YOU ARE MY SAVIOUR 🖤

@Timer
Copy link
Member

Timer commented Mar 6, 2020

The latest version of Next.js supports Global CSS and CSS Modules simultaneously (and Sass on next@canary), zero configuration required.

@papiro

This comment has been minimized.

@Timer
Copy link
Member

Timer commented Mar 11, 2020

This is fixed in Next.js 9.3 if you use the built-in Sass support and not @zeit/next-sass.

@jlurena
Copy link

jlurena commented Apr 18, 2020

Instead of global css by default why not do module css by default? Use style.global.scss when we want a global style.

@ebs-PriyankaKanwar
Copy link

Hello Team
I have facing issues regarding the next-CSS . I have using next-CSS but they are giving me a warning and when I removed the next-CSS from next.config file. my style CSS has not loaded chunks in the production. and my CSS is out of order in a production build.
Can you plz help me.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests