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

Node fs读取文件报ENOENT错误:路径存在但无法访问

问题排查:fs.readFileSync 找不到已存在的文件

问题背景

我在项目中使用Node.js的fs模块编写了读取文件的代码,该代码属于Container类的SetComponent方法。当用vitest调用Container.SetComponent()时,抛出文件不存在的错误,但实际文件确实存在。尝试添加.tsx后缀、使用ts-node和tsx运行均未解决问题。

关键代码片段

SetComponent方法中读取文件的核心代码:

const files: FileSystemTree = {
  "Component.tsx": {
    file: {
      contents: fs.readFileSync(
        `../../apps/components/${name.toLowerCase()}/${name.charAt(0).toUpperCase()}${name.slice(1)}.tsx`
      )
    }
  }
};

完整Container类代码

import {WebContainer, FileSystemTree} from "@webcontainer/api";
import fs from "fs";

export default class Container {
  private mContainer!: WebContainer;

  constructor() {
    this.CreateContainer();
    this.ScaffoldViteApp();
    this.StartDevServer();
  }

  private CreateContainer = async () => {
    try {
      this.mContainer = await WebContainer.boot();
    } catch (err) {
      throw new Error(JSON.stringify(err));
    }

    return this.mContainer;
  }; 

  private ScaffoldViteApp = async () => {
    try {
      this.mContainer.spawn("npm", [
        "create",
        "vite",
        "container-example -- --template react-swc-ts"
      ]);
    } catch (err) {
      throw new Error(JSON.stringify(err));
    }

    return this.mContainer;
  };

  private StartDevServer = async () => {
    try {
      this.mContainer.spawn("npm", ["run", "dev"]);
    } catch (err) {
      throw new Error(JSON.stringify(err));
    }

    return this.mContainer;
  };

  public SetComponent(name: string) {
    const files: FileSystemTree = {
      "Component.tsx": {
        file: {
          contents: fs.readFileSync(
            `../../apps/components/${name.toLowerCase()}/${name.charAt(0).toUpperCase()}${name.slice(1)}.tsx`
          )
        }
      }
    };

    console.log(fs.readFileSync(
        `../../apps/components/${name.toLowerCase()}/${name.charAt(0).toUpperCase()}${name.slice(1)}`
      ))

    try {
      this.mContainer.fs.mkdir("components");
    } catch (err) {
      throw new Error(JSON.stringify(err));
    }

    try {
      this.mContainer.mount(files, {mountPoint: "components"});
    } catch (err) {
      throw new Error(JSON.stringify(err));
    }

    return this.mContainer;
  }

  public GetIframe() {
    return this.mContainer.on("server-ready", (port, url) => {
      return url;
    });
  }

  public WriteComponent(name: string, content: string) {
    const files: FileSystemTree = {
      "Component.tsx": {
        file: {
          contents: content
        }
      }
    };

    try {
      this.mContainer.mount(files, {mountPoint: "components"});
    } catch (err) {
      throw new Error(JSON.stringify(err));
    }

    return this.mContainer;
  }
}

错误信息

Error: ENOENT: no such file or directory, open '../../apps/components/example/Example'

项目结构

