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

Next.js TypeScript集成TinyMce报错:navigator is not defined

解决Next.js + TinyMCE本地打包刷新时navigator is not defined错误

问题描述

我在TypeScript版本的Next.js项目中,采用本地打包方式集成TinyMCE(无需API key),参考官方文档创建了BundledEditor.jsx组件,正常使用无问题,但刷新页面时会抛出ReferenceError: navigator is not defined错误。

错误原因

Next.js默认采用服务端渲染(SSR),TinyMCE的核心依赖代码会尝试访问navigator这个浏览器专属全局对象,而服务端环境中不存在该对象,因此刷新页面(服务端重新渲染组件)时会触发错误。

解决方案

只需确保TinyMCE相关组件仅在客户端环境中渲染,以下是两种简洁的实现方式:


方案一:动态导入组件并禁用SSR(推荐)

在使用BundledEditor的tsx文件中,改用Next.js提供的dynamic函数导入组件,明确禁用服务端渲染:

import { useRef } from 'react'
import dynamic from 'next/dynamic'

// 动态导入BundledEditor,指定仅在客户端渲染
const BundledEditor = dynamic(() => import('../BundledEditor'), {
  ssr: false,
  loading: () => <div>加载编辑器中...</div> // 可选的加载占位UI
})

const editorRef = useRef<any>(null)

return (
  <>
    <BundledEditor
      onInit={(evt: any, editor: any) => (editorRef.current = editor)}
      initialValue=''
      init={{
        height: 500,
        menubar: false,
        plugins: [
          'advlist',
          'anchor',
          'autolink',
          'help',
          'image',
          'link',
          'lists',
          'searchreplace',
          'table',
          'wordcount'
        ],
        toolbar:
          'undo redo | blocks | ' +
          'bold italic forecolor | alignleft aligncenter ' +
          'alignright alignjustify | bullist numlist outdent indent | ' +
          'removeformat | help',
        content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
      }}
    />
  </>
);

方案二:在组件内部判断客户端环境

修改BundledEditor.jsx,通过useEffect和状态判断,确保仅在客户端环境渲染编辑器:

import React, { useEffect, useState } from 'react'
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'

// importing the plugin js.
// if you use a plugin that is not listed here the editor will fail to load
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'

// importing plugin resources
import 'tinymce/plugins/emoticons/js/emojis'

// Content styles, including inline UI like fake cursors
/* 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
  const [isClient, setIsClient] = useState(false)

  useEffect(() => {
    // 仅在客户端环境执行此逻辑
    setIsClient(true)
  }, [])

  // 服务端渲染时返回占位UI
  if (!isClient) {
    return <div>加载编辑器中...</div>
  }

  return (
    <Editor
      init={{
        ...init,
        skin: false,
        content_css: false,
        content_style: [contentCss, contentUiCss, init.content_style || ''].join('\n')
      }}
      {...rest}
    />
  )
}

说明:两种方案都能解决问题,方案一代码更简洁,且直接利用Next.js特性隔离服务端渲染逻辑,是更推荐的做法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:09:58