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

如何让Rollup在Jest测试中使用模拟文件系统?

问题

为Rollup插件编写测试时,使用memfs模拟内存文件系统,但运行测试报错RollupError: Could not resolve entry module "src/index.js"。直接用fs模块能读取到文件内容,但Rollup似乎没使用模拟的文件系统。测试代码如下:

import { describe, expect, jest, test } from "@jest/globals";
import memfs from "memfs";
import {
  InputOptions,
  OutputAsset,
  OutputChunk,
  OutputOptions,
  rollup,
} from "rollup";
import { externalAssets } from "../src";

jest.mock("fs", () => memfs.fs);
jest.mock("fs/promises", () => memfs.fs.promises);

async function build(inputOptions: InputOptions, outputOptions: OutputOptions) {
  const bundle = await rollup(inputOptions);
  try {
    const { output } = await bundle.generate(outputOptions);

    const chunks = output.filter(
      (file): file is OutputChunk => file.type === "chunk"
    );
    const assets = output.filter(
      (file): file is OutputAsset => file.type === "asset"
    );

    return { chunks, assets };
  } finally {
    await bundle.close();
  }
}

describe("produces correct import paths", () => {
  test("chunk and asset in same dir", async () => {
    memfs.vol.fromJSON({
      "assets/text.txt": "Lorem Ipsum is simply dummy text",
      "src/index.js": `
      import txt from "../assets/text.txt";
      console.log(txt);
      `,
    });

    const { chunks } = await build(
      {
        input: "src/index.js",
        plugins: [externalAssets("assets/*")],
      },
      {
        assetFileNames: "[name][extname]",
        file: "index.js",
      }
    );

    expect(chunks).toHaveLength(1);
    expect(chunks[0].code).toMatchSnapshot();
  });
});

解决方案

Rollup 默认不会直接依赖 Node.js 的 fs 模块处理文件,而是有自己的文件系统抽象层,单纯 mock fs 和 fs/promises 无法让 Rollup 切换到内存文件系统,需要通过 Rollup 插件机制替换它的文件读取逻辑,有两种可行方案:

方案一:使用@rollup/plugin-virtual注入虚拟文件

如果测试用的文件内容固定,可以直接用该插件在 Rollup 配置中注入虚拟文件,无需依赖 memfs:

import virtual from '@rollup/plugin-virtual';

// 在 build 的 inputOptions 中添加插件
plugins: [
  virtual({
    'src/index.js': `
      import txt from "../assets/text.txt";
      console.log(txt);
    `,
    'assets/text.txt': 'Lorem Ipsum is simply dummy text'
  }),
  externalAssets("assets/*")
]

方案二:自定义插件适配memfs

编写一个轻量插件,拦截 Rollup 的文件解析和读取钩子,用 memfs 处理文件操作:

function memfsRollupPlugin() {
  return {
    name: 'memfs-plugin',
    async resolveId(source, importer) {
      const resolvedPath = require('path').resolve(
        importer ? require('path').dirname(importer) : process.cwd(),
        source
      );
      // 告知Rollup该路径由当前插件处理
      if (memfs.vol.existsSync(resolvedPath)) {
        return resolvedPath;
      }
      return null; // 其他路径交给默认逻辑处理
    },
    async load(id) {
      // 用memfs读取文件内容
      if (memfs.vol.existsSync(id)) {
        return memfs.vol.readFileSync(id, 'utf8');
      }
      return null;
    }
  };
}

// 在测试的inputOptions中添加该插件
plugins: [memfsRollupPlugin(), externalAssets("assets/*")]

注意事项

  • 确保memfs.vol.fromJSON()的调用在build函数执行前完成,保证内存文件系统已初始化
  • 若使用TypeScript,可给自定义插件添加类型声明,或用// @ts-ignore临时忽略类型检查

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 06:15:15