Next.js构建时遇ReferenceError: navigator is not defined问题求助
问题背景
我在TypeScript的Next.js项目中,实现了基于TinyMCE的BundledEditor组件:
// ** 参考TinyMCE官方文档实现 **// import { Editor } from '@tinymce/tinymce-react' // TinyMCE so the global var exists // eslint-disable-next-line no-unused-vars import tinymce from 'tinymce/tinymce' // DOM model import 'tinymce/models/dom/model' // Theme import 'tinymce/themes/silver' // Toolbar icons import 'tinymce/icons/default' // Editor styles import 'tinymce/skins/ui/oxide/skin.min.css' // 导入所需插件 import 'tinymce/plugins/advlist' import 'tinymce/plugins/anchor' import 'tinymce/plugins/autolink' import 'tinymce/plugins/autoresize' import 'tinymce/plugins/autosave' import 'tinymce/plugins/charmap' import 'tinymce/plugins/code' import 'tinymce/plugins/codesample' import 'tinymce/plugins/directionality' import 'tinymce/plugins/emoticons' import 'tinymce/plugins/fullscreen' import 'tinymce/plugins/help' import 'tinymce/plugins/image' import 'tinymce/plugins/importcss' import 'tinymce/plugins/insertdatetime' import 'tinymce/plugins/link' import 'tinymce/plugins/lists' import 'tinymce/plugins/media' import 'tinymce/plugins/nonbreaking' import 'tinymce/plugins/pagebreak' import 'tinymce/plugins/preview' import 'tinymce/plugins/quickbars' import 'tinymce/plugins/save' import 'tinymce/plugins/searchreplace' import 'tinymce/plugins/table' import 'tinymce/plugins/template' import 'tinymce/plugins/visualblocks' import 'tinymce/plugins/visualchars' import 'tinymce/plugins/wordcount' // 导入插件资源 import 'tinymce/plugins/emoticons/js/emojis' // 内容样式 /* eslint import/no-webpack-loader-syntax: off */ import contentCss from '!!raw-loader!tinymce/skins/content/default/content.min.css' import contentUiCss from '!!raw-loader!tinymce/skins/ui/oxide/content.min.css' export default function BundledEditor(props) { const { init, ...rest } = props return ( <Editor init={{ ...init, skin: false, content_css: false, content_style: [contentCss, contentUiCss, init.content_style || ''].join('\n') }} {...rest} /> ) }
最初直接通过import BundledEditor from './BundledEditor';引入时,页面可正常运行,但刷新时抛出:
ReferenceError: navigator is not defined
改用动态导入后解决了刷新问题:
const BundledEditor = dynamic(() => import('../BundledEditor'), { ssr: false })
但执行yarn build时仍出现相同错误:
info - Collecting page data ...ReferenceError: navigator is not defined at /Users/motogod19/4iDPS/Sphere/sphere-brand-dev/node_modules/tinymce/tinymce.js:961:23 at Object.<anonymous> (/Users/motogod19/4iDPS/Sphere/sphere-brand-dev/node_modules/tinymce/tinymce.js:31525:3) at Module._compile (node:internal/modules/cjs/loader:1254:14) at Module._extensions..js (node:internal/modules/cjs/loader:1308:10) at Module.load (node:internal/modules/cjs/loader:1117:32) at Module._load (node:internal/modules/cjs/loader:958:12) at Module.require (node:internal/modules/cjs/loader:1141:19) at require (node:internal/modules/cjs/helpers:110:18) at 3868 (/Users/motogod19/4iDPS/Sphere/sphere-brand-dev/.next/server/pages/apps/campaign/BundledEditor.js:28:33) at __webpack_require__ (/Users/motogod19/4iDPS/Sphere/sphere-brand-dev/.next/server/webpack-runtime.js:25:42) > Build error occurred Error: Failed to collect page data for /apps/campaign/BundledEditor
解决方法
1. 调整组件存放目录
不要将BundledEditor组件放在pages目录下。Next.js会自动对pages目录下的所有文件执行SSR预渲染,即便使用了dynamic({ ssr: false }),构建时仍会解析模块内的静态导入,导致TinyMCE在服务端执行时访问navigator报错。
将BundledEditor移到components目录,再进行动态导入。
2. 使用Next.js客户端组件标记(Next.js 13+)
如果你的项目使用Next.js 13及以上版本,直接在BundledEditor组件顶部添加'use client'指令,标记其为客户端组件,跳过服务端渲染:
'use client'; // 添加这行 import { Editor } from '@tinymce/tinymce-react'; // ... 其余导入和组件代码保持不变
添加后无需再使用dynamic导入,直接正常引入组件即可:
import BundledEditor from '../components/BundledEditor';
3. 优化动态导入逻辑(兼容旧版Next.js)
如果使用Next.js 12及以下版本,确保动态导入时,组件内的TinyMCE相关代码仅在客户端执行。可以将TinyMCE的核心导入放在动态导入的回调中,或者在组件内部通过typeof window判断:
// 动态导入时直接加载客户端组件 const BundledEditor = dynamic(() => import('../components/BundledEditor'), { ssr: false, loading: () => <div>加载编辑器中...</div> // 可选加载态 });
同时在BundledEditor组件中,避免在模块顶层执行依赖浏览器环境的代码,确保所有TinyMCE相关逻辑在组件挂载后执行。
4. 验证修复
调整后执行yarn build,确认构建过程不再抛出navigator is not defined错误。
内容的提问来源于stack exchange,提问作者Morton

