Next.js: Built-In Sass Support

Created on 17 Jan 2020  路  14Comments  路  Source: vercel/next.js

Feature request

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

With #8626 it was commented that the various non-css-in-js styling plugins would be deprecated in favor of built-in support. This did not happen, and my tests with the new built-in CSS support and @zeit/next-sass even showed Sass to outright fail in cases.

Describe the solution you'd like

Installation of node-sass should enable built-in Sass support, both global and CSS Modules per the original RFC suggestion.

I've created PR #10133 (as a start) which modified the CSS webpack config to enable .scss, .sass, .module.scss, and .modules.sass. It adds sass-loader as the only additional dependency.

Describe alternatives you've considered

I've considered rewriting @zeit/next-sass to cooperate with the current built-in CSS and CSS Module config. This would come with the benefit of not requiring sass-loader as another core dependency, but would require a complex setup to gain the same level of benefits, further user config, prolonged maintenance of the plugin, etc.

Additional context

  • Tests focusing on Sass need to be written, but many of the tests for output CSS should work for Sass tests.
  • Documentation will need to be updated to remove @zeit/next-sass references and include instructions for installing node-sass to enable.
  • Some additional refactoring may be able to DRY up repetition, but I also didn't want to make individual configurations more difficult by abstracting too much. Because of this some comments from the original implementation are a bit redundant in the sass-loader.
  • Error messages skew towards "CSS" verbiage. There could be custom Sass messages, but I think this increases the footprint unnecessarily and Sass becomes CSS so I feel the messages work.

Let me know if this is the correct path forward and if you'd like me to continue contributing towards this feature.

Most helpful comment

How can we set any sass loader options like includePaths ?

All 14 comments

This feature has been experimentally landed. Please try it out on the latest canary!

Enabled with an experimental flag in your next.config.js:

module.exports = {
  experimental: { scss: true }
}

How can we set any sass loader options like includePaths ?

Doesn't seem to work together with TypeScript like the built in CSS support does. Reproduction in this repo:
https://github.com/csirkeee/with-scss-typescript

Second to last commit there is the same but with CSS modules, and it seems like TS parsing is set up for that successfully, but if I switch to SCSS it fails to build.

I would open a separate issue @csirkeee

@csirkeee #10363 addresses this, but I believe is on hold until this release is no longer experimental.

If you want to experiment in the meantime you can create a scss.d.ts file in your root with:

declare module '*.module.scss' {
  const content: {[className: string]: string};
  export default content;
}

Or add that to your next-env.d.ts

@timer Tbh I think it's fine to ship it either way, it's just to bypass TypeScript checking and would still fail on webpack not being able to bundle 馃憤

How can we set any sass loader options like includePaths ?

There is a feature request here https://github.com/zeit/next.js/issues/10339

I tried out the SCSS as a module but it didn't compile the SCSS to CSS so all the nested classes were broken. The outer class worked though.

Also, it is working well when used globally.

@jeremyk do you have a repo or reproducible example?

I tried out the SCSS as a module but it didn't compile the SCSS to CSS so all the nested classes were broken. The outer class worked though.

Also, it is working well when used globally.

@jeremyk I'm seeing this same issue. Did you ever figure this one out? Not sure if I'm missing something in the docs here.

I was actually using it incorrectly - I thought one only referenced the "outer" or top level classes via the import (as that would give global uniqueness) but you have to reference all the inner ones as well. If you want to opt out of that behavior you can put :global {} around a class or block of scss and it will opt out of that (making it work how I thought it would originally). And using :local {} inside a global block will revert back to the default behavior. Hope that helps. @thadwoodman

@jeremyk thanks this solved the issue for me! I think this would be really helpful to have in the docs.

Was this page helpful?
0 / 5 - 0 ratings