npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jisan901/fs-browser

v1.0.1

Published

Browser-compatible filesystem API with Vite plugin support

Readme

@jisan901/fs-browser

Browser-compatible filesystem API with Vite plugin support. Write Node.js-style fs code that works in the browser!

Features

  • 🚀 Node.js-like fs API for the browser
  • 🔌 Vite plugin for seamless integration
  • 📦 Supports all major file operations
  • 💪 Full TypeScript support
  • 🎯 Handles text, JSON, binary, and Blob data
  • 🔒 Safe path resolution with base directory protection

Installation

npm install @jisan901/fs-browser

Quick Start

Development with Vite

1. Setup Vite Plugin

// vite.config.js
import { defineConfig } from 'vite';
import fsPlugin from '@jisan901/fs-browser/plugin';

export default defineConfig({
  plugins: [
    fsPlugin({
      baseDir: './data',      // Base directory for file operations
      apiPrefix: '/api/fs'    // API route prefix
    })
  ]
});

2. Use in Browser Code

import { readFile, writeFile, mkdir } from '@jisan901/fs-browser';

// Write a file
await writeFile('hello.txt', 'Hello World!');

// Read a file
const content = await readFile('hello.txt');
console.log(content); // "Hello World!"

// Create directory
await mkdir('myFolder', { recursive: true });

// Write JSON
await writeFile('data.json', { name: 'John', age: 30 });

// Write binary data
const blob = new Blob([imageData], { type: 'image/png' });
await writeFile('image.png', blob);



fs.configure({ 
  apiBase: 'http://localhost:2300/api/fs' 
});


Production - Serve Built Projects

After building your project, use the withfs CLI to serve it with fs API support:

# Build your project
npm run build

# Serve with fs API support
withfs ./dist --host

# Or with custom options
withfs ./dist --host --port 8080 --open

CLI Options:

withfs [projectDir] [options]

Options:
  --host, -h <host>          Host (default: localhost, use --host for 0.0.0.0)
  --port, -p <port>          Port (default: 3000)
  --base-dir, -b <dir>       Base dir for fs operations (default: ./data)
  --api-prefix, -a <prefix>  API route prefix (default: /api/fs)
  --open, -o                 Open browser automatically
  --justfs                   Only run fs API (no static file serving)
  --help                     Show help message

Example Workflow:

# Development
npm run dev

# Build
npm run build

# Production serve with fs API
withfs ./dist --host --open

Development with Other Frameworks

While @jisan901/fs-browser includes a Vite plugin, you can use it with any framework or development setup by running the withfs server separately.

React (Create React App, Next.js)

Option 1: Proxy (Recommended for CRA)

// package.json (Create React App)
{
  "proxy": "http://localhost:5001"
}
# Terminal 1: fs API server
withfs --justfs --port 5001

# Terminal 2: React dev server
npm start
// App.js
import { readFile, writeFile } from '@jisan901/fs-browser';

function App() {
  const handleSave = async () => {
    await writeFile('data.txt', 'Hello from React!');
  };
  
  return <button onClick={handleSave}>Save File</button>;
}

Option 2: Configure API Base (Next.js, App Router)

// lib/fs.js
import fs from '@jisan901/fs-browser';

export default fs.configure({ 
  apiBase: 'http://localhost:5001/api/fs' 
});
// app/page.js
import fs from '@/lib/fs';

export default function Page() {
  const saveFile = async () => {
    await fs.writeFile('notes.txt', 'Hello Next.js!');
  };
  
  return <button onClick={saveFile}>Save</button>;
}

Vue (Vue CLI, Nuxt)

Vue CLI with Proxy

// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api/fs': {
        target: 'http://localhost:5001',
        changeOrigin: true
      }
    }
  }
};
# Terminal 1: fs API server
withfs --justfs --port 5001

# Terminal 2: Vue dev server
npm run serve
<!-- App.vue -->
<script setup>
import { readFile, writeFile } from '@jisan901/fs-browser';

const saveFile = async () => {
  await writeFile('vue-data.json', { framework: 'Vue' });
};
</script>

<template>
  <button @click="saveFile">Save File</button>
</template>

Nuxt 3 with Configuration

// composables/useFs.js
import fs from '@jisan901/fs-browser';

export const useFs = () => {
  return fs.configure({ 
    apiBase: 'http://localhost:5001/api/fs' 
  });
};
<!-- pages/index.vue -->
<script setup>
const fs = useFs();

const saveData = async () => {
  await fs.writeFile('nuxt-file.txt', 'Hello Nuxt!');
};
</script>

Angular

Proxy Configuration

// proxy.conf.json
{
  "/api/fs": {
    "target": "http://localhost:5001",
    "secure": false,
    "changeOrigin": true
  }
}
// angular.json
{
  "serve": {
    "options": {
      "proxyConfig": "proxy.conf.json"
    }
  }
}
# Terminal 1: fs API server
withfs --justfs --port 5001

# Terminal 2: Angular dev server
ng serve
// app.component.ts
import { readFile, writeFile } from '@jisan901/fs-browser';

export class AppComponent {
  async saveFile() {
    await writeFile('angular-data.json', { framework: 'Angular' });
  }
}

Svelte (SvelteKit)

SvelteKit with Proxy

// vite.config.js
import { sveltekit } from '@sveltejs/kit/vite';

export default {
  plugins: [sveltekit()],
  server: {
    proxy: {
      '/api/fs': {
        target: 'http://localhost:5001',
        changeOrigin: true
      }
    }
  }
};
# Terminal 1: fs API server
withfs --justfs --port 5001

# Terminal 2: SvelteKit dev server
npm run dev
<!-- +page.svelte -->
<script>
  import { readFile, writeFile } from '@jisan901/fs-browser';
  
  async function saveFile() {
    await writeFile('svelte-data.txt', 'Hello SvelteKit!');
  }
