materialize
materialize copied to clipboard
WebpackError: window is not defined
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
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.
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>
;
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)
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
I suggest creating an issue in the Gatsby project.
The only issue with gatsby js v2 it that I haven't figured out how to make the waves effect work in production builds.
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.
You don't have to change anything inside. You just have to apply some UMD wrapper which exports Materialize to root
or window
.
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);
});