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

启动NextJS项目时JSDOM报错:无法解析‘net’模块,求帮助

解决NextJS中使用jsdom出现Module not found: Can't resolve 'net'错误

问题原因

jsdom是基于Node.js环境开发的库,依赖net等Node核心模块,但NextJS的客户端组件默认运行在浏览器环境,浏览器不提供这些Node专属模块,因此直接在客户端组件中导入jsdom会触发模块找不到的错误。

解决方案

将使用jsdom和Readability的抓取逻辑移至服务器端执行,比如API路由、服务器组件或服务端数据获取函数中,以下是两种常用实现方式:

方式一:通过API路由处理抓取逻辑

  1. 在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: "抓取失败" });
  }
}
  1. 修改客户端组件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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 08:10:23