在Nuxt.js中,“window is not defined”

63

我尝试将代码从Vue.js移植到Nuxt.js时遇到错误。

我正在尝试在node_modules中使用vue-session。它成功编译,但在浏览器中我看到以下错误:

ReferenceError:window未定义

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;
          },

所以,我按照这篇文档的说明进行操作:

rewardadd.vue:

import VueSession from 'vue-session';

Vue.use(VueSession);

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

nuxt.config.js:

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

但是我仍然无法解决这个问题。


1
window 只存在于客户端浏览器中。在 Node.js 环境中它不存在。 - Arfeo
1
获取相同的大小写 - Irvan
9个回答

47

2021年8月更新

“Window is not defined”错误是由于Node.js服务器端脚本无法识别仅在浏览器中本地存在的window对象。

自nuxt v2.4版本起,您无需添加process.clientprocess.browser对象。

通常情况下,您的nuxt插件目录结构如下:

~/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);

然后在你的 nuxt.config.js 中,你可以使用以下两种方法之一将插件添加到你的项目中:

方法1:

将属性 mode 值设置为 'client' 来添加插件。

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

方法二:(在我看来更简单)

将你的插件重命名为扩展名为.client.js,然后将其添加到 nuxt.config.js 中的插件。Nuxt 2.4.x 将会识别插件的扩展名并在服务器端渲染.server.js或客户端渲染 .client.js,具体取决于所使用的扩展名

注意:如果没有添加 .client.js.server.js 扩展名,则会同时在客户端和服务器端渲染该插件。更多信息请参阅此处

plugins: ['~/plugins/myplugin.client.js']

如何确定服务器端需要哪个插件,客户端需要哪个插件? - Ярослав Прохоров
这对我也有效。但是我想限制在特定组件上使用 plugin。有没有一种方法可以在特定组件上导入插件,而不是全局可用? - Adriano
@Adriano 这实际上是一个非常好的想法(限制全局插件的使用)。要将其导入到特定组件中,您可以直接在组件中编写 import VueSession from 'vue-session'。这样,它将被限定在该组件中,并且仅在该组件中使用。当只有一个组件使用该包时以及您不想对整个应用程序造成影响时,这非常有用。 - kissu
@kissu 但是你如何让它只在客户端加载? - solidau
将其放置在 <client-only> 标签内。 - kissu
显示剩余2条评论

33

在服务器端渲染中没有窗口对象。但是快速解决方法是检查process.browser

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

这有点粗糙,但它可以工作。这里有一篇很好的文章,介绍如何使用插件来更好地实现


8

所有的内容都在nuxt 文档和常见问题解答中有详细说明。首先,您需要将其制作为插件。其次,您需要将插件设为仅限于客户端。

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

同时,在Nuxt 2.x中不再使用vendor,如果它在插件中具有ssr false,则不需要process.client。


7
在Nuxt 3中,您可以如下使用process.client:
if (process.client) {
  alert(window);
}

你也可以在Vue2中使用它。 - Toni Michel Caubet

2
如果你已经尝试了这里的大部分答案但仍无法解决问题,那么请看这里。我也曾在使用支付包Paystack时遇到了同样的问题。以下是我的建议:
创建一个插件并将扩展名命名为.client.js,这样它只会在客户端上呈现。因此,在plugins文件夹中创建一个文件'vue-session.client.js',它是插件,并放入以下代码。
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)

因此,在nuxt.config.js中,根据您的插件路径注册插件。

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

在index.vue或其他想使用该软件包的页面中...在mounted中导入软件包,以便在客户端页面加载时可用...
export default {
 ...
 mounted() {
   if (process.client) {
     const VueSession = () => import('vue-session')
   }
 }
...
}

1
您可以检查您是在客户端还是在浏览器中运行。从SSR中,window未定义。
const isClientSide: boolean = typeof window !== 'undefined'

0

除了这里的所有答案之外,您还可能会遇到一些不兼容 SSR 的其他包,需要一些技巧才能正常工作。 这是我的回答的详细信息。

简而言之,您有时需要:

  • 使用process.client
  • 使用<client-only>标签
  • 如果后面需要,使用动态导入,如const Ace = await import('ace-builds/src-noconflict/ace')
  • 有条件地加载组件components: { [process.client && 'VueEditor']: () => import('vue2-editor') }

0

对我来说,这是在Nuxt中使用apex-charts的情况,因此我必须将ssr: false添加到nuxt.config.js中。


我也因为在Nuxt 3中使用Apex-Charts而发现了这篇文章,你找到了一种同时保持SSR的方法吗? - Kevin Riordan
不知道为什么会被踩...但这解决了我的问题。n.b. ssr: false 的本质意思是仅在客户端渲染。我想这是因为服务器端并不知道Window对象,因为它不是一个浏览器... - Inigo

0

懒加载对我很有用。在Vue中懒加载组件就像使用包装在函数中的动态导入导入组件一样容易。我们可以按照以下方式懒加载StepProgress组件:

export default {
  components: {
    StepProgress: () => import('vue-step-progress')
  }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接