Search code examples
node.jstypescriptfilesystemsvitestnode.js-fs

Node fs file does not exist


I have the following code to read a file in my project with Node fs.

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

Which is part of the overall class:

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;
  }
}

When I use vitest to run: Container.SetComponent() I get an error:

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

However, upon commanding clicking the path it does in fact exist. I have tried the same thing with a .tsx ending to no avail. I have also tried running the file with ts-node and tsx and I get the same results. Here is my project structure:

.
├── 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/@[email protected][email protected][email protected]/node_modules/@astrojs/check
│   │   │   │   └── starlight -> ../../../../node_modules/.pnpm/@[email protected][email protected]_@[email protected][email protected][email protected]_/node_modules/@astrojs/starlight
│   │   │   ├── astro -> ../../../node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/astro
│   │   │   ├── sharp -> ../../../node_modules/.pnpm/[email protected]/node_modules/sharp
│   │   │   └── typescript -> ../../../node_modules/.pnpm/[email protected]/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

Solution

  • This is probably because paths in node are relative to the current working directory (where you invoked the command to launch the node executable) and not from the file with the path in it.

    So you probably either want this, if apps is in the root of your project where you are running this command from:

    apps/components/path/here
    

    Or perhaps this if you want it to be relative to the current file:

    path.join(__dirname, '../../app/components/path/here')
    // or if using es modules
    path.join(import.meta.dirname, '../../app/components/path/here')