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 🙏

© 2024 – Pkg Stats / Ryan Hefner

vertstack

v2.6.1

Published

A lightweight framework for building modular, real-time web applications with a vertical architecture

Downloads

482

Readme

VertStack

Overview

VertStack is a lightweight framework for building modular, real-time web applications with a vertical architecture. It allows developers to create interconnected client-server modules that communicate seamlessly across different parts of the application. Think of it as a microservice architecture without having to manage servers.

Features

  • Modular architecture for easy scaling and maintenance
  • Real-time communication between client and server
  • Cross-module messaging system
  • Automatic session management
  • Easy-to-use API for both client and server-side code
  • Cross-channel communication
  • Local message handling for improved performance
  • Private messaging for secure communication
  • Static file serving for project directories
  • Custom index.html support with module placement
  • Template system for reusable HTML components
  • Automatic URL rewriting for relative paths
  • Iframe-based module rendering with automatic resizing
  • WebSocket connection with automatic reconnection

Getting Started

Prerequisites

  • Node.js (version 20 or higher recommended)
  • A modern web browser

Installation

  1. Clone the repository or copy the VertStack file into your project directory.
  2. Create a directory for each module of your application.

Project Structure

your-project/
├── VertStack
├── index.html (optional)
├── templates/               # Global templates directory
│   ├── header.html
│   └── footer.html
├── module1/
│   ├── client.js
│   ├── server.js
│   ├── header.html         # Module-specific template
│   └── public/ or dist/ (optional)
│       ├── index.html
│       └── ... (other static files)
├── module2/
│   ├── client.js
│   ├── server.js
│   └── public/ or dist/ (optional)
└── ...

Usage

Starting the Server

Run the following command from your project root:

npx vertstack --port=3456 module1 module2 ...

Replace module1, module2, etc., with the names of your module directories.

Local Installation and Usage

You can install VertStack locally in your project directory by using the --install flag. This process will:

  1. Download the current version of VertStack
  2. Create watch, serve, and serve-down scripts in your directory

To install:

npx vertstack --install [options] module1 module2 ...

Once installed, you can use the following scripts:

  • watch.cmd (Windows) or watch.sh (Unix): Starts the server with auto-restart on file changes
  • serve.cmd (Windows) or serve.sh (Unix): Runs the server in detached mode
  • serve-down.cmd (Windows) or serve-down.sh (Unix): Stops the detached server

The serve script automatically runs in detached mode and redirects output to a vertstack.logs file in your project's root directory.

Example usage:

# Install VertStack locally with custom port and modules
npx vertstack --install --port=3456 module1 module2

# Start the server with auto-restart (development mode)
./watch.cmd  # or ./watch.sh on Unix systems

# Start the server in detached mode
./serve.cmd  # or ./serve.sh on Unix systems

# Stop the detached server
./serve-down.cmd  # or ./serve-down.sh on Unix systems

After installation, you don't need to specify the modules again when running the scripts. The installation process saves your configuration for future use.

API Reference

bus(key, data) or bus(key, callback)

  • key (string): The event key. Use dot notation for namespacing.
  • data (any): The data to send with the event.
  • callback (function): A function to handle incoming events.

Special Keys

  • Use _ prefix for private messages (e.g., '_privateEvent')
  • Use * for project-wide events (e.g., '*.globalEvent')
  • Use # prefix for cross-channel communication (e.g., '#otherModule.event')
  • Use $ prefix for local messages (e.g., '$localEvent')

Server-Side Module Export

Export a function that takes bus and sessionId as parameters and optionally returns a cleanup function.

Static File Serving

VertStack automatically serves static files from the public/ or dist/ directory within each module. This is useful for serving HTML, CSS, JavaScript, and other assets specific to each module.

Usage

  1. Create a public/ or dist/ directory in your module folder.
  2. Place your static files (e.g., index.html, CSS, JavaScript) in this directory.
  3. These files will be automatically served when accessing your module's route.

Example structure:

module1/
├── server.js
├── client.js
└── public/
    ├── index.html
    ├── styles.css
    └── script.js

Custom Index.html

