Deno Fresh岛组件使用@egjs/preact-flicking遇document未定义错误
解决Fresh框架中使用preact-flicking时
document is not defined的报错问题 我在基于Fresh搭建网站时,选用preact-flicking作为轮播组件,但渲染时出现构建失败,报错如下:
➜ example git:(main) ✗ deno task start Task start deno run -A --watch=static/,routes/ dev.ts Watcher Process started. The manifest has been generated for 5 routes and 1 islands. error: Uncaught (in promise) ReferenceError: document is not defined at https://esm.sh/v132/@egjs/preact-flicking@4.11.0/denonext/preact-flicking.mjs:2:56465 Watcher Process failed. Restarting on file change...
初始代码:
// islands/Carousel.tsx import Flicking from "https://esm.sh/@egjs/preact-flicking@4.11.0"; export const Carousel = () => <Flicking />;
之前尝试过判断typeof window !== 'undefined',以及用lazy+Suspense懒加载,但前者无效,后者初始显示[object Promise],刷新后仍报同样错误。
解决方法
问题根源在于Fresh的服务端预渲染机制:preact-flicking在模块加载阶段就会访问document对象,而服务端环境不存在这个对象,导致报错。需要确保组件的导入和渲染仅在客户端执行,同时指定适配浏览器的模块版本。
方案1:在useEffect中动态导入(推荐)
// islands/Carousel.tsx import { useEffect, useState } from "preact/hooks"; export const Carousel = () => { const [FlickingComp, setFlickingComp] = useState(null); useEffect(() => { // 指定browser目标,让esm.sh返回浏览器适配版本 import("https://esm.sh/@egjs/preact-flicking@4.11.0?browser") .then(mod => setFlickingComp(mod.default)); }, []); if (!FlickingComp) { return <p>加载中...</p>; } return <FlickingComp />; };
方案2:结合lazy加载与客户端判断
// islands/Carousel.tsx import { lazy, Suspense } from "preact/compat"; import { useEffect, useState } from "preact/hooks"; // 导入浏览器适配版本的组件 const Flicking = lazy(() => import("https://esm.sh/@egjs/preact-flicking@4.11.0?browser")); export const Carousel = () => { const [isClient, setIsClient] = useState(false); useEffect(() => { // 仅在客户端标记渲染状态 setIsClient(true); }, []); if (!isClient) { return <p>加载中...</p>; } return ( <Suspense fallback={<p>加载中...</p>}> <Flicking /> </Suspense> ); };
原理说明
?browser参数告诉esm.sh返回适配浏览器环境的模块代码,避免加载针对Deno/Node的版本;useEffect确保动态导入和组件渲染逻辑仅在浏览器客户端执行,避开服务端预渲染阶段;- 两种方案都通过状态判断实现客户端渲染的条件控制,解决服务端无
document的问题。
内容的提问来源于stack exchange,提问作者tkovs
相关产品推荐
相关产品推荐

