60

I get an error porting from Vue.js to Nuxt.js.

I am trying to use vue-session in node_modules. It compiles successfully, but in the browser I see the error:

ReferenceError window is not defined

node_modules\vue-session\index.js:

VueSession.install = function(Vue, options) {
    if (options && 'persist' in options && options.persist) STORAGE = window.localStorage;
    else STORAGE = window.sessionStorage;
    Vue.prototype.$session = {
        flash: {
          parent: function() {
            return Vue.prototype.$session;
          },

so, I followed this documentation:

rewardadd.vue:

import VueSession from 'vue-session';

Vue.use(VueSession);

if (process.client) {
  require('vue-session');
}

nuxt.config.js:

  build: {
    vendor: ['vue-session'],

But I still cannot solve this problem.

ttulka
  • 10,309
  • 7
  • 41
  • 52
HM.Park
  • 757
  • 1
  • 5
  • 9

9 Answers9

48

UPDATED AUGUST 2021

The Window is not defined error results from nodejs server side scripts not recognising the window object which is native to browsers only.

As of nuxt v2.4 you don't need to add the process.client or process.browser object.

Typically your nuxt plugin directory is structured as below:

~/plugins/myplugin.js

import Vue from 'vue';
// your imported custom plugin or in this scenario the 'vue-session' plugin
import VueSession from 'vue-session';

Vue.use(VueSession);

And then in your nuxt.config.js you can now add plugins to your project using the two methods below:

METHOD 1:

Add the mode property with the value 'client' to your plugin

plugins: [
  { src: '~/plugins/myplugin.js', mode: 'client' }
]

METHOD 2: (Simpler in my opinion)

Rename your plugin with the extension .client.js and then add it to your plugins in the nuxt.config.js plugins. Nuxt 2.4.x will recognize the plugin extension as to be rendered on the server side .server.js or the client side .client.js depending on the extension used.

NOTE: Adding the file without either the .client.js or .server.js extensions will render the plugin on both the client side and the server side. Read more here.

plugins: ['~/plugins/myplugin.client.js']
kissu
  • 40,416
  • 14
  • 65
  • 133
innocentwkc
  • 596
  • 8
  • 8
  • how to determine which plugin is needed for the server side and which for the client? – Ярослав Прохоров Nov 15 '20 at 08:40
  • @ЯрославПрохоров that depends on what you want to achieve with your plugin and how much data it consumes on the client side(as this will impact your user experience). If you plugin makes a number of api calls that affects the loading times of pages I'd suggest making it asyncronous on the client side, on the other hand if you are touchy about making your plugin secure then render it on the backend. This is just my opinion you can ask other devs and get an answer that suits your application. Happy Holidays! – innocentwkc Dec 16 '20 at 13:30
  • This works for me as well. But I would like to restrict the use of the `plugin` on specific components. Is there a way to import the plugin on specific components, rather than having it available globally? – Adriano Feb 24 '21 at 00:31
  • @Adriano this is actually a very good idea (limit the usage of global plugins). To import it into a specific component, you can write `import VueSession from 'vue-session'` directly into your component. That way, it will be scoped there and only there. Useful when only one component uses the package and when you don't want to give a penalty to your whole app. – kissu Jul 26 '21 at 10:04
  • @kissu but then how do you get it to load only on client? – solidau Jul 30 '21 at 18:25
  • Put it inside of `` tags. – kissu Jul 30 '21 at 18:33
30

There is no window object on the server side rendering side. But the quick fix is to check process.browser.

  created(){
    if (process.browser){
      console.log(window.innerWidth, window.innerHeight);
    }
  }

This is a little bit sloppy but it works. Here's a good writeup about how to use plugins to do it better.

kissu
  • 40,416
  • 14
  • 65
  • 133
RoccoB
  • 2,439
  • 2
  • 27
  • 30
8

Its all covered in nuxt docs and in faq. First you need to make it a plugin. Second you need to make your plugin client side only

plugins: [
  { src: '~/plugins/vue-notifications', mode: 'client' }
]

Also vendor is not used in nuxt 2.x and your process.client not needed if its in plugin with ssr false

kissu
  • 40,416
  • 14
  • 65
  • 133
Aldarund
  • 17,312
  • 5
  • 73
  • 104
6

In Nuxt 3 you use process.client like so:

if (process.client) {
  alert(window);
}
kissu
  • 40,416
  • 14
  • 65
  • 133
ubershmekel
  • 11,864
  • 10
  • 72
  • 89
2

If you've tried most of the answers here and it isn't working for you, check this out, I also had the same problem when using Paystack, a payment package. I will use the OP's instances

Create a plugin with .client.js as extension so that it can be rendered on client side only. So in plugins folder, create a file 'vue-session.client.js' which is the plugin and put in the code below

import Vue from 'vue'
import VueSession from 'vue-session'
//depending on what you need it for
Vue.use(VueSession)
// I needed mine as a component so I did something like this
Vue.component('vue-session', VueSession)

so in nuxt.config.js, Register the plugin depending on your plugin path

plugins:[
...
{ src: '~/plugins/vue-session.client.js'},
...
]

In index.vue or whatever page you want to use the package... import the package on mounted so it is available when the client page mounts...

export default {
 ...
 mounted() {
   if (process.client) {
     const VueSession = () => import('vue-session')
   }
 }
...
}
Ilesanmi John
  • 194
  • 2
  • 4
1

You can check if you're running with client side or with the browser. window is not defined from the SSR

const isClientSide: boolean = typeof window !== 'undefined'
kissu
  • 40,416
  • 14
  • 65
  • 133
0

Lazy loading worked for me. Lazy loading a component in Vue is as easy as importing the component using dynamic import wrapped in a function. We can lazy load the StepProgress component as follows:

export default {
  components: {
    StepProgress: () => import('vue-step-progress')
  }
};
mikemaal
  • 317
  • 3
  • 6
0

For me it was the case of using apex-charts in Nuxt, so I had to add ssr: false to nuxt.config.js.

wael32gh
  • 324
  • 5
  • 11
  • i also found this post because of apex-charts in nuxt3 did you find a way to do it and keep ssr? – Kevin Riordan Feb 01 '23 at 00:24
  • don't know why this is downvoted... fixed the issue for me n.b. `ssr: false` essentially means only client-side rendering. So I guess this is because server-side doesn't know what the Window object is because it isn't a browser... – Inigo Mar 06 '23 at 07:49
0

On top of all the answers here, you can also face some other packages that are not compatible with SSR out of the box and that will require some hacks to work properly. Here is my answer in details.

The TLDR is that you'll sometimes need to:

  • use process.client
  • use the <client-only> tag
  • use a dynamic import if needed later on, like const Ace = await import('ace-builds/src-noconflict/ace')
  • load a component conditionally components: { [process.client && 'VueEditor']: () => import('vue2-editor') }
kissu
  • 40,416
  • 14
  • 65
  • 133