You can provide a custom index.html file in the root of your project to control the overall layout of your application.

Usage

  1. Create an index.html file in your project root.
  2. Use the special comment syntax <!-- @[MODULENAME] --> to indicate where each module should be rendered.

Example index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>My VertStack Application</title>
  </head>
  <body>
    <header>Welcome to My App</header>
    <main>
      <section id="module1">
        <!-- @module1 -->
      </section>
      <section id="module2">
        <!-- @module2 -->
      </section>
    </main>
    <footer>© 2024 My VertStack Application</footer>
  </body>
</html>

Template System

VertStack includes a powerful template system that allows you to create reusable HTML components and include them in your pages. Templates can be either global (shared across all modules) or module-specific.

Template Directory Structure

  • Global templates: Place in the root templates/ directory
  • Module-specific templates: Place directly in the module directory
your-project/
├── templates/
│   ├── header.html         # Global header template
│   ├── footer.html         # Global footer template
│   └── navigation.html     # Global navigation template
└── module1/
    ├── header.html         # Module-specific header (overrides global)
    └── sidebar.html        # Module-specific sidebar

Using Templates

Use the special comment syntax <!-- @@templateName --> to include templates in your HTML files.

<!DOCTYPE html>
<html>
  <head>
    <title>My VertStack Application</title>
  </head>
  <body>
    <!-- @@header -->
    <main>
      <div class="sidebar">
        <!-- @@sidebar -->
      </div>
      <div class="content">
        <!-- @module1 -->
      </div>
    </main>
    <!-- @@footer -->
  </body>
</html>

Template Features

  1. Template Hierarchy

    • Module-specific templates take precedence over global templates
    • Allows for module-level customization while maintaining global defaults
  2. Nested Templates

    • Templates can include other templates
    • Circular references are automatically detected and prevented
  3. Module Integration

    • Templates can include module references (<!-- @module -->)
    • All module references are collected and processed
  4. URL Rewriting

    • Relative URLs in templates are automatically rewritten
    • Ensures proper resource loading in both global and module contexts

Example Templates

  1. Global header template (templates/header.html):
<header class="site-header">
  <div class="logo">
    <!-- @@logo -->
  </div>
  <nav>
    <!-- @@navigation -->
  </nav>
  <!-- @userProfile -->
</header>
  1. Module-specific sidebar (module1/sidebar.html):
<div class="module-sidebar">
  <h3>Module Navigation</h3>
  <ul>
    <li><a href="/section1">Section 1</a></li>
    <li><a href="/section2">Section 2</a></li>
  </ul>
  <!-- @moduleNav -->
</div>
  1. Template with nested components (templates/page-layout.html):
<div class="page-container">
  <!-- @@header -->
  <div class="content-wrapper">
    <!-- @@sidebar -->
    <main>
      <!-- @content -->
    </main>
  </div>
  <!-- @@footer -->
</div>

Template Best Practices

  1. Modularity

    • Keep templates focused on specific components
    • Use nested templates for complex layouts
    • Avoid deep nesting (more than 3-4 levels)
  2. Naming Conventions

    • Use descriptive, component-based names
    • Consider using prefixes for different template types:
      • layout- for page layouts
      • component- for reusable components
      • section- for content sections
  3. Performance

    • Keep templates lightweight
    • Use module references (<!-- @module -->) for dynamic content
    • Consider caching strategies for frequently used templates
  4. Maintenance

    • Document template dependencies
    • Keep a consistent structure between global and module-specific templates
    • Regular review of template usage and necessity

URL Rewriting

VertStack automatically rewrites relative URLs within each module to ensure they work correctly when served as part of the larger application.

This feature works for:

  • HTML src and href attributes
  • CSS url() functions
  • Dynamically added elements and styles

No additional configuration is needed; this happens automatically for all modules.

Iframe Resizing

Modules are rendered within iframes, which are automatically resized to fit their content. This ensures that each module displays correctly regardless of its content size.

How it works

  1. Each module's content is wrapped in an iframe.
  2. A script monitors the content size of each iframe.
  3. The iframe's height is dynamically adjusted to match its content.

