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
核心原因分析
- 第三方库顶层代码触发SSR报错:gsap、locomotive-scroll这类库的部分代码可能在模块加载阶段就直接访问
window,哪怕组件加了'use client',Node环境解析模块时仍会执行这些顶层代码,导致报错。 'use client'位置不规范:如果'use client'不是文件第一行(前面有注释、导入语句),会导致客户端指令失效,组件仍会在SSR阶段执行。- 动态导入的依赖未做延迟处理:动态导入的组件内部若直接在顶层导入客户端库,打包或预渲染阶段仍会触发
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
验证步骤
- 本地执行
npm run build,检查是否能正常打包(生产部署失败多因打包阶段报错,本地build可提前发现问题) - 打包成功后执行
npm start,启动生产环境服务,确认控制台无报错 - 重新部署到Vercel
内容的提问来源于stack exchange,提问作者Rayyan Eka Putra
相关产品推荐
相关产品推荐

