Next.js: Possibility to pass options to css-loader and sass-loader when using (s)css modules

Created on 30 Jan 2020  路  4Comments  路  Source: vercel/next.js

Feature request

Is your feature request related to a problem? Please describe.

I'd like to pass further options (like includePaths or localIdentName) to sass-loader/css-loader when using the new built in css modules.

Additional context

Maybe hashing the css classnames via localIdentName: [hash:base64] in production mode could be a default.

Most helpful comment

I would go with A) since people might be used to it from the old next-plugins, e.g. https://github.com/zeit/next-plugins/blob/master/packages/next-sass/readme.md

Something like:

// next.config.js

const isProd = process.env.NODE_ENV === 'production'

module.exports = {

  sassLoaderOptions: { 
    includePaths: ['absolute/path/a', 'absolute/path/b'] 
  },

  cssLoaderOptions: {  
    modules: {
      // This could be a next.js default?
      localIdentName: isProd ? '[hash:base64]' : '[path][name]__[local]--[hash:base64:5]',
    },
  }

}

All 4 comments

We need includePaths because we have a monorepo and we don't want to deal with long relative paths.

I'm not part of the Next team but I've been putting some thought into the best way to handle this.

Some options:
A) Simply brute force in another option that can be used inside next.config.js. Pass through the value to sass-loader options object.
Pros:

  • Easy to implement into the codebase
  • Easy to implement as a user

Cons:

  • It's not really a configuration for Next specifically
  • Increases the Next config footprint

B) Build in config detection for .sassrc.js .sassrc.json sass.config.js and/or a sass option in package.json.
Pros:

  • Follows the industry set convention
  • Separates the settings from next.config.js

Cons:

  • Is not built-in convention for Webpack Sass (Parcel has this convention built in)
  • Adds a lot of complexity to Next for the sake of loading a separate config

C) Build the above config detection upstream for sass-loader.
Pros:

  • Follows convention of postcss-loader which uses postcss-load-config
  • Keeps maintenance out of Next
  • Improves cross-project support of sass-loader

Cons:

  • Will take longest to implement/merge
  • Might not be accepted route by sass-loader maintainers

My personal opinion is that C is the best way forward, but maybe there's a half-step that can be taken in the meantime? I'd just like to see .sassrc.json and such accepted out-of-box for all Webpack projects than try to shim the customization into Next.

I would go with A) since people might be used to it from the old next-plugins, e.g. https://github.com/zeit/next-plugins/blob/master/packages/next-sass/readme.md

Something like:

// next.config.js

const isProd = process.env.NODE_ENV === 'production'

module.exports = {

  sassLoaderOptions: { 
    includePaths: ['absolute/path/a', 'absolute/path/b'] 
  },

  cssLoaderOptions: {  
    modules: {
      // This could be a next.js default?
      localIdentName: isProd ? '[hash:base64]' : '[path][name]__[local]--[hash:base64:5]',
    },
  }

}

As a workaround for now, you can do the following to get your custom options in there. It's not pretty but it works...

let rule, moduleRules, cssLoader, scssRules, sassLoader;
if (rule = config.module.rules.find(rule => Object.keys(rule).includes('oneOf'))) {
  // Locate css-loader config for css modules
  if (moduleRules = rule.oneOf.filter(r => ('test.module.scss'.match(r.test) || 'test.module.css'.match(r.test)) && Array.isArray(r.use))) {
    for (const moduleRule of moduleRules) {
      if (cssLoader = moduleRule.use.find(u => u.loader.match('css-loader'))) {
        cssLoader.options = {
          ...cssLoader.options,
          // Any custom css loader options here
          modules: {
            ...cssLoader.options.modules,
            // Your custom css-modules options below.
            getLocalIdent: () => false, // Fall back to default getLocalIdent function
            localIdentName: process.env.NODE_ENV === 'production' ? '[hash:base64:8]' : '[name]__[local]___[hash:base64:5]',
          }
        }
      }
    }
  }

  // Locate sass-loader config
  if (scssRules = rule.oneOf.filter(r => ('test.scss'.match(r.test) || 'test.module.scss'.match(r.test)) && Array.isArray(r.use))) {
    for (const scssRule of scssRules) {
      if (sassLoader = scssRule.use.find(u => u.loader.match('sass-loader'))) {
        sassLoader.options = {
          ...sassLoader.options,
          // Your custom sass-loader options below.
          prependData: '@import "~styles/variables.scss";',
        }
      }
    }
  }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

Timer picture Timer  路  60Comments

arunoda picture arunoda  路  103Comments

robinvdvleuten picture robinvdvleuten  路  74Comments

rauchg picture rauchg  路  208Comments

ematipico picture ematipico  路  66Comments