启动NextJS项目时JSDOM报错:无法解析‘net’模块,求帮助
解决NextJS中使用jsdom出现
Module not found: Can't resolve 'net'错误 问题原因
jsdom是基于Node.js环境开发的库,依赖net等Node核心模块,但NextJS的客户端组件默认运行在浏览器环境,浏览器不提供这些Node专属模块,因此直接在客户端组件中导入jsdom会触发模块找不到的错误。
解决方案
将使用jsdom和Readability的抓取逻辑移至服务器端执行,比如API路由、服务器组件或服务端数据获取函数中,以下是两种常用实现方式:
方式一:通过API路由处理抓取逻辑
- 在
pages/api目录下新建fetch-news-content.js文件,编写服务器端抓取代码:
import { JSDOM } from "jsdom"; import { Readability } from "@mozilla/readability"; export default async function handler(req, res) { const { url } = req.query; if (!url) { return res.status(400).json({ error: "URL参数缺失" }); } try { const response = await fetch(url); const html = await response.text(); const dom = new JSDOM(html, { url }); const reader = new Readability(dom.window.document); const article = reader.parse(); res.status(200).json(article); } catch (error) { res.status(500).json({ error: "抓取失败" }); } }
- 修改客户端组件
MinBlock.js,通过fetch调用API获取内容:
'use client' import Image from "next/image"; import { useState, useEffect } from "react"; function MinBlock({ headline, tagline, imgUrl, newsUrl }) { const [articleContent, setArticleContent] = useState(null); function urlPasser(str) { const regExp = /^http/gi; return regExp.test(str) ? str : ""; } useEffect(() => { async function fetchContent() { if (!newsUrl) return; const res = await fetch(`/api/fetch-news-content?url=${encodeURIComponent(newsUrl)}`); const data = await res.json(); setArticleContent(data); } fetchContent(); }, [newsUrl]); return ( <a href={newsUrl || '#'} className="grid grid-cols-4 gap-2 group"> <div className="col-span-1 bg-cover h-24 relative" style={{ backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.6 ))`, }} > {urlPasser(imgUrl) && ( <Image src={imgUrl} alt={headline} fill style={{ objectFit: "cover", }} /> )} </div> <div className="col-span-3"> <p className="font-light text-xs">{tagline}</p> <h3 className="font-header text-xl my-2 group-hover:text-primary-600"> {headline} </h3> {articleContent && <p className="text-sm text-gray-600">{articleContent.excerpt}</p>} </div> </a> ); } export default MinBlock;
方式二:使用NextJS 13+ App Router的服务器组件
如果项目采用App Router,可直接将组件设为服务器组件,在组件内部执行抓取逻辑:
// app/components/MinBlock.js import Image from "next/image"; import { JSDOM } from "jsdom"; import { Readability } from "@mozilla/readability"; async function fetchArticleContent(url) { if (!url) return null; try { const response = await fetch(url); const html = await response.text(); const dom = new JSDOM(html, { url }); const reader = new Readability(dom.window.document); return reader.parse(); } catch (error) { console.error("抓取失败:", error); return null; } } function urlPasser(str) { const regExp = /^http/gi; return regExp.test(str) ? str : ""; } export default async function MinBlock({ headline, tagline, imgUrl, newsUrl }) { const articleContent = await fetchArticleContent(newsUrl); return ( <a href={newsUrl || '#'} className="grid grid-cols-4 gap-2 group"> <div className="col-span-1 bg-cover h-24 relative" style={{ backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.6 ))`, }} > {urlPasser(imgUrl) && ( <Image src={imgUrl} alt={headline} fill style={{ objectFit: "cover", }} /> )} </div> <div className="col-span-3"> <p className="font-light text-xs">{tagline}</p> <h3 className="font-header text-xl my-2 group-hover:text-primary-600"> {headline} </h3> {articleContent && <p className="text-sm text-gray-600">{articleContent.excerpt}</p>} </div> </a> ); }
额外说明
- 若使用NextJS 12及以下的Pages Router,也可通过
getServerSideProps在页面层面完成数据抓取,再将结果传递给组件。 - 所有依赖Node核心模块的代码(如jsdom、fs、net相关操作)都必须放在服务器端执行,避免在客户端组件中调用。
内容的提问来源于stack exchange,提问作者Yagi91
相关产品推荐
相关产品推荐

