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

pochade-js

v0.9.5

Published

npx starter template for Pochade-JS projects

Readme

Pochade JS Splash Image

Pochade-JS

For Writing JS with Passion

There are some frameworks for writing careful enterprise software. This is not one of them.

Pochade-JS is a lightweight, opinionated starter template for building vanilla JavaScript projects with modern tooling. It's designed for developers who want to write quick, passionate code without the overhead of heavy frameworks.

What is Pochade-JS?

Pochade-JS provides a streamlined development environment for creating vanilla JS, CSS, and HTML projects with:

  • Custom HTML Elements - Built-in support for dataroom-js, making custom elements easy
  • Web Workers - First-class support for parallel processing with automatic bundling
  • Fast Builds - Powered by Rspack for lightning-fast development and production builds
  • Modern CSS - PostCSS with cssnano optimization
  • Static Assets - Automatic asset handling for images, fonts, and other static files
  • Context Engineering - Includes LLM-friendly documentation for AI-assisted development

Perfect for static websites, interactive web apps, browser extensions, or any project where you want vanilla JavaScript with modern tooling.


Quick Start

Create a new Pochade-JS project with a single command:

npx create-pochade-js my-project

The CLI will guide you through setup with interactive prompts:

  • Project title - Display name for your project
  • Project description - Brief description of what you're building
  • Project URL - Where your project will be hosted
  • Project image URL - Social sharing image
  • Project image alt text - Accessibility text for the image
  • Project site name - Name for social sharing
  • Author name - Your name
  • Author email - Your email address
  • GitHub username - For repository links
  • License - Project license (defaults to Unlicense)

After answering the prompts, Pochade-JS will:

  1. Create your project directory
  2. Copy all template files
  3. Configure package.json with your information
  4. Update index.html with your project metadata
  5. Install all dependencies automatically

Then just:

cd my-project
npm start

Your development server will be running at http://localhost:3000 (or your configured port).


Project Structure

my-project/
├── assets/              # Static files (images, fonts, etc.)
├── src/                 # JavaScript source files
│   ├── example-component.js
│   └── example-webworker.js
├── styles/              # CSS files
│   └── variables.css
├── scripts/             # Build scripts
│   └── transform-workers.js
├── index.html           # Main HTML file
├── index.js             # Main JavaScript entry point
├── index.css            # Main CSS file
├── rspack.config.js     # Build configuration
├── package.json         # Project metadata and dependencies
└── .env.example         # Environment variable template

Key Directories

assets/ - Place any static files here (images, fonts, PDFs, etc.). These files are:

  • Served from the root path (/) during development
  • Copied to the dist root during production builds
  • Accessible without any path prefix

src/ - Your JavaScript modules and components. Use ES6 imports/exports freely.

styles/ - CSS files organized by component or purpose. Import them in index.css.

scripts/ - Build-time scripts, including the web worker transformer.


Development

Starting the Dev Server

npm start

This starts the Rspack development server with:

  • Hot module replacement (HMR)
  • Source maps for debugging
  • Automatic recompilation on file changes
  • Static file serving from assets/
  • Default port: 3000 (configurable via .env)

Building for Production

npm run build

Creates an optimized production build in the dist/ directory with:

  • Minified JavaScript
  • Optimized and minified CSS
  • Bundled web workers
  • Copied static assets
  • Source maps (optional)

The build output is a single JavaScript file (default: main.min.js) ready for deployment.


Configuration

Environment Variables

Create a .env file in your project root to customize the build:

# Output filename for production build
OUTPUT_FILE_NAME=my-app.min.js

# Development server port
PORT=8080

Available Variables:

  • OUTPUT_FILE_NAME - Name of the bundled JavaScript file (default: main.min.js)
  • PORT - Development server port (default: 3000)
  • NODE_ENV - Set to production for production builds (automatically set by npm scripts)

Rspack Configuration

The rspack.config.js file is pre-configured but fully customizable. Key features:

Module Processing:

  • CSS: style-loadercss-loaderpostcss-loader (with cssnano)
  • JavaScript: Custom worker transformer → SWC loader
  • Source maps enabled in development

Optimization:

  • Single bundle output (no code splitting)
  • No separate runtime chunk
  • Automatic dist directory cleaning

Development Server:

  • Gzip compression
  • Cache-Control headers
  • Static file serving
  • Configurable port

Working with Custom Elements

Pochade-JS uses dataroom-js for creating custom HTML elements. It provides a clean API without Shadow DOM complexity.

Creating a Component

import DataroomElement from 'dataroom-js';

class MyComponent extends DataroomElement {
  async initialize() {
    // Create elements
    this.create('h1', { content: 'Hello World' });
    this.create('p', { 
      content: 'This is my component',
      class: 'description'
    });
    
    // Create a button with click handler
    const button = this.create('button', { content: 'Click Me' });
    button.addEventListener('click', () => {
      this.event('button-clicked', { timestamp: Date.now() });
    });
  }
}