</script>

<button on:click={saveFile}>Save File</button>

Astro

With Astro Dev Server

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  vite: {
    server: {
      proxy: {
        '/api/fs': {
          target: 'http://localhost:5001',
          changeOrigin: true
        }
      }
    }
  }
});
# Terminal 1: fs API server
withfs --justfs --port 5001

# Terminal 2: Astro dev server
npm run dev
---
// src/pages/index.astro
---
<script>
  import { writeFile } from '@jisan901/fs-browser';
  
  document.querySelector('#save')?.addEventListener('click', async () => {
    await writeFile('astro-data.json', { framework: 'Astro' });
  });
</script>

<button id="save">Save File</button>

Vanilla JavaScript / HTML

Direct Configuration

<!DOCTYPE html>
<html>
<head>
  <title>@jisan901/fs-browser Demo</title>
</head>
<body>
  <button id="save">Save File</button>
  <button id="read">Read File</button>
  <pre id="output"></pre>

  <script type="module">
    import fs from 'https://cdn.jsdelivr.net/npm/@jisan901/fs-browser/src/index.js';

    // Configure to point to your fs server
    const myFs = fs.configure({ 
      apiBase: 'http://localhost:5001/api/fs' 
    });

    document.getElementById('save').onclick = async () => {
      await myFs.writeFile('demo.txt', 'Hello from vanilla JS!');
      alert('File saved!');
    };

    document.getElementById('read').onclick = async () => {
      const content = await myFs.readFile('demo.txt');
      document.getElementById('output').textContent = content;
    };
  </script>
</body>
</html>
# Run the fs API server
withfs --justfs --port 5001 --host

# Open the HTML file in browser
# Or use any simple HTTP server:
python -m http.server 8000

Webpack Dev Server

Proxy Configuration

// webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      '/api/fs': {
        target: 'http://localhost:5001',
        changeOrigin: true
      }
    }
  }
};

Parcel

No configuration needed! Just run both servers:

# Terminal 1: fs API server
withfs --justfs --port 5001

# Terminal 2: Parcel dev server
npx parcel index.html
// Configure in your JS
import { configure } from '@jisan901/fs-browser';

configure({ apiBase: 'http://localhost:5001/api/fs' });

Production Deployment

For production, you have several options:

Option 1: Same Server

# Build your frontend
npm run build

# Serve everything together
withfs ./dist --host

Option 2: Separate Services

# Frontend on CDN/static host
# Backend fs API on separate server
withfs --justfs --host --port 5001

# Configure frontend to point to API
fs.configure({ apiBase: 'https://fs-api.example.com/api/fs' });

Option 3: Reverse Proxy (Nginx)

location /api/fs {
    proxy_pass http://localhost:5001/api/fs;
}

location / {
    root /var/www/html;
}

Environment Variables

Set API base via environment variables:

// config/fs.js
import fs from '@jisan901/fs-browser';

const API_BASE = import.meta.env.VITE_FS_API_BASE || 
                 process.env.REACT_APP_FS_API_BASE ||
                 '/api/fs';

export default fs.configure({ apiBase: API_BASE });
# .env
VITE_FS_API_BASE=http://localhost:5001/api/fs
# or
REACT_APP_FS_API_BASE=http://localhost:5001/api/fs

Docker Setup

# Dockerfile
FROM node:18

WORKDIR /app

# Install @jisan901/fs-browser globally
RUN npm install -g @jisan901/fs-browser

# Copy your built frontend
COPY ./dist ./dist

# Expose port
EXPOSE 3000

# Run withfs
CMD ["withfs", "./dist", "--host", "0.0.0.0", "--port", "3000"]
# docker-compose.yml
version: '3'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ./data:/app/data

Summary

  • Development: Run withfs --justfs on a separate port and use proxy or configure API base
  • Production: Use withfs ./dist --host to serve everything together
  • Microservices: Run withfs --justfs as a dedicated fs API service
  • Any Framework: Works with any setup that can make HTTP requests!

API Reference

File Reading

  • readFile(path, options?) - Read file contents
  • readdir(path, options?) - List directory contents
  • stat(path) - Get file/directory stats
  • lstat(path) - Get stats without following symlinks
  • realpath(path) - Get canonical path
  • readlink(path) - Read symbolic link
  • exists(path) - Check if file exists

File Writing

  • writeFile(path, data, options?) - Write data to file
  • appendFile(path, data, options?) - Append data to file
  • copyFile(src, dest, flags?) - Copy file

Directory Operations

  • mkdir(path, options?) - Create directory
  • rmdir(path, options?) - Remove directory
  • rm(path, options?) - Remove file or directory

File Manipulation

  • rename(oldPath, newPath) - Rename or move file/directory
  • unlink(path) - Delete file

TypeScript Support

Full TypeScript definitions included:

import { readFile, writeFile, Stats, Dirent } from '@jisan901/fs-browser';

const content: string = await readFile('test.txt', 'utf8');
const stats: Stats = await stat('test.txt');
const files: Dirent[] = await readdir('.', { withFileTypes: true });

Plugin Options

interface PluginOptions {
  baseDir?: string;    // Base directory for file operations (default: './data')
  apiPrefix?: string;  // API route prefix (default: '/api/fs')
}

Data Types Supported

  • Text: Plain text strings
  • JSON: JavaScript objects (auto-serialized)
  • Binary: Buffers, ArrayBuffers, TypedArrays
  • Blob: Browser Blob objects

Security

All file operations are restricted to the configured base directory. Attempts to access files outside this directory will throw an error.

License

MIT © claude:sonnet4.5

Contributing

Contributions welcome! Please open an issue or PR.