Juris: The Framework That Isn't a Framework
Pinoy Codie

Pinoy Codie @lynphp

About:

Joined:
Sep 2, 2023

Juris: The Framework That Isn't a Framework

Publish Date: Jun 29
14 3

Juris Home Page

How one JavaScript library solved the framework debate by transcending it entirely


The Great Framework Divide

For over a decade, the JavaScript community has been locked in an endless debate: frameworks versus vanilla JavaScript. On one side, framework advocates argue for productivity, structure, and modern development patterns. On the other, vanilla JavaScript purists champion performance, simplicity, and freedom from dependencies.

Both sides have valid points. Frameworks like React and Vue provide powerful abstractions but come with bundle size, learning curves, and architectural lock-in. Vanilla JavaScript offers ultimate control but lacks the convenience and optimization that modern applications demand.

What if this entire debate was based on a false dichotomy? What if there was a third way?

Enter Juris—a JavaScript solution that manages to be simultaneously a powerful framework and not a framework at all, depending on how you choose to use it.

The Paradox Explained

Juris achieves this seemingly impossible feat through architectural flexibility. Unlike traditional frameworks that force you into specific patterns and structures, Juris is designed as a collection of independent, composable tools that can work together as a framework or separately as utilities.

// As a simple DOM utility (not a framework)
const element = juris.objectToHtml({
    button: { 
        text: 'Click me', 
        onclick: () => alert('Hello!') 
    }
});
document.body.appendChild(element);

// As a full framework
const app = new Juris({
    components: { Header, Dashboard, Footer },
    services: { api, auth, analytics },
    states: { user: null, theme: 'dark' },
    layout: { App: {} }
});
app.render('#app');
Enter fullscreen mode Exit fullscreen mode

Both examples use the same Juris codebase, but the first feels like vanilla JavaScript with superpowers, while the second provides complete application architecture.

The Spectrum of Identity

Rather than forcing a binary choice, Juris operates on a spectrum:

Level 1: Pure Utility

// Just enhanced DOM creation
const juris = new Juris();
const widget = juris.objectToHtml({
    div: {
        text: 'Status: Loading...',
        style: { color: 'blue' }
    }
});
Enter fullscreen mode Exit fullscreen mode

At this level, Juris is indistinguishable from a utility library. No framework patterns, no architectural decisions—just better DOM manipulation with automatic async handling and memory management.

Level 2: Progressive Enhancement

// Enhance existing HTML without rewriting
juris.enhance('.price-display', () => ({
    text: () => `$${juris.getState('stockPrice', '---')}`,
    className: () => juris.getState('trend') === 'up' ? 'green' : 'red'
}));

// Update from anywhere
websocket.onmessage = (event) => {
    juris.setState('stockPrice', event.data.price);
    juris.setState('trend', event.data.trend);
};
Enter fullscreen mode Exit fullscreen mode

Here, Juris adds reactivity to existing applications without requiring architectural changes. Legacy PHP, WordPress, or static sites can gain modern capabilities incrementally.

Level 3: Component-Based Development

// Reusable components without full framework commitment
juris.registerComponent('UserCard', (props, context) => ({
    div: {
        className: 'user-card',
        children: [
            { img: { src: props.avatar } },
            { h3: { text: props.name } },
            { p: { text: props.email } }
        ]
    }
}));

const card = juris.objectToHtml({
    UserCard: { 
        name: 'John Doe', 
        email: 'john@example.com',
        avatar: '/avatars/john.jpg'
    }
});
Enter fullscreen mode Exit fullscreen mode

Components are available but optional. You can create reusable UI elements without committing to a complete component-based architecture.

Level 4: Full Framework

// Complete application framework
const tradingApp = new Juris({
    components: {
        PriceGrid: require('./components/PriceGrid'),
        OrderBook: require('./components/OrderBook'),
        Portfolio: require('./components/Portfolio')
    },
    services: {
        marketData: new MarketDataService(),
        trading: new TradingService(),
        analytics: new AnalyticsService()
    },
    states: {
        prices: {},
        portfolio: null,
        orders: []
    },
    layout: { TradingDashboard: {} }
});