// Register the element
customElements.define('my-component', MyComponent);

Using in HTML

<my-component></my-component>

Key DataroomElement Methods

create(type, attributes, target) - Create and append HTML elements

const div = this.create('div', { class: 'container' });
this.create('p', { content: 'Nested paragraph' }, div);

event(name, detail) - Emit custom events

this.event('data-loaded', { items: [...] });

on(name, callback) - Listen to events

this.on('data-loaded', (detail) => {
  console.log('Data:', detail.items);
});

once(name, callback) - Listen to events (fires once)

this.once('initialized', (detail) => {
  console.log('Component ready');
});

call(endpoint, body) - Make fetch requests with authentication

const data = await this.call('/api/users', { method: 'GET' });

getJSON(url) - Fetch and parse JSON

const config = await this.getJSON('/config.json');

log(message) - Conditional logging (requires verbose attribute)

this.log('Debug information');

Component Attributes

security-scheme - Authentication method for call()

  • localstorage (default) - Sends bearer token from localStorage
  • cookie - Uses browser cookies

call-timeout - Request timeout in milliseconds

<my-component call-timeout="5000"></my-component>

verbose - Enable debug logging

<my-component verbose="true"></my-component>

Lifecycle Methods

class MyComponent extends DataroomElement {
  async initialize() {
    // Called when component is added to DOM
    console.log('Component initialized');
  }
  
  async disconnect() {
    // Called when component is removed from DOM
    console.log('Component disconnected');
  }
}

Attribute Observation

Components automatically observe attribute changes:

class MyComponent extends DataroomElement {
  async initialize() {
    this.on('NODE-CHANGED', (detail) => {
      console.log(`${detail.attribute} changed to ${detail.newValue}`);
    });
  }
}

Working with Web Workers

Pochade-JS has first-class support for Web Workers with automatic bundling and transformation.

Creating a Web Worker

src/my-worker.js:

/**
 * My Web Worker
 * Handles background processing
 */

self.onmessage = (event) => {
  const { data } = event;
  
  // Do some heavy computation
  const result = processData(data);
  
  // Send result back to main thread
  self.postMessage({ result });
};

function processData(data) {
  // Your processing logic
  return data.map(item => item * 2);
}

Using a Web Worker

import DataroomElement from 'dataroom-js';

class WorkerComponent extends DataroomElement {
  async initialize() {
    // Create worker instance
    const worker = new Worker(
      new URL('./my-worker.js', import.meta.url)
    );
    
    // Listen for messages from worker
    worker.onmessage = (event) => {
      console.log('Worker result:', event.data.result);
      this.create('p', { 
        content: `Result: ${event.data.result}` 
      });
    };
    
    // Send data to worker
    worker.postMessage([1, 2, 3, 4, 5]);
  }
}

customElements.define('worker-component', WorkerComponent);

Worker Best Practices

  • Use workers for CPU-intensive tasks (data processing, calculations, parsing)
  • Keep worker files focused on a single responsibility
  • Use structured data for messages (objects, not primitives)
  • Handle errors in both main thread and worker
  • Terminate workers when no longer needed: worker.terminate()

Styling

Pochade-JS uses standard CSS without CSS-in-JS. Keep your styles organized and maintainable.

CSS Organization

Component-specific styles:

styles/
├── variables.css       # Global variables and theme
├── my-component.css    # Component styles
└── another-component.css

Import in index.css:

@import './styles/variables.css';
@import './styles/my-component.css';
@import './styles/another-component.css';

Using CSS Variables

styles/variables.css:

:root {
  --primary-color: #007bff;
  --secondary-color: #6c757d;
  --font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --spacing-unit: 8px;
}

Component styles:

my-component {
  font-family: var(--font-family);
  padding: calc(var(--spacing-unit) * 2);
}

my-component h1 {
  color: var(--primary-color);
}

No Shadow DOM

Pochade-JS components don't use Shadow DOM, so:

  • Global styles apply to components
  • Components can be styled from outside
  • No style encapsulation issues
  • Standard CSS cascade rules apply

Context Engineering for AI

Pochade-JS includes documentation files optimized for AI assistants (LLMs) to help with code generation.

Included Documentation

  • LLM.md - Complete guide for AI assistants on project structure and conventions
  • GEMINI.md - Gemini-specific instructions
  • WARP.md - Warp AI-specific instructions

Using with AI Assistants

When working with AI coding assistants (GitHub Copilot, Cursor, Warp AI, etc.), reference these files:

"Please read the LLM.md file and help me create a new component"

The documentation ensures AI assistants:

  • Use dataroom-js correctly
  • Follow project conventions (DockBlock comments, no Shadow DOM)
  • Create properly structured components
  • Organize CSS files correctly
  • Handle web workers appropriately

