Next.js导入JS文件报错:ReferenceError: navigator is not defined
这个问题我之前在Next.js项目里踩过坑!根源在于Next.js默认的服务端渲染(SSR)机制:codemirror/mode/python/python.js内部直接使用了浏览器专属的navigator对象,但SSR阶段是在服务器环境运行的,根本没有这个浏览器API,所以就抛出了ReferenceError。
下面给你两种靠谱的解决办法,亲测有效:
方法1:用next/dynamic动态导入(推荐)
通过next/dynamic把依赖浏览器环境的CodeMirror组件和Python模式都设置为仅客户端渲染,这样就能避开SSR阶段的环境差异。
修改你的组件代码如下:
import Link from "next/link"; import dynamic from "next/dynamic"; import "../node_modules/codemirror/lib/codemirror.css"; import "../node_modules/codemirror/theme/material.css"; import styled from "styled-components"; // 动态导入CodeMirror,同时在客户端加载Python模式 const CodeMirror = dynamic( () => { // 仅在客户端环境执行此导入,此时navigator已存在 import("../node_modules/codemirror/mode/python/python.js"); return import("react-codemirror2").then(mod => mod.UnControlled); }, { ssr: false } // 禁用服务端渲染 ); const CodeContainer = styled.div` position: absolute; width: 600px; left: 600px; height: 100%; overflow-y: auto; z-index: 1; `; const Code = () => ( <CodeContainer> <CodeMirror value="print('Hello Python!')" // 换成Python代码测试 options={{ mode: "python", theme: "material", lineNumbers: true }} onChange={(editor, data, value) => {}} /> </CodeContainer> ); export default Code;
方法2:在useEffect中延迟导入
useEffect是React仅在客户端渲染阶段执行的钩子,把Python模式的导入放在这里,就能确保只在浏览器环境下加载:
import Link from "next/link"; import { UnControlled as CodeMirror } from "react-codemirror2"; import { useEffect } from "react"; import "../node_modules/codemirror/lib/codemirror.css"; import "../node_modules/codemirror/theme/material.css"; import styled from "styled-components"; const CodeContainer = styled.div` position: absolute; width: 600px; left: 600px; height: 100%; overflow-y: auto; z-index: 1; `; const Code = () => { // 客户端渲染时才加载Python模式 useEffect(() => { import("../node_modules/codemirror/mode/python/python.js"); }, []); return ( <CodeContainer> <CodeMirror value="print('Hello Python!')" options={{ mode: "python", theme: "material", lineNumbers: true }} onChange={(editor, data, value) => {}} /> </CodeContainer> ); }; export default Code;
原理说明
两种方法的核心都是让Python模式的代码只在客户端环境执行:
- 方法1通过
next/dynamic的ssr: false选项,直接把整个CodeMirror相关逻辑排除在SSR之外; - 方法2利用
useEffect的执行时机,延迟导入需要浏览器API的模块。
这样修改后,你就能正常使用CodeMirror渲染Python代码,不会再碰到navigator is not defined的错误了。
内容的提问来源于stack exchange,提问作者StackUnderFlow




