Juris (JavaScript Unified Reactive Interface Solution)
repository·main·Indexed 42 days ago
https://github.com/jurisjs/jurisA browser-optimized, non-blocking reactive framework designed for high-performance, cross-platform applications. Juris features a zero-build, object-first architecture that supports progressive enhancement of existing HTML, a Virtual DOM convention, and a modular system including StateManager, HeadlessManager, and DOMEnhancer. It provides built-in support for reactive props, async operations, and integration with libraries like HTMX, Alpine.js, and Stimulus.
What's inside Juris
- Juris (JavaScript Unified Reactive Interface Solution) is a non-blocking reactive framework designed to eliminate build complexity for applications of all sizes. It focuses on progressive enhancement, allowing developers to add reactivity to existing DOM structures without a heavy build step.
Overview of @jurisjs/juris server features
mainThe
@jurisjs/jurisserver package is designed for high-performance, reactive, full-stack applications. Key capabilities include:Server-Side Rendering & Hydration
- Server-Side Rendering (SSR): Fast initial page loads.
- Smart Hydration: Efficient client-side takeover from SSR.
- String Renderer: Specialized component for HTML generation during SSR.
API & Routing
- RESTful API Routes: Built-in endpoints with automatic routing.
- Universal API Client: A fetch client that works seamlessly across both server and browser environments.
- CORS Support: Ready for cross-origin requests.
Performance & Runtime
- High Performance: Capable of 1,300+ req/s with ~9.6ms response times.
- Cross-Runtime Support: Compatible with Node.js (14+), Bun, and Deno.
- Compression: Built-in Gzip compression for production environments.
Review Juris limitations and ecosystem maturity
mainAs a newer framework (released 2024), Juris has specific characteristics to consider during adoption:
Current Limitations
- New Ecosystem: Limited availability of third-party components and tools.
- Small Community: Fewer tutorials and community resources compared to mature frameworks like React or Vue.
- Tooling: Developer tools are currently more basic than established frameworks.
- Learning Resources: Documentation and examples are still expanding.
- Testing Ecosystem: While Juris has superior built-in testing capabilities, the external testing patterns and tools are still developing.
- Design Systems: There are currently no established component libraries.
Maturity Context
Juris is currently in the 'New' stage of maturity with a 'Just Starting' community size, distinguishing it from mature ecosystems like React, Vue, or Angular.
Compare Juris with mainstream frameworks
mainJuris is an All-in-One Platform built on an Object-first reactive architecture. It is designed for universal deployment, AI collaboration, and progressive enhancement.
How it compares to other frameworks:
- React: Unlike React's component-based virtual DOM approach, Juris uses an object-first reactive model.
- Vue.js: While Vue is template-based, Juris focuses on a different reactive philosophy.
- Angular: Juris differs from Angular's TypeScript-first enterprise patterns.
- Svelte: Unlike Svelte's compile-time approach, Juris provides a runtime-capable platform.
- Alpine.js: While Alpine is HTML-first for minimal JS, Juris is a more comprehensive platform.
Optimize list rendering with the 'ignore' return value
mainWhen rendering lists, you can optimize DOM stability and performance using the
ignorepattern.If the length of a list remains unchanged, returning
"ignore"from your list rendering logic allows Juris to preserve the existing DOM structure. This enables individual items within the list to handle their own reactivity updates without triggering a full re-render of the list container.When to use Static vs Reactive children
mainChoosing the right type of
childrenproperty is critical for performance:Static Children (Array): Use when the structure of the list or component tree does not change. This is ideal for fixed layouts or lists where items handle their own internal reactivity.
- Example:
children: [{ Header: {} }, { MainContent: {} }]orchildren: users.map(...).
- Example:
Reactive Children (Function): Use only when the actual structure of the DOM tree must change based on state (e.g., conditional rendering of entire components based on user roles).
- Example:
children: () => userRole === 'admin' ? [{ AdminPanel: {} }] : [{ LoginForm: {} }].
- Example:
How the CSS Extractor's three-layer system works
mainThe CSS Extractor categorizes styles into three distinct layers to optimize performance:
- Static Styles: Extracted to native CSS classes for fast rendering (e.g.,
padding,display). - Reactive Styles: Preserved as JavaScript functions that run when state changes (e.g.,
color: () => getState('theme.color')). - Interactive States: Converted into event handlers (e.g.,
$hover,$active).
When you provide a style object, the processor analyzes the properties, generates CSS for the static layer, modifies props to include the generated
classNameand reactive styles, and sets up event handlers for interactive states.// Input Example: { style: { padding: '1rem', // Static color: () => getState('theme.color'), // Reactive $hover: { background: 'blue' } // Interactive } } // Output Example: { className: 'j-component-abc123', // CSS class for static styles style: { color: () => getState('theme.color') // Preserved reactive styles }, onmouseenter: (e) => { ... }, // Generated event handler onmouseleave: (e) => { ... } }- Static Styles: Extracted to native CSS classes for fast rendering (e.g.,
Create Headless Components
mainHeadless components allow you to define logic and APIs that can be consumed by other components without providing a UI. You define them in the
headlessComponentsproperty of theJurisconstructor. They can expose anapiobject for method calls and usehooks(likeonRegister) for setup logic. These are accessed viactx.<componentName>within other components.const app = new Juris({ headlessComponents: { geolocation: (props, ctx) => ({ api: { getCurrentPosition() { navigator.geolocation.getCurrentPosition( pos => ctx.setState('geo.position', pos.coords) ); } }, hooks: { onRegister: () => console.log('Geolocation service ready') } }) } }); // Usage in a component const LocationDisplay = (props, ctx) => ({ button: { text: 'Get Location', onclick: () => ctx.geolocation.getCurrentPosition() } });Achieving Temporal Independence with path-based reactivity
mainJuris achieves Temporal Independence by Default through an object-first architecture and path-based reactivity.
Unlike traditional frameworks where a change to a single state variable can trigger a cascade of re-renders across an entire component tree, Juris allows you to define reactivity at the property level using functions that call
context.getState(). This ensures that a component or sub-component only updates when the specific piece of state it is watching changes, eliminating unnecessary render waterfalls and the need for manual optimization patterns likeReact.memo.// Juris: Temporal independence through path-based reactivity const App = (props, context) => ({ div: { children: [ { UserProfile: { // Only updates when user data changes user: () => context.getState('user.profile') } }, { PostsList: { // Only updates when posts change posts: () => context.getState('posts.items') } }, { LoadingSpinner: { // Only updates when loading state changes loading: () => context.getState('ui.loading') } } ] } });Transform Object DOM into different formats using Transformation Engines
mainThe Object DOM is platform-agnostic and can be converted into various target formats (HTML, React, Vue, Native, etc.) using transformation engines. This allows a single component definition to be deployed across web, mobile, and desktop platforms.
Key transformation capabilities include:
- HTML: Converts the object structure into standard HTML strings.
- React: Converts the object into
React.createElementcalls, mapping properties likeonclicktoonClickand handling children viaReact.cloneElement. - Vue: Generates Vue component objects containing templates, data, methods, and computed properties.
- Native (Mobile): Maps web elements (like
div,span,button) to native components (likeView,Text,TouchableOpacityfor React Native; orContainer,Text,ElevatedButtonfor Flutter/SwiftUI).
// Example of a universal component definition const universalCard = { div: { className: 'card', style: { padding: '20px', borderRadius: '8px' }, children: [ { h3: { className: 'card-title', text: () => getTitle() } }, { button: { className: 'card-action', text: 'Action', onclick: () => handleAction() } } ] } }; // Deploying to different platforms const webOutput = juris.render(universalCard); const reactOutput = objectToReact(universalCard); const vueOutput = objectToVue(universalCard); const mobileOutput = objectToReactNative(universalCard);Implement Headless Component Architecture
mainJuris uses a headless component pattern to decouple business logic from UI implementation. This allows you to define pure logic components that manage state and provide an API, which can then be consumed by multiple different UI implementations (e.g., Mobile vs. Desktop).
To create a headless component:
- Define a function that returns an object containing an
api(methods to manipulate state) and optionallyhooks(lifecycle methods). - Use
context.getState(path)to retrieve state andcontext.setState(path, value)to update it. - Register the component using
juris.registerHeadlessComponent(name, component, options). - Access the logic in your UI components via
context.ComponentName.
// 1. Define pure logic const TodoLogic = (props, context) => ({ api: { addTodo: (text) => { const todos = context.getState('todos', []); const newTodo = { id: Date.now(), text, completed: false }; context.setState('todos', [...todos, newTodo]); }, // ... other methods } }); // 2. Register it juris.registerHeadlessComponent('TodoLogic', TodoLogic, { autoInit: true }); // 3. Use in UI const MobileUI = (props, context) => ({ div: { children: () => { const todos = context.getState('todos', []); const todoAPI = context.TodoLogic; // Access the registered API return [ { MobileInput: { onSubmit: todoAPI.addTodo } }, { MobileList: { todos } } ]; } } });- Define a function that returns an object containing an
Use interactive states for full reactivity
mainWhile standard CSS pseudo-selectors (
&:hover,&:active) are limited to static values or CSS variables, Juris Interactive States (prefixed with$) allow for full JavaScript reactivity. These are converted into event handlers, enabling complex logic and dynamic values during interactions.{ // Standard CSS Pseudo-selectors (static only) '&:hover': { background: 'blue', color: 'var(--hover-color)' } // Juris Interactive States (full reactivity) $hover: { background: () => getState('theme.hoverBg'), color: () => computeContrastColor(), transform: () => `scale(${getState('ui.scale')})` } }