tradingApp.render('#app');
Enter fullscreen mode Exit fullscreen mode

At this level, Juris provides complete application architecture with dependency injection, state management, and component orchestration—everything you'd expect from a modern framework.

The Technical Magic

How does Juris achieve this flexibility? The secret lies in its modular core architecture:

class Juris {
    constructor(config = {}) {
        // Each manager is independent and optional
        this.stateManager = new StateManager(config.states || {});
        this.componentManager = new ComponentManager(this);
        this.domRenderer = new DOMRenderer(this);
        this.domEnhancer = new DOMEnhancer(this);
        this.headlessManager = new HeadlessManager(this);
    }

    // Public APIs can be used independently
    objectToHtml(vnode) { return this.domRenderer.render(vnode); }
    enhance(selector, definition) { return this.domEnhancer.enhance(selector, definition); }
}
Enter fullscreen mode Exit fullscreen mode

Each subsystem can function independently. You're never forced to use all of them. The state manager works without components. The DOM renderer works without state management. The enhancement system works without either.

This modularity extends to performance. Whether you use Juris as a simple utility or a full framework, you get the same optimizations:

  • 9MB memory usage on complex trading dashboards
  • 40 FPS performance on async-heavy applications
  • Automatic memory management with zero-leak guarantee
  • Temporal independence for bulletproof async handling

Real-World Applications

The E-commerce Enhancement

// Existing WordPress site, add modern cart functionality
const cartManager = new Juris();

// Enhance existing "Add to Cart" buttons
cartManager.enhance('.add-to-cart', () => ({
    onclick: async (e) => {
        const productId = e.target.dataset.productId;
        await fetch('/cart/add', {
            method: 'POST',
            body: JSON.stringify({ productId })
        });

        // Update cart count reactively
        const cart = await fetch('/cart/count').then(r => r.json());
        cartManager.setState('cartCount', cart.count);
    }
}));

// Reactive cart counter
cartManager.enhance('.cart-count', () => ({
    text: () => cartManager.getState('cartCount', '0')
}));
Enter fullscreen mode Exit fullscreen mode

Identity: Enhancement tool, not a framework

The Trading Platform Revolution

// Replace React with Juris for performance
const tradingApp = new Juris({
    components: {
        PriceGrid, OrderBook, Portfolio, Charts
    },
    services: {
        marketData: new WebSocketService(),
        trading: new TradingAPI(),
        portfolio: new PortfolioService()
    },
    states: {
        prices: {},
        positions: {},
        orders: {},
        user: null
    },
    layout: { TradingDashboard: {} }
});

tradingApp.render('#trading-app');
Enter fullscreen mode Exit fullscreen mode

Identity: Full framework replacement

The Microservice Dashboard

// Just need async coordination for service health checks
const dashboard = new Juris();

const createServiceWidget = (serviceName) => dashboard.objectToHtml({
    div: {
        className: 'service-widget',
        children: [
            { h3: { text: serviceName } },
            { 
                div: {
                    text: fetch(`/health/${serviceName}`)
                        .then(r => r.json())
                        .then(data => `Status: ${data.status}`)
                        .catch(() => 'Status: Error'),
                    className: 'status-indicator'
                }
            }
        ]
    }
});

// Create widgets for 50 microservices without blocking UI
const widgets = services.map(createServiceWidget);
Enter fullscreen mode Exit fullscreen mode

Identity: Async coordination library

The Migration Path

Perhaps most importantly, Juris provides a natural migration path. You can start at any level and evolve your usage over time:

Week 1: Add Juris for better DOM creation

const element = juris.objectToHtml({ div: { text: 'Hello' } });
Enter fullscreen mode Exit fullscreen mode

Week 2: Add some reactive state

juris.setState('user', userData);
Enter fullscreen mode Exit fullscreen mode

Week 3: Create your first component

juris.registerComponent('UserWidget', userWidgetFunction);
Enter fullscreen mode Exit fullscreen mode

Month 2: Enhance existing forms

juris.enhance('.legacy-form', modernFormBehavior);
Enter fullscreen mode Exit fullscreen mode

Month 6: Full application architecture

