React SSR项目使用react-owl-carousel报window未定义错误如何解决
问题原因
react-owl-carousel底层依赖的Owl Carousel是纯浏览器端组件,源码直接硬编码调用了window、document等浏览器专属API。而SSR(服务端渲染)的代码执行在Node.js环境,Node原生没有window对象,因此组件导入阶段就会直接抛出错误,报错日志如下:
F:\react\test\testsite> npm run ssr > testsite@0.1.0 ssr > node server/index.js F:\react\test\testsite\node_modules\react-owl-carousel\umd\OwlCarousel.js:1795 })(window.Zepto || window.jQuery, window, document); ^ ReferenceError: window is not defined at F:\react\test\testsite\node_modules\react-owl-carousel\umd\OwlCarousel.js:1795:8 at F:\react\test\testsite\node_modules\react-owl-carousel\umd\OwlCarousel.js:2:85 at Object.<anonymous> (F:\react\znap\znapcash\node_modules\react-owl-carousel\umd\OwlCarousel.js:5:2) at Module._compile (internal/modules/cjs/loader.js:1063:30) at Module._compile (F:\react\znap\znapcash\node_modules\pirates\lib\index.js:99:24) at Module._extensions..js (internal/modules/cjs/loader.js:1092:10) at Object.newLoader [as .js] (F:\react\test\testsite\node_modules\pirates\lib\index.js:104:7) at Module.load (internal/modules/cjs/loader.js:928:32) at Function.Module._load (internal/modules/cjs/loader.js:769:14) at Module.require (internal/modules/cjs/loader.js:952:19) PS F:\react\test\testsite>
解决方案
根据你使用的SSR框架选择对应处理方式即可:
1. Next.js 框架
直接用官方提供的dynamic动态导入能力,关闭组件的服务端渲染:
import dynamic from 'next/dynamic'; // 关闭SSR导入轮播组件 const OwlCarousel = dynamic(() => import('react-owl-carousel'), { ssr: false, // 可选:加载时展示的占位组件 loading: () => <div>轮播加载中...</div> }); // 引入样式文件,样式文件可以正常在服务端导入 import 'owl.carousel/dist/assets/owl.carousel.css'; import 'owl.carousel/dist/assets/owl.theme.default.css'; // 后续正常使用OwlCarousel组件即可
2. 自定义SSR框架
方案A:客户端侧动态导入
在组件挂载后(此时已经到浏览器环境)再引入组件:
import { useState, useEffect } from 'react'; const MyCarousel = (props) => { const [Carousel, setCarousel] = useState(null); useEffect(() => { // 客户端执行时才导入组件 const OwlCarousel = require('react-owl-carousel').default; setCarousel(() => OwlCarousel); // 同时导入样式 require('owl.carousel/dist/assets/owl.carousel.css'); require('owl.carousel/dist/assets/owl.theme.default.css'); }, []); // 服务端渲染时返回占位,客户端加载完成后再渲染轮播 if (!Carousel) return <div>轮播加载中...</div>; return <Carousel {...props}>{props.children}</Carousel>; }; export default MyCarousel;
方案B:服务端模拟window对象
如果需要组件在服务端也能正常导入,可以在服务端入口文件最顶部注入模拟的浏览器环境:
// server/index.js 最顶部添加 const { JSDOM } = require('jsdom'); const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>'); global.window = dom.window; global.document = dom.window.document; global.navigator = dom.window.navigator; // 后续再加载其他服务端逻辑
注意:该方案可能会导致其他依赖环境判断的库出现异常,优先推荐使用动态导入方案。
注意事项
react-owl-carousel依赖jQuery,确保jQuery也只在客户端环境引入,不要在服务端加载- 所有轮播实例的方法调用、动态配置修改,都要确保在客户端执行,不要放在服务端渲染逻辑中
内容的提问来源于stack exchange,提问作者Simple Design
相关产品推荐
相关产品推荐