Publishing to npm

Your Pochade-JS project is pre-configured for npm publishing.

Before First Publish

  1. Update package.json:

    • Set unique package name
    • Update author information
    • Update repository, bugs, and homepage URLs
    • Set initial version (recommend 0.1.0)
  2. Test the build:

    npm run build
  3. Preview package contents:

    npm pack --dry-run

Publishing

# Login to npm (first time only)
npm login

# Publish the package
npm publish

The prepublishOnly script automatically runs the build before publishing.

Updating Versions

# Bug fixes: 1.0.0 → 1.0.1
npm version patch

# New features: 1.0.0 → 1.1.0
npm version minor

# Breaking changes: 1.0.0 → 2.0.0
npm version major

# Then publish
npm publish

What Gets Published

The package includes:

  • dist/ - Built production files
  • src/ - Source JavaScript files
  • styles/ - CSS files
  • index.js, index.css, index.html - Entry files
  • package.json and metadata

Development files (config, scripts, tests) are excluded via .npmignore.


Examples

Simple Counter Component

import DataroomElement from 'dataroom-js';

class CounterComponent extends DataroomElement {
  async initialize() {
    this.count = 0;
    
    this.create('h2', { content: 'Counter' });
    this.display = this.create('p', { content: '0' });
    
    const btnInc = this.create('button', { content: '+' });
    const btnDec = this.create('button', { content: '-' });
    
    btnInc.addEventListener('click', () => this.increment());
    btnDec.addEventListener('click', () => this.decrement());
  }
  
  increment() {
    this.count++;
    this.updateDisplay();
  }
  
  decrement() {
    this.count--;
    this.updateDisplay();
  }
  
  updateDisplay() {
    this.display.textContent = this.count;
    this.event('count-changed', { count: this.count });
  }
}

customElements.define('counter-component', CounterComponent);

Data Fetching Component

import DataroomElement from 'dataroom-js';

class UserListComponent extends DataroomElement {
  async initialize() {
    this.create('h2', { content: 'Users' });
    
    try {
      const users = await this.getJSON(
        'https://jsonplaceholder.typicode.com/users'
      );
      
      const list = this.create('ul');
      users.forEach(user => {
        this.create('li', { content: user.name }, list);
      });
      
      this.event('users-loaded', { count: users.length });
    } catch (error) {
      this.create('p', { 
        content: `Error: ${error.message}`,
        class: 'error'
      });
    }
  }
}

customElements.define('user-list', UserListComponent);

Worker-Powered Component

import DataroomElement from 'dataroom-js';

class ImageProcessorComponent extends DataroomElement {
  async initialize() {
    this.create('h2', { content: 'Image Processor' });
    
    const input = this.create('input', { type: 'file' });
    const button = this.create('button', { content: 'Process' });
    
    const worker = new Worker(
      new URL('./image-worker.js', import.meta.url)
    );
    
    button.addEventListener('click', async () => {
      const file = input.files[0];
      if (!file) return;
      
      const arrayBuffer = await file.arrayBuffer();
      worker.postMessage({ image: arrayBuffer });
    });
    
    worker.onmessage = (event) => {
      this.create('p', { 
        content: `Processed in ${event.data.time}ms` 
      });
      this.event('processing-complete', event.data);
    };
  }
}

customElements.define('image-processor', ImageProcessorComponent);

Troubleshooting

Port Already in Use

If port 3000 is already in use, create a .env file:

PORT=8080

Web Workers Not Working

Ensure you're using the correct import syntax:

// ✅ Correct
const worker = new Worker(new URL('./worker.js', import.meta.url));

// ❌ Incorrect
const worker = new Worker('./worker.js');

Assets Not Loading

  • Check that files are in the assets/ directory
  • Verify the directory exists and contains files
  • Reference assets from root: /image.png not ./assets/image.png

Custom Element Not Rendering

  • Ensure you've imported the component file
  • Check that customElements.define() is called
  • Verify the element name contains a hyphen (required by spec)
  • Check browser console for errors

Build Fails

  • Delete node_modules and package-lock.json
  • Run npm install again
  • Check Node.js version (requires Node 16+)

Requirements

  • Node.js 16 or higher
  • npm 7 or higher

Technologies


Philosophy

Pochade-JS embraces simplicity and vanilla web technologies:

  • No framework lock-in - Use standard Web APIs
  • No Shadow DOM - Keep styling simple and predictable
  • No CSS-in-JS - Separate concerns, use real CSS
  • No complex build chains - Fast, simple Rspack configuration
  • No unnecessary abstractions - Write JavaScript, not framework code

Perfect for developers who want modern tooling without framework overhead.


License

Unlicense (Public Domain)


Contributing

Issues and pull requests welcome at github.com/lnsy-dev/pochade-js


Credits

Created by LNSY

Write JS with passion! 🎨