.
├── README.md
├── apps
│   ├── components
│   │   ├── example
│   │   │   ├── Example.tsx
│   │   │   ├── stories
│   │   │   │   └── Example.stories.tsx
│   │   │   └── tests
│   │   │       └── example.spec.tsx
│   │   └── project.json
│   ├── docs
│   │   ├── README.md
│   │   ├── astro.config.mjs
│   │   ├── node_modules
│   │   │   ├── @astrojs
│   │   │   │   ├── check -> ../../../../node_modules/.pnpm/@astrojs+check@0.7.0_prettier@3.2.5_typescript@5.4.5/node_modules/@astrojs/check
│   │   │   │   └── starlight -> ../../../../node_modules/.pnpm/@astrojs+starlight@0.23.2_astro@4.9.2_@types+node@20.12.13_terser@5.31.0_typescript@5.4.5_/node_modules/@astrojs/starlight
│   │   │   ├── astro -> ../../../node_modules/.pnpm/astro@4.9.2_@types+node@20.12.13_terser@5.31.0_typescript@5.4.5/node_modules/astro
│   │   │   ├── sharp -> ../../../node_modules/.pnpm/sharp@0.32.6/node_modules/sharp
│   │   │   └── typescript -> ../../../node_modules/.pnpm/typescript@5.4.5/node_modules/typescript
│   │   ├── package.json
│   │   ├── project.json
│   │   ├── public
│   │   │   └── favicon.svg
│   │   └── src
│   │       ├── assets
│   │       │   └── houston.webp
│   │       ├── content
│   │       │   ├── config.ts
│   │       │   └── docs
│   │       │       ├── components
│   │       │       │   └── example.mdx
│   │       │       ├── guides
│   │       │       │   └── example.md
│   │       │       └── index.mdx
│   │       └── env.d.ts
│   └── storybook
│       ├── node_modules
│       ├── package.json
│       ├── project.json
│       ├── tsconfig.json
│       └── tsconfig.storybook.json
├── docs
│   ├── assets
│   │   ├── highlight.css
│   │   ├── icons.js
│   │   ├── icons.svg
│   │   ├── main.js
│   │   ├── navigation.js
│   │   ├── search.js
│   │   └── style.css
│   ├── functions
│   │   └── default.html
│   ├── index.html
│   ├── modules.html
│   └── types
│       └── Props.html
├── eslint.config.js
├── index.css
├── nx.json
├── package.json
├── packages
│   ├── docs-sandbox
│   │   ├── createContainer.ts
│   │   ├── project.json
│   │   └── tests
│   │       └── createContainer.spec.ts
│   ├── etech-ui-dev
│   │   └── project.json
│   └── etech-ui-utils
│       └── project.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── postcss.config.cjs
├── reactDocgen.ts
├── tailwind.config.js
├── tests
│   └── setup.ts
├── tsconfig.astro.json
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.react.json
├── types
│   └── eslint-plugin-react.d.ts
└── vite.config.ts

解决方案

1. 修复console.log中的路径缺失后缀

错误信息里的路径../../apps/components/example/Example缺少.tsx后缀,这是直接触发报错的原因。修改SetComponent方法中的console.log代码:

console.log(fs.readFileSync(
  `../../apps/components/${name.toLowerCase()}/${name.charAt(0).toUpperCase()}${name.slice(1)}.tsx`
))

2. 使用绝对路径避免工作目录问题

vitest运行时的工作目录可能和预期不一致(比如从packages/docs-sandbox/tests目录执行),相对路径会失效。改用绝对路径:

  • 先导入path模块:import path from "path";
  • 修改fs.readFileSync的路径为绝对路径:
const componentPath = path.resolve(
  __dirname,
  `../../apps/components/${name.toLowerCase()}/${name.charAt(0).toUpperCase()}${name.slice(1)}.tsx`
);
// 替换两处fs.readFileSync的路径为componentPath

如果是ES模块环境,也可以用import.meta.url替代__dirname:

const componentPath = new URL(
  `../../apps/components/${name.toLowerCase()}/${name.charAt(0).toUpperCase()}${name.slice(1)}.tsx`,
  import.meta.url
).pathname;

3. 修复异步方法调用的时序问题

Container构造函数中直接调用异步方法(CreateContainer、ScaffoldViteApp、StartDevServer)但未使用await,会导致mContainer还未初始化就调用SetComponent,引发潜在问题。建议重构为异步初始化:

export default class Container {
  private mContainer!: WebContainer;

  private constructor() {}

  public static async init() {
    const container = new Container();
    await container.CreateContainer();
    await container.ScaffoldViteApp();
    await container.StartDevServer();
    return container;
  }

  // ...其他方法保持不变
}

// 使用时:
const container = await Container.init();
container.SetComponent("example");

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 23:35:55