Wonay
Wonay

Reputation: 1250

How to deal with `module.scss` with react and next?

I am very lost.

For context, I am using Next and React.

// package.json
  "dependencies": {
    "@netlify/plugin-nextjs": "^3.4.2",
    "next": "^10.0.0",
    "postcss-flexbugs-fixes": "^5.0.2",
    "postcss-preset-env": "^6.7.0",
    "react": "17.0.1",
    "react-dom": "17.0.1",
    "react-onclickoutside": "^6.11.2",
    "react-svg": "14.0.0"
  },
  "devDependencies": {
    "classnames": "^2.2.6",
    "sass": "^1.34.0"
  }

I use npx next build && npx next start -p 4000 to test production locally. It all works fine in dev using netlify dev -e.

There are weird effects. When I have two imports of .module.scss, the client-side javascript just stops.

I have a page:

// /pages/test.js
import CompA from 'components/comp-a'
import CompB from 'components/comp-b'

And:

// /components/comp-a.js
import styles from 'components/comp-a.module.scss`

and

// /components/comp-b.js
import styles from 'components/comp-b.module.scss`

This situation renders correctly visually but NO client-side javascript is working at all and, of course, without any error. I spent the day commenting and uncommenting each component and line of my source code to narrow down to this situation.

I tried by commenting out in the page, with one component the client-side js works, not with two.

I tried commenting out the styles import in one of the components, the client-side js works as well.

Another situation where it does not work is :

// components/comp-a.js
import styles from 'components/comp-a.module.js'
import CompB from 'components/comp-b.module.js'

and it works if I comment either one of the style or the sub component.

And none of it makes sense because in the page, I also have the Layout being imported that does contain its own styles and that works fine.

What is going on ???

Edit: Continuing to dig, I found out that I was doing @extend .class-abc and at the top @import 'style/foo.module'; , and the .class-abc was containing an other class:

// /style/foo.module.scss
.class-abc {
  ...
  .bar { 
    ...
  }
}

For some reason, commenting out .bar solve the problem. No idea what is going on.

Upvotes: 1

Views: 1408

Answers (1)

I'm Joe Too
I'm Joe Too

Reputation: 5840

One of the main benefits of using css/scss modules is that you keep the styles close to the component and everything gets namespaced for you. So you wouldn't typically import the component styles into your page. Restructuring a bit should help:

- components/
  - comp-a/
    - index.js
    - index.module.scss
  - comp-b/
    - index.js
    - index.module.scss
- pages
  // If test.js doesn't also have its own styles
  - test.js
  // Or if test.js has its own css/scss modules
  - test
    - index.js
    - index.module.scss

Your components and pages would then look like this:

// comp-a
import styles from "./index.module.css"

export default function MyCompA() {
  return (<div className={styles.someClass}>I have local comp-a styles</div>)
}

// comp-b
import styles from "./index.module.css"

export default function MyCompB() {
  return (<div className={styles.someClass}>I have local comp-b styles</div>)
}

// test
import MyCompA from "../components/comp-a"
import MyCompB from "../components/comp-b"

// If this also has its own styles
import styles from "./index.module.scss"

export default function MyCompTestPage() {
  return (
    <>
      <p className={styles.someClass}>I have local test page styles</p>
      <MyCompA />
      <MyCompB />
    </>
  )
}

Sharing Styles Between Components

If multiple components need to share the same styles, you would generally want to (a) extract those styles to a global stylesheet or (b) extract that common code into its own component or (c) share the stylesheet between components. An example of option c can look like this:

- components/
  - comps-ab/
    - comp-a.js
    - comp-b.js
    - index.module.scss
- pages
  - test.js
// comps-ab/comp-a
import styles from "./index.module.css"

export default function MyCompA() {
  return (<div className={styles.someClass}>I have shared comps-ab styles but still local to these components</div>)
}

// comps-ab/comp-b
import styles from "./index.module.css"

export default function MyCompB() {
  return (<div className={styles.someClass}>I have shared comps-ab styles but still local to these components</div>)
}

// test
import MyCompA from "../components/comps-ab/comp-a"
import MyCompB from "../components/comps-ab/comp-b"

export default function MyCompTestPage() {
  return (
    <>
      <MyCompA />
      <MyCompB />
    </>
  )
}

In this case, your two components pull from the same stylesheet, but it's still local to those two components and isn't brought into the test.js page manually.

Upvotes: 3

Related Questions