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

NextJS SSR动态导入penumbra返回空对象问题如何解决

问题描述
  • 在NextJS项目中引入penumbra库作为依赖后,运行时抛出window is undefined错误。该报错符合预期:NextJS服务端渲染(SSR)阶段不存在浏览器window对象,而penumbra库会直接非安全访问window对象,因此触发报错。
  • 这类SSR兼容问题是NextJS开发中的常见问题,官方给出的标准解决方案是使用动态导入。
  • 按照官方文档方案实现动态导入时,得到的导入结果为空对象,复现代码如下:
import("@transcend-io/penumbra").then(mod => {
  console.log(mod.default); // 空对象,对应default导出
  console.log(mod.penumbra); // undefined,对应命名导出
})
  • 相同的动态导入写法对其他第三方模块(例如moment)可以正常生效,测试代码如下:
import("moment").then(mod => {
  console.log(mod.default()); // 正常返回moment实例
})
  • 基于测试结果可判断,问题原因要么是动态导入时遗漏了必要配置,要么是penumbra模块本身存在SSR兼容缺陷。
  • 本地搭建的可运行复现示例中,运行日志可验证:moment动态导入后可正常返回实例,penumbra的default导出为空对象{},命名导出penumbra值为undefined。
解决方案

问题核心原因是penumbra本身是纯浏览器环境打包的UMD模块,未做Node/SSR环境兼容,模块初始化阶段就会直接访问window对象,哪怕用动态导入,只要代码在服务端执行解析,模块初始化就会失败,导致导出为空。可按以下方式修复:

方案1:客户端侧动态导入(推荐)

不要直接在组件顶层或服务端执行逻辑中调用导入,强制将penumbra的加载和执行限制在浏览器端,同时注意penumbra加载后会挂载到全局window对象上,可直接从window取实例使用,示例代码:

import { useEffect, useState } from 'react';

export default function TargetPage() {
  const [penumbraInstance, setPenumbraInstance] = useState(null);

  useEffect(() => {
    // useEffect内的逻辑仅在浏览器端执行,不会跑在SSR阶段
    const loadModule = async () => {
      await import('@transcend-io/penumbra');
      // 模块加载完成后直接从window取挂载的实例
      setPenumbraInstance(window.penumbra);
    };
    loadModule();
  }, []);

  // 模块未加载完成时返回兜底态
  if (!penumbraInstance) return <div>资源加载中</div>;

  // 后续可直接调用penumbraInstance的相关方法
  return <div>功能组件</div>;
}

如果用NextJS的next/dynamic语法,记得必须加ssr: false配置,禁止服务端渲染该模块相关组件。

方案2:配置服务端外部依赖+脚本引入(兜底)

如果方案1仍有解析报错,可直接配置NextJS不参与penumbra模块的服务端打包,完全绕开服务端解析逻辑:

  1. 修改NextJS配置文件,将penumbra加入服务端外部包列表:
/** @type {import('next').NextConfig} */
const nextConfig = {
  serverExternalPackages: ['@transcend-io/penumbra'],
};

module.exports = nextConfig;
  1. 在页面中通过NextJS内置的Script组件引入penumbra的浏览器端脚本,等脚本加载完成后从window取实例使用即可。

注意事项

  • 所有penumbra相关的调用逻辑,必须放在浏览器端执行的上下文里:比如useEffect回调、用户交互事件回调、脚本加载完成回调,禁止在组件顶层、服务端数据获取函数、元数据生成函数等服务端执行的代码块中调用penumbra
  • 不要尝试在服务端给window做polyfill兼容,penumbra依赖大量浏览器专属API(Web流、Service Worker相关能力等),Node环境下即使打了polyfill也无法正常运行

内容的提问来源于stack exchange,提问作者user16100351

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:18:15