Dogfalo / materialize

Materialize, a CSS Framework based on Material Design
https://materializecss.com
MIT License
38.86k stars 4.74k forks source link

WebpackError: window is not defined #6087

Open vojtechruz opened 6 years ago

vojtechruz commented 6 years ago

When trying to use materialize with GatsbyJS and deploying to Netlify I get the following error when building the project: WebpackError: window is not defined

1:04:37 PM:   WebpackError: window is not defined
1:04:37 PM:   
1:04:37 PM:   - materialize.min.js:6 Object.module.exports.layoutContext
1:04:37 PM:     ~/materialize-css/dist/js/materialize.min.js:6:1135
1:04:37 PM:   
1:04:37 PM:   - index.js:6 Object.exports.__esModule
1:04:37 PM:     src/layouts/index.js:6:1
1:04:37 PM:   
1:04:37 PM:   - index.js:3 Object.exports.__esModule
1:04:37 PM:     .cache/layouts/index.js:3:3
1:04:37 PM:   
1:04:37 PM:   - sync-requires.js:6 Object.exports.__esModule
1:04:37 PM:     .cache/sync-requires.js:6:35
1:04:37 PM:   
1:04:37 PM:   - static-entry.js:8 Object.<anonymous>
1:04:37 PM:     .cache/static-entry.js:8:1

The sample project is here: https://github.com/vojtechruz/staticman-example

The failed build log here: https://app.netlify.com/sites/staticman-example/deploys/5b81377f4ed62f240de8d134

vojtechruz commented 6 years ago

This issue occurs generally with server-side rendering as you are relying on window object which is not available on the server. It is not just gatsby specific. It would be nice to be able to work with SSR and materialize.

Dhana-Krishnasamy commented 6 years ago

It's not materialize's issue too. If your css/sass processor (e.g: style-loader) loads the css at runtime in your HTML, you would see this error. So those processors (e.g: style-loader) add code to work on real dom/window object etc, which are not present when you do SSR. I use ExtractTextPlugin to extract the css and manually add the css file in the HTML template. What I think would be nice is if any web pack plugin could do the variable substitution and place the css in the template at build time like const htmlTemplate= <html><head>${webpack.css.plugin.generatedcss}</head></html>;

hug0b commented 6 years ago

In gatsby js v1 (React 15) and materialize 1.0 I can initialize a sidebar like this

if (typeof window !== 'undefined') {
  require('materialize-css/dist/js/materialize.min.js')
}

class Navigation extends Component {
  componentDidMount() {
    let elem = document.querySelector('.sidenav')
    M.Sidenav.init(elem, {})  
}

But migrating to Gatsby 2 (React 16) it doesn't work anymore (window is not defined when building the production app)

hug0b commented 6 years ago

In gatsby v2 what works is something like (still for a Sidenav component here)


if (typeof window !== 'undefined') {
  require('materialize-css/dist/js/materialize.min.js')
}

class Navigation extends Component {
  componentDidMount() {
    const elem = document.querySelector('.sidenav')
    window.M.Sidenav.init(elem, {})
  }

If that helps anyone

DanielRuf commented 6 years ago

I suggest creating an issue in the Gatsby project.

hug0b commented 6 years ago

The only issue with gatsby js v2 it that I haven't figured out how to make the waves effect work in production builds.

vojtechruz commented 6 years ago

It's not materialize's issue too.

If I understand correctly, materialize JS uses the window object, which means that one would never be able to use it with ANY framework or situation, where server-side rendering is used, right? That's not just issue of Gatsby. What's suggested in the comments above is a workaround, but it would be nice if materialize would work with SSR out of the box?

Not sure how easy is the transition though, looks like there are 184 occurrences of the window in the materialize JS.

DanielRuf commented 6 years ago

You don't have to change anything inside. You just have to apply some UMD wrapper which exports Materialize to root or window.

ahummel25 commented 4 years ago

Did anyone figure out a workaround for this? I'm also trying to import materialize-css (trying to use waves specifically) into my Gatsby app. Not having any luck. Tried importing it inside a useEffect but that doesn't appear to work. Which seems weird because this works for scrollspy:

useEffect(() => {
    if (typeof window !== 'undefined') {
      import('materialize-css').then((M) => {
        const scrollSpyElems = document.querySelectorAll('.scrollspy');
        M.ScrollSpy.init(scrollSpyElems);
      });
    }
 }, []);

But for whatever reason, I cannot get waves to work using this same import.

Update:

Got waves to work by adding this inside the above import.then:

const wavesElems = document.querySelectorAll('.waves-effect');

const Waves = window.Waves;

wavesElems.forEach((wavesElem): void => {
     Waves.attach(wavesElem);
});