No additional configuration is required; this feature works automatically for all modules.

Examples

Examples can be found under the examples folder in Github.

Cross-Channel Communication

The # prefix allows you to send messages to specific channels (modules) from any other module. This is useful for inter-module communication without broadcasting to all modules. By default exported functions will subscribe to private and global scope.

Usage:

// Send a message to the 'userStats' module
bus("#userStats.update", { activeUsers: 10 });

// userStats exports a handler
export const update = (payload) => {
  // handle the event
};

Local Message Handling

The $ prefix is used for local messages that should not be sent over the network. This is useful for optimizing performance and keeping certain logic contained within either the client or server side.

Usage:

// Send a local message (client-side or server-side)
bus("$localEvent", { someData: "value" });
// or
bus("$local-event", { someData: "value" });

export const $localEvent = (payload) => {
  // Handle the local event
};

Vertical Message Handling

The _ prefix is used for server to client messages in a single module. If prefixed with _ only the server or client module will receive the message.

Usage:

// Send a vertical message
bus("_verticalMessage", { sensitiveData: "value" }, targetSessionId);

// Listen for vertical messages
export const _verticalMessage = (payload) => {
  // Handle the private message
  console.log("Received private message:", payload.data);
};

Server side Session subscription

As a server can handle multiple clients it is configured slightly different. It expects a default export that can handle new sessions.

export default (bus, sessionId, pageId) => {
  console.log("new user", sessionId, pageId);
  return () => {
    console.log("called when user leaves");
  };
};

Listening to all messages

In the event that you want to subscribe to all public messages for the session you can use the wildcard * prefix directly on the bus.

export default (bus, sessionId, pageId) => {
  bus("*", (payload) => {
    console.log("Received message", payload);
  });

  bus("*.targetedMessage", (payload) => {
    console.log(
      "Received message with .targetedMessage as subkek and the payload",
      payload
    );
  });
};

Proxy Support

VertStack supports proxying requests to specific ports for each module. This feature is useful when you need to integrate existing services or APIs with your VertStack application.

Usage

When starting the server, you can specify a proxy port for each module:

npx vertstack module1=8080 module2=8081

This will set up module1 to proxy requests to port 8080 and module2 to port 8081.

How it works

  • Requests to /{moduleName}/p/{path} will be proxied to the specified port.
  • The proxy will forward all headers and the request body.
  • This allows you to seamlessly integrate existing services with your VertStack application.

Example: If you have an existing API running on port 8080, you can integrate it with your VertStack module like this:

// In your client.js
async function fetchData() {
  const response = await fetch("/module1/p/api/data");
  const data = await response.json();
  // Process the data
}

This request will be proxied to http://localhost:8080/api/data.

Using pageId

The concept of pageId can be used to manage multiple instances of the same module across different pages or components of a user session.

The pageId is automatically generated and managed by VertStack. In your module code, you can access and use it as follows:

  1. In server-side code:
module.exports = function (bus, sessionId, pageId) {
  bus("someEvent", (payload) => {
    console.log(`Received event for page: ${pageId}`);
    // Handle the event
  });

  // Send a message to a specific page instance
  bus("specificPageEvent", data, sessionId, pageId);
};
  1. In client-side code:
// The pageId is automatically handled in the background
bus("someEvent", (payload) => {
  // This will only be called for events sent to this specific page instance
  console.log("Received event:", payload);
});

Troubleshooting

  • If modules aren't loading, ensure the directory names match the command-line arguments.
  • Check the console for WebSocket connection errors if real-time updates aren't working.
  • Verify that event keys are correctly namespaced to avoid conflicts between modules.
  • If static files are not being served, check that they are placed in the public/ or dist/ directory of the module.
  • For custom layouts, ensure your root index.html file uses the correct <!-- @[MODULENAME] --> syntax for module placement.
  • If templates aren't loading, check:
    • Template file names match the references exactly
    • Templates are in the correct directory (templates/ or module directory)
    • No circular references in nested templates
    • File permissions allow reading template files

Contributing

Contributions are welcome! Please submit pull requests or open issues for any bugs or feature requests.

License

This project is licensed under the MIT License.