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

@junojs/core

v0.4.9

Published

JunoJS Core Engine

Readme

🪐 JunoJS Core


⚡ Features

  • ⚛️ Native Web Components: Future-proof, standard-based components that work natively in the browser.
  • 🏝️ Island & Performance Architecture: Zero-JS server components ("use server") alongside highly-interactive client islands ("use client").
  • 🕹️ Vibe Coding: Clean, expressive HTML-First templates with powerful structural directives and zero runtime tension.
  • Signal Reactivity: Fine-grained, auto-tracking reactive primitives — signal(), computed(), and effect().
  • 🛠️ Decorator-driven TypeScript: Build features intuitively using @Component, @State, and Dependency Injection.
  • 🧩 Zero Virtual DOM: Hyper-fast, targeted reconciliation directly on the Light DOM for maximum speed.
  • 🛣️ Slot-Based Routing: Robust client-side navigation with the native <router-outlet> and automatic parameter synchronization.
  • 🚀 Built-in SSG & SSR: Automatic routing and static generation out of the box with the Juno CLI.
  • 🤖 AI-Native Context: Optimized for modern LLMs with dedicated system prompts for seamless code generation.

⚖️ How it Compares

JunoJS vs. Angular

Angular is a powerful enterprise framework, but it comes with significant boilerplate and a proprietary runtime (Zone.js). JunoJS provides a similar decorator-driven experience but stays native to the browser.

| Feature | Angular | JunoJS | | :--- | :--- | :--- | | Components | Proprietary Template Engine | Native Web Components (Standard) | | Reactivity | Zone.js (Dirty Checking) | Proxy-based / Signals (Fine-grained) | | Bundle Size | ~50KB+ (Minimum) | ~8KB (Core Runtime) | | Learning Curve | Steep (Modules, RxJS, etc.) | Low (HTML, CSS, TS Decorators) |

🔍 Code Comparison

@Component({
  selector: 'app-counter',
  template: `
    <button (click)="inc()">
      {{count}}
    </button>
  `
})
export class Counter {
  count = 0;
  inc() { this.count++; }
}
@Component({
  tag: 'juno-counter',
  template: `
    <button @click="count++">
      {count}
    </button>
  `
})
export class Counter {
  @State() count = 0;
}

JunoJS vs. Next.js

Next.js is the gold standard for React-based SSR. JunoJS takes the "Island" concept from Astro but integrates it into a unified, decorator-based framework that uses native components instead of a Virtual DOM.

| Feature | Next.js | JunoJS | | :--- | :--- | :--- | | Rendering | Full Page Hydration | Hybrid Islands (Selective Hydration) | | DOM | Virtual DOM (React) | Native Light DOM (Zero VDOM) | | Routing | File-system based | Slot-based + Declarative (<router-outlet>) | | Static Build | Complex "use client" boundaries | Seamless "use server" directives |

🔍 Code Comparison

Next.js (Server/Client split):

// page.tsx (Server Component)
export default function Page() {
  return <main><Counter /></main>;
}

// counter.tsx ("use client")
"use client";
export function Counter() { 
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

JunoJS (Unified approach):

"use server";
@Component({
  tag: "home-page",
  static: true,
  template: `
    <main>
      <h1>My Page</h1>
      <juno-counter></juno-counter> <!-- Interactive island -->
    </main>
  `
})
export class HomePage {}

🚀 Performance Benchmark

JunoJS is built for speed. By ditching the Virtual DOM and embracing Native Web Components, we achieve industry-leading performance metrics.

| Metric | React (Next.js) | Angular | JunoJS | | :--- | :--- | :--- | :--- | | Runtime Size (Gzipped) | ~45KB | ~60KB | ~8KB | | Reconciliation | Virtual DOM Diffing | Zone.js Dirty Checking | Targeted Proxy Updates | | DOM Interaction | Synthetic Events | Wrapper Elements | Native Light DOM | | Hydration Strategy | Full Page | Incremental | Selective (Islands) | | Startup TTI | Moderate | Slow | Blazing Fast |

💡 Why JunoJS is faster:

  1. Direct DOM Updates: When a @State variable changes, JunoJS updates exactly the affected DOM node. No tree diffing, no unnecessary re-renders of parent/child components.
  2. 0KB Static Pages: Pages composed purely of "use server" components ship zero JavaScript to the browser.
  3. Native Speed: By using the browser's built-in CustomElementRegistry, JunoJS leverages the underlying optimizations of modern JS engines (V8, JavaScriptCore).

📦 Quick Start

Get a high-performance app running in seconds:

npx juno new my-app --tailwind --ui
cd my-app && npm run dev

🕹️ The "Vibe"

JunoJS components feel like standard HTML, but with superpowers.

"use client";
import { Component, State, Action, bootstrap } from "@junojs/core";

@Component({
  tag: "juno-counter",
  template: `
    <div class="p-6 bg-zinc-900 rounded-2xl border border-white/10">
      <h1 class="text-3xl font-bold bg-gradient-to-r from-emerald-400 to-cyan-400 bg-clip-text text-transparent">
        Count: {count}
      </h1>
      <button @click="count++" class="mt-4 px-6 py-2 bg-emerald-500 hover:bg-emerald-400 transition-colors rounded-xl text-black font-medium">
        Increment
      </button>
    </div>
  `,
})
export class CounterComponent {
  @State() count = 0; 
}

bootstrap(CounterComponent);

### 🔍 Key Concepts
- **`@Component`**: Registers a standard Custom Element.
- **`@State()`**: A Proxy-based reactive variable. Mutating it (e.g., `this.count++`) triggers a microtask-batched DOM update.
- **`@click`**: Declarative event binding. Support for modifiers like `@click.stop` or `@keyup.enter` is built-in.
- **Interpolation**: `{count}` is live-bound. No manual DOM manipulation needed.

🏝️ Hybrid Rendering (Islands)

JunoJS allows you to mix static server-side content with interactive client islands seamlessly using the "use server" and "use client" directives.

  • "use server": Zero-JS. Executed at build time. Ideal for layout and data fetching.
  • "use client": Interactive. Hydrated on the client with full reactivity.
"use server";
@Component({
  tag: "home-page",
  static: true, 
  route: "/", 
  template: `
    <main>
      <h1>Static Header</h1>
      <ui-client-island></ui-client-island> <!-- Only this part loads JS -->
    </main>
  `
})
export class HomePage {}

### 📂 How it works
1. **Build Time**: The Juno CLI discovers `static: true` and runs a headless render.
2. **Hydration**: On the client, `"use client"` components are resurrected with full state, while `"use server"` parts remain static HTML.
3. **Zero-JS**: If a page only contains server components, **0KB of JunoJS** is shipped to the browser.

🛣️ Slot-Based Routing

JunoJS v0.4.0 introduces a robust, component-first routing system using the <router-outlet>. This replaces manual conditional rendering with a declarative slot-based architecture.

1. Register Routes

Register your routes in your application root using the component property (which refers to the component's tag name).

// main.ts
onInit() {
  const router = RouterService.instance;
  router.register([
    { path: '/', component: 'home-page', title: 'Home' },
    { path: '/profile/:id', component: 'profile-page', title: 'User Profile' }
  ]);
}

2. Define the Outlet

Place the <router-outlet></router-outlet> anywhere in your template. It will automatically listen to route changes and inject the matched component.

<!-- app.html -->
<nav>
  <button @click="Router.navigate('/')">Home</button>
  <button @click="Router.navigate('/profile/123')">Profile</button>
</nav>

<main>
  <router-outlet></router-outlet> <!-- Dynamic components are injected here -->
</main>

3. Parameters Synchronization

Route parameters (like :id) are automatically passed to your component as both Properties (camelCase) and Attributes (kebab-case).

@Component({ tag: 'profile-page' })
export class ProfilePage {
  @Input() id!: string; // Automatically populated from the route
}

4. Programmatic Navigation

The cleanest way to navigate programmatically is to inject the RouterService using the @Use decorator. This automatically resolves to the framework's singleton instance.

import { Component, Use, RouterService } from "@junojs/core";

@Component({ tag: 'user-list' })
export class UserList {
  @Use(RouterService) router!: RouterService;

  goToUser(id: string) {
    this.router.navigate(`/profile/${id}`); // Adds to history
  }

  forceGoToUser(id: string) {
    this.router.replace(`/profile/${id}`); // Replaces current history entry
  }

  goBack() {
    this.router.back();
  }
}

5. Route Guards

Protect routes using the canActivate() lifecycle hook or by passing guards in the route configuration.

export class AdminPage {
  async canActivate() {
    return AuthService.instance.isAdmin(); // Returns boolean or new path string
  }
}

🧬 The Reactivity Engine

JunoJS offers two ways to handle state. Choose the one that fits your architectural needs.

Quick Comparison

| Feature | @State() Decorator | signal() Primitive | | :--- | :--- | :--- | | Best For | Component-local UI state | Shared logic, Services, Global state | | Mechanism | Proxy-based (Class properties) | Atom-based (Functional) | | Syntax | this.count++ | count.value++ | | Tracking | Manual property binding | Automatic via .value access |


🟢 Local Reactivity (@State)

Perfect for internal component variables. Simple, class-based, and intuitive.

@State() name = "Juno";
// Mutate directly: this.name = "New Name";

🔵 Global Reactivity (Signals)

The powerhouse for services and cross-component communication.

Signals are fine-grained, auto-tracking reactive primitives.

1. Writable Signals

const count = signal(0);
count.value = 5; // Triggers subscribers

2. Computed Signals (Derivatives)

const total = computed(() => price.value * quantity.value);

3. Effects & Batching

effect(() => console.log(count.value)); // Runs on change

batch(() => {
  a.value = 10;
  b.value = 20; 
}); // Notifies once

4. Service Pattern (Cart Example)

Signals are ideal for global state. Here's how a Service and Component interact:

// cart.service.ts
export class CartService {
  items = signal<Product[]>([]);
  itemCount = computed(() => this.items.value.length);

  add(p: Product) {
    this.items.update(prev => [...prev, p]); // Immutable update triggers reactivity
  }
}

// cart-icon.component.ts
@Component({
  tag: "cart-icon",
  template: `<span>🛒 {cart.itemCount.value}</span>`
})
export class CartIcon {
  @Use(CartService) cart!: CartService;
}

🛠️ Core Decorators API

Power up your components with built-in decorators:

  • @Component: Register your Custom Web Component.
  • @Input: Two-way bindable props from HTML attributes.
  • @Use: Easy Dependency Injection for singleton services.
  • @Event: Custom bubbling events with EventEmitter.
  • @Validate: Built-in reactive validation logic.
  • @HostElement: Access the native HTMLElement directly.

🧩 Putting it all together

A robust component using the full power of JunoJS decorators:

@Component({
  tag: "user-profile",
  template: `
    <div class="card">
      <img src="{avatar}" />
      <h2>{username}</h2>
      <button @click="notify">Follow</button>
      <if condition="{isVerified}">
        <span class="badge">Verified</span>
      </if>
    </div>
  `
})
export class UserProfile {
  @Input() username = "Guest";
  @Input() avatar = "/default.png";
  @Input() isVerified = false;

  @Event("follow") followEvent!: EventEmitter<string>;
  @Use(LoggerService) logger!: LoggerService;

  notify() {
    this.logger.log(`Following ${this.username}`);
    this.followEvent.emit(this.username);
  }
}

🏗️ Template Logic

JunoJS uses an AST-based template parser for high-performance structural directives.

Conditional Rendering

<if condition="{isLoggedIn}">
  <user-dashboard></user-dashboard>
<else>
  <login-form></login-form>
</if>

List Rendering

Always provide a key for optimal DOM reconciliation.

<ul>
  <for each="{(item, i) in items}">
    <li key="{item.id}">{i}: {item.title}</li>
  </for>
</ul>

🔄 Lifecycle Hooks

Control your component's behavior at every stage:

| Hook | Timing | Best For | | :--- | :--- | :--- | | canActivate() | Before mount (Async) | Route guards, Auth checks. | | onInit() | Before first render (Async) | Data fetching, API calls. | | onRender(el) | After DOM sync | 3rd party libs (Chart.js, D3). | | onDestroy() | Unmount | Cleaning up timers/subscriptions. |


🤖 AI-Native Development

JunoJS is designed to be the best framework for AI-assisted coding. We provide specialized System Prompts to turn your LLM into a JunoJS expert.

  • 💎 Gemini.md: Optimized for Gemini 2.0/3.0 Pro.
  • Claude.md: Optimized for Claude 3.5/4.5 Sonnet.

[!TIP] Copy these files into your project root as .cursorrules or .clauderules to give your AI full framework context.


🔌 Tooling & Ecosystem

  • Juno CLI: Scaffolding, Dev Server (Vite), and SSG Builder.
  • Juno UI: Tailwind-powered, interactive component library.
  • VS Code Plugin: Syntax highlighting and template intellisense.

📜 License

MIT © Norbi Szobszlai & JunoJS Contributors