You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14添加'use client'等后仍报window未定义,部署失败

Next.js 14 "window is not defined" 报错排查与解决(开发正常/生产部署失败)

问题重现

  • page.jsx已添加'use client'指令,通过dynamic导入组件并设置ssr: false禁用SSR,同时在useEffect中判断window存在后执行客户端逻辑
  • hero.jsx同样添加'use client',window相关代码包裹在useEffect内
  • 开发环境视觉、动画正常,但控制台仍报"window is not defined",Vercel生产环境部署直接失败
  • 项目依赖包含gsap@3.12.5、locomotive-scroll@5.0.0-beta.13

核心原因分析

  1. 第三方库顶层代码触发SSR报错:gsap、locomotive-scroll这类库的部分代码可能在模块加载阶段就直接访问window,哪怕组件加了'use client',Node环境解析模块时仍会执行这些顶层代码,导致报错。
  2. 'use client'位置不规范:如果'use client'不是文件第一行(前面有注释、导入语句),会导致客户端指令失效,组件仍会在SSR阶段执行。
  3. 动态导入的依赖未做延迟处理:动态导入的组件内部若直接在顶层导入客户端库,打包或预渲染阶段仍会触发window访问。

分步解决方案

1. 规范'use client'的位置

所有涉及客户端逻辑或依赖客户端库的文件,'use client'必须是文件第一行代码,不能有任何前置内容:

'use client'; // 必须置顶,不能有注释、导入在前面
import { useEffect } from 'react';

2. 延迟加载客户端依赖库

不要在顶层导入gsap、locomotive-scroll,改为在useEffect中动态导入,确保只在浏览器环境执行:

'use client';
import { useEffect, useState } from 'react';

export default function Hero() {
  const [scrollInstance, setScrollInstance] = useState(null);

  useEffect(() => {
    // 动态导入locomotive-scroll并初始化
    import('locomotive-scroll').then((module) => {
      const LocomotiveScroll = module.default;
      const instance = new LocomotiveScroll({
        el: document.querySelector('[data-scroll-container]'),
        smooth: true
      });
      setScrollInstance(instance);
    });

    // 动态导入gsap执行动画
    import('gsap').then((module) => {
      const gsap = module.default;
      gsap.to('.hero-title', { y: 0, opacity: 1, duration: 1.2 });
    });

    // 组件卸载时清理实例
    return () => {
      scrollInstance?.destroy();
    };
  }, []);

  return (
    <div data-scroll-container>
      <h1 className="hero-title">Hero Section</h1>
    </div>
  );
}

3. 优化动态导入组件的配置

确保动态导入组件时,不仅设置ssr: false,还要保证组件内部的依赖都做了延迟处理:

'use client';
import dynamic from 'next/dynamic';

// 动态导入Hero组件,禁用SSR
const Hero = dynamic(() => import('./hero'), {
  ssr: false,
  loading: () => <div className="loading">加载中...</div>
});

export default function Home() {
  return (
    <main>
      <Hero />
    </main>
  );
}

4. 增加浏览器环境判断兜底

封装工具函数,在任何可能访问window的代码前做判断:

// 封装浏览器环境判断函数
const isBrowser = () => typeof window !== 'undefined';

// 使用示例
useEffect(() => {
  if (isBrowser()) {
    const viewportWidth = window.innerWidth;
    console.log('视口宽度:', viewportWidth);
  }
}, []);

5. 排查locomotive-scroll版本问题

当前使用的是beta版,存在SSR兼容风险:

  • 尝试升级到最新稳定版(若已发布)
  • 初始化时确保DOM元素已挂载,避免提前访问DOM

验证步骤

  1. 本地执行npm run build,检查是否能正常打包(生产部署失败多因打包阶段报错,本地build可提前发现问题)
  2. 打包成功后执行npm start,启动生产环境服务,确认控制台无报错
  3. 重新部署到Vercel

内容的提问来源于stack exchange,提问作者Rayyan Eka Putra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 09:12:22