const app = new Juris({ /* complete configuration */ });
Enter fullscreen mode Exit fullscreen mode

No rewrites necessary. No breaking changes. Your investment in Juris grows incrementally with your needs.

The End of Framework Wars

By transcending the framework/vanilla divide, Juris represents something new in the JavaScript ecosystem. It's neither a heavyweight framework that imposes architectural decisions nor a minimal library that leaves you to solve everything yourself.

Instead, it's a graduated system that scales from simple utilities to complete application frameworks, maintaining the same performance characteristics and API consistency throughout.

For framework enthusiasts, Juris provides all the power and structure they expect, with better performance than React or Vue. For vanilla JavaScript advocates, it offers enhanced capabilities without the commitment or overhead they typically reject.

The Developer Experience Revolution

What makes this particularly powerful is the developer experience. Framework haters can use Juris and barely notice it's there:

// Feels like vanilla JS with superpowers
const button = juris.objectToHtml({
    button: { text: 'Click me', onclick: handleClick }
});
document.body.appendChild(button);
Enter fullscreen mode Exit fullscreen mode

Framework lovers get a complete development environment:

// Full framework capabilities
const app = new Juris({
    components: { /* rich ecosystem */ },
    middleware: [ /* custom logic */ ],
    services: { /* dependency injection */ }
});
Enter fullscreen mode Exit fullscreen mode

Both groups are using the same underlying technology, benefiting from the same optimizations, and can collaborate on the same codebase.

Performance Without Compromise

Regardless of how you use Juris, you get industry-leading performance:

  • Memory efficiency: 9MB total usage on complex trading dashboards (vs 150-200MB for React equivalents)
  • Frame rate: Consistent 40 FPS on async-heavy applications
  • Bundle size: 50KB complete framework, or <1KB for utility-only usage
  • Startup time: Sub-3ms render for simple apps, sub-20ms for complex applications

These aren't trade-offs between different usage patterns—they're consistent across the entire spectrum.

The Future of JavaScript Development

Juris suggests a future where the framework debate becomes irrelevant. Instead of choosing between frameworks and vanilla JavaScript, developers can choose their level of abstraction based on project needs, team preferences, and timeline constraints.

A single technology that serves as:

  • A utility library for framework skeptics
  • A progressive enhancement tool for legacy applications
  • A component system for reusable UI development
  • A full framework for complex applications
  • A performance optimization layer for any use case

Conclusion: The Both/Neither Solution

Is Juris a framework? The answer is both yes and no, which is precisely the point.

For developers who want framework power, Juris delivers a complete application development platform with state management, component systems, dependency injection, and architectural patterns.

For developers who reject frameworks, Juris provides enhanced vanilla JavaScript capabilities with no commitment, no lock-in, and no architectural imposition.

The genius lies not in choosing one identity over another, but in making the choice unnecessary. By designing a system that works equally well as a framework or as a collection of utilities, Juris ends the framework war not through victory, but through transcendence.

In a world where developers are forced to choose between power and simplicity, control and convenience, performance and productivity—Juris simply asks: "Why choose?"

The future of JavaScript development might not be about better frameworks or better vanilla JavaScript. It might be about solutions that make the distinction irrelevant.

And in that future, the question isn't whether to use a framework or not. It's whether to use Juris a little, or a lot.


Juris represents a fundamental shift in how we think about JavaScript development tools. By refusing to be constrained by traditional categories, it opens up new possibilities for how we build applications, enhance existing systems, and evolve our development practices over time.

Website: https://jurisjs.com/
GitHub: https://github.com/jurisjs/juris
NPM: https://www.npmjs.com/package/juris
Codepen: https://codepen.io/jurisauthor
Online Testing: https://jurisjs.com/tests/juris_pure_test_interface.html

Comments 3 total

  • artydev
    artydevJun 29, 2025

    Your test site is just a gift, thank you very much :-)

    • Pinoy Codie
      Pinoy CodieJun 29, 2025

      Welcome and I appreciate the positive response; it helps a lot to keep going.

  • beernutz
    beernutzJul 8, 2025

    This looks VERY interesting! Thank you!

Add comment