Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebpackError: ReferenceError: localStorage is not defined #14480

Closed
JeffWScott opened this issue Jun 1, 2019 · 11 comments
Closed

WebpackError: ReferenceError: localStorage is not defined #14480

JeffWScott opened this issue Jun 1, 2019 · 11 comments

Comments

@JeffWScott
Copy link

Description

localStorage is available when running 'develop' but build fails on error "WebpackError: ReferenceError: localStorage is not defined"

Steps to reproduce

add a reference to localStorage anywhere in your gatsby project

Expected result

localStorage works

Actual result

localStorage throws an error on build

Environment

Run gatsby info --clipboard in your project directory and paste the output here.
System:
OS: Windows 10
CPU: (4) x64 Intel(R) Core(TM) i5-3550 CPU @ 3.30GHz
Binaries:
npm: 6.4.1 - C:\Program Files\nodejs\npm.CMD
Languages:
Python: 2.7.15
Browsers:
Edge: 42.17134.1.0
npmPackages:
gatsby: ^2.8.2 => 2.8.2
gatsby-image: ^2.1.2 => 2.1.2
gatsby-plugin-manifest: ^2.1.1 => 2.1.1
gatsby-plugin-offline: ^2.1.1 => 2.1.1
gatsby-plugin-react-helmet: ^3.0.12 => 3.0.12
gatsby-plugin-sharp: ^2.1.3 => 2.1.3
gatsby-source-filesystem: ^2.0.38 => 2.0.38
gatsby-transformer-sharp: ^2.1.21 => 2.1.21

Opening bug reports is always my last resort. I google'd the crap out of this and didn't get anywhere.

@kaijchang
Copy link

You should see this comment: #309 (comment). Basically, when you build, localStorage isn't defined because it's a browser-only feature. Here's the fix: #309 (comment).

@JeffWScott
Copy link
Author

@kajchang
I'm not sure I follow. I'm basically building an SPA which relies heavily on local-storage to persist information across sessions.
By the looks of that thread this isn't really possible?

Is Gatsby not the right frameword for SPAs? That would be a shame because I love working with it.

@JeffWScott
Copy link
Author

JeffWScott commented Jun 1, 2019

@kajchang

okay, I have been able to build and deploy the site.
Basically I had to wait for the window to load before letting everything else load. luckily i have all my localStorage logic contained in a seperate js file so it wasn't a big hassle.

My solution looks like this (I don't know why insert code isn't working and I don't have time to troubleshoot that too):

`import * as StorageHelpers from '../js/localstorage_helpers';

function PageFramework(props) {
const [initialized, setInitialized] = useState(false);
const [windowLoaded, setWindowLoaded] = useState(false);

useEffect(() => {
if (!windowLoaded){
if (typeof window !== 'undefined' && window){
setWindowLoaded(true)
}
}
}, [windowLoaded]);

useEffect(() => {
if (!initialized && windowLoaded) {
//You can now use your localStorage commands
StorageHelpers.initiateStorage();

  setInitialized(true);
}

}, [initialized, windowLoaded]);`

I hope this helps someone and thanks you @kajchang for the link!

@kaijchang
Copy link

@JeffWScott you don't necessarily have to use state for this. typeof window !== 'undefined' && # your localStorage interaction is a more simple solution, because the root problem isn't that the window is yet loaded, it's just that gatsby does a lot of optimization when you build, but when it's building and going through your code, it doesn't know what localStorage is. Either way works though.

@yurkoturskiy
Copy link
Contributor

I have another solution. Just retrieve data after a component was mounted.

// Wrong
const [key] = useState(localStorage.getItem('token'))
// Correct
const [key, setKey] = useState(undefined)

useEffect(() => {
  setKey(localStorage.getItem('token'))
}, [])

@matheusmazeto
Copy link

I have another solution. Just retrieve data after a component was mounted.

// Wrong
const [key] = useState(localStorage.getItem('token'))
// Correct
const [key, setKey] = useState(undefined)

useEffect(() => {
  setKey(localStorage.getItem('token'))
}, [])

Thanks for helping me.

@arhoy
Copy link

arhoy commented Dec 5, 2019

I am using localStorage in a redux action type.
Netlify is giving me this error

3:20:57 PM:   11 | const initialState = {
3:20:57 PM: > 12 |   token: typeof window !== undefined ? localStorage.getItem('token') : '',
3:20:57 PM:      |                                        ^
3:20:57 PM:   13 |   isAuthenticated: null,
3:20:57 PM:   14 |   loading: true,
3:20:57 PM:   15 |   user: null,
3:20:57 PM: 
3:20:57 PM:   WebpackError: ReferenceError: localStorage is not defined

What is a good way to avoid this issue? Thanks

@jonniebigodes
Copy link

@arhoy gatsby when builds your website/app. It will do it in node, some apis like window, localstorage and others that are on the other "side of the spectrum", with that they are not available during the process. You will need to make some adjustments to your code, create a "guard" against this in the means of a check if the api is present, something like documented here.

@JeffWScott
Copy link
Author

@arhoy gatsby when builds your website/app. It will do it in node, some apis like window, localstorage and others that are on the other "side of the spectrum", with that they are not available during the process. You will need to make some adjustments to your code, create a "guard" against this in the means of a check if the api is present, something like documented here.

This is just a question from a guy who is largely ignorant on how frameworks are put together, but doesn't it make sense that if this fact is largely known that the framework itself couldn't do this automatically?

@jonniebigodes
Copy link

@JeffWScott it could be done, but it would be a daunting task to do this, based on my knowledge of how the framework is put together. As there are alot of moving parts inside, gatsby is already really "inteligent" in picking up some stuff, but for this case it to add guard methods, it would have to make a run checking each individual files for specific patterns and change the files accordingly, this would add a big overhead on the build time. More even, not everyone has the same coding style, so even more with that. I know that seasoned gatsby developers know how to circunvent this, but newcomers don't and with that that's why @gillkyle has put this #19966 that from my perspective will help solve issues like this in the future. The documentation already has a mention on how to solve it, but it's a bit tucked away in the corner and not all people will discover it. Most get the answer they want from a search that will lead them to a big list of similar issues, so with that the effort that was put in the pr i've mentioned will be a great addition.

@moafzalmulla
Copy link

Use let variable if Local Storage does not exist

As Local storage only exists in browser runtime.

When developing for Gatsby, think like a script ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants