在Next.js 14.1.0中导入Bootstrap 5.3.2出现document未定义错误
解决Next.js 14.1.0 App Router中Bootstrap 5.3.2组件SSR时
document is not defined的问题 问题现象
硬刷新页面时触发500错误,控制台报错:
⨯ node_modules/bootstrap/dist/js/bootstrap.esm.js (803:18) @ document ⨯ ReferenceError: document is not defined at __webpack_require__ (/Users/rsilva/Desktop/bs/.next/server/webpack-runtime.js:33:42) at eval (./app/TooltipComponent.js:9:67) at (ssr)/./app/TooltipComponent.js (/Users/rsilva/Desktop/bs/.next/server/app/page.js:162:1) at __webpack_require__ (/Users/rsilva/Desktop/bs/.next/server/webpack-runtime.js:33:42)
问题原因
虽然TooltipComponent添加了"use client"指令,但模块顶部的import { Tooltip } from "bootstrap"会在**服务端渲染(SSR)**阶段被执行。Bootstrap的ESM模块加载时会直接访问浏览器特有的document对象,而Node.js服务端环境不存在该对象,导致报错。
解决方案
方案1:在客户端 useEffect 中动态导入Tooltip
修改TooltipComponent,将Bootstrap的Tooltip导入和实例化逻辑移到客户端的useEffect中,确保仅在浏览器环境执行:
"use client"; import { useEffect, useRef } from "react"; export function TooltipComponent({ children, title = "Missing tooltip 'title' property", placement = "top", trigger = "hover", }) { const tooltipRef = useRef(); const tooltipInstanceRef = useRef(null); useEffect(() => { if (!title) return; async function initTooltip() { // 仅在客户端动态导入Bootstrap Tooltip const { Tooltip } = await import("bootstrap/dist/js/bootstrap.esm.js"); tooltipInstanceRef.current = new Tooltip(tooltipRef.current, { title, placement, trigger, container: "body", }); } initTooltip(); return () => { // 组件卸载时销毁Tooltip实例 if (tooltipInstanceRef.current) { tooltipInstanceRef.current.dispose(); } }; }, [title, placement, trigger]); return <span ref={tooltipRef}>{children}</span>; }
方案2:使用Next.js动态导入禁用SSR
如果需要对整个组件禁用服务端渲染,可在page.js中通过dynamic导入组件:
import dynamic from 'next/dynamic'; // 禁用该组件的SSR,仅在客户端加载 const TooltipComponent = dynamic( () => import('./TooltipComponent').then(mod => mod.TooltipComponent), { ssr: false } ); export default function Home() { return ( <main> <TooltipComponent title="Test"> test tooltip </TooltipComponent> </main> ); }
补充说明
- 原
BootstrapProvider可保留,它负责将Bootstrap挂载到window对象上,与上述方案不冲突;若仅使用动态导入的Tooltip,也可移除该Provider。 - 核心思路是确保Bootstrap的JS代码仅在浏览器环境执行,避免服务端渲染时访问浏览器专属API。
内容的提问来源于stack exchange,提问作者rsilva
相关产品推荐
相关产品推荐

