It is possible:
No endless dependencies, no dev environment setup, no build step, no Web Components required, minimal boilerplate, minimal lock-in.
Raw HTML, CSS and JS have everything needed and are web standards, unlike custom syntaxes.
Key benefits:
- Bundle size proportional to the logic.
- Consistent hydration.
- No unnecessary breaking changes.
- Much less black-box reactivity.
- Lower risk of supply chain attacks.
- Native semantic accessibility.
- SEO-friendly and better indexing.
- No niches, transferable web standards learned.
This article is not:
A call to switch your framework or dismiss other techniques; after all, today's custom syntaxes may be tomorrow's standards. It also doesn't ignore the massive challenges, serious business and enterprise needs, or the real value of today's tools or methods.
Perspective:
Modern frontend fundamentals were analyzed from this viewpoint: having written code close to the metal (XDP, shared memory, C), delved into low-level systems (protocol flows, RAM interactions, Go), focused on optimizing core operations and identifying high-performance algorithms (BM25, HNSW, djb2), and compared the performance of various runtimes (PHP, Lua, Node, Wasm, Rust).
Simplified solution:
What was mentioned at the beginning (regarding what is possible) could be solved if most modern browsers or JavaScript engines updated to a recent ECMAScript specification with native Type Annotations and backward compatibility support.
But the proprietary or custom syntaxes that have been invented are not standard JS or TS; they require transpilers, optimizers, compilers, bundlers, and so on (understanding their inner workings and mechanisms is indeed fascinating).
Proposition:
There are several steps that can be bypassed between the scripting language, the framework, and development (covered up to here in this article, without requiring any updates to ES/TS specifications), and bundling, the interpreter, and the end user (which follow in an upcoming article, where additional tooling is optional).
Focus points:
- Point 1: JavaScript/TypeScript as the scripting language that does the actual work and creates the upper framework.
- Point 2: The framework, which helps avoid repetitive boilerplate, making the work with the scripting language easier and more efficient.
- Point 3: Developing interrelated or independent components using the framework to further abstract logic, reduce repetitive code, and reuse processes.
- Point 4: Preparation and bundling of frontend assets into optimized output for production.
Steps to bypass:
Note: links marked EXT, along with the GitHub repositories referenced throughout as POC or GIT, point to implementations shown as evidence the approach works rather than endorsements of third-party tools, all developed by this article's author.Between Point 1 and 2
-
Context:
For a framework to build dynamic, real-time, or interconnected frontends and UIs, it requires state, reactivity, components, routing, event handling, DOM manipulation, HTTP capabilities, and so on. To achieve this, ECMAScript and Web APIs natively provide these features since ES5, ES6, ES2016+ and DOM Level 1-4. -
Bypass:
Advanced usage of native primitives, baseline widely available features/functions, and APIs, such as the following.State & Reactivity:
Implemented in ReactiveEXT using ES6+.DOM, Events & Templating:
Implemented in DOMEXT, EventsEXT & HandlersEXT using ES6+.MutationObserver,IntersectionObserver,DocumentFragment,HTMLTemplateElement,TreeWalker,NodeFilter,Node,EventTarget,getComputedStyle,...Routing & Navigation:
Implemented in RoutingEXT using ES6+.Asynchronous & Orchestration:
Implemented in HTTPEXT & ComponentsEXT using ES6+.Promise,queueMicrotask,requestAnimationFrame,fetch,AbortController,Blob,URL,XMLHttpRequest,...
Between Point 2 and 3
- Context:
Recurring UI development problems are solved through well-organized, reusable components; efficient centralized or decentralized state management; synchronized, granular DOM updates; routing control without page reloads, coordinated with the UI; and conventions that facilitate interoperable collaboration.
That can be achieved seamlessly using: native HTML, in-memory JS-scoped data, batched event-based DOM reactivity, isolated and complete routing lifecycle interfaces, and standards-compliant HTML, CSS, and JS conventions with minimal guidelines. Well-organized, reusable components:
-
Specific context:
'Well-organized components' is ambiguous and subjective. Many favor precompiled or bundled components merged into a single asset (which optimizes network performance), yet the resulting bundle itself is not reusable on its own (typically due to minification and obfuscation); only the pre-bundled source components are.
There are also other factors to consider depending on the complexity of the application these components form, or even the organizational style, such as structuring them so that both AI models/agents and developer teams can leverage them in a consistent, coherent, and scalable manner.
The data consumed by components is ultimately more valuable than the components themselves. Furthermore, components can be fetched on demand via signed or authenticated requests whenever protecting source origins, intellectual property, or assets is required—completely decoupled from how they are organized or reused.
While Web Components are a solid solution, they are less flexible than raw HTML. For instance, scoping styles to a single component is not always desirable—often styles need to cascade globally or affect other components (such as wrappers for specific layout areas or residual elements). Standard HTML also has a lower learning curve and is inherently SEO-friendly, avoiding extra prerendering layers or the need to 'teach' web browsers, bots, and scrapers what elements actually mean. -
Bypass:
HTML natively provides traditional, broadly compatible mechanisms to load components, which is often sufficient for many scenarios, likescripttag attributesdefer,async,type="module"(deferred), as well as standard synchronous execution:When precise component synchronization is required (such as managing execution order or inter-component dependencies), patterns like "Shared Resource Resolution System with Barrier/Completion Conditions" can be implemented using ES6+:<script src="./main.sync.js"></script><script defer src="./html.complete.js"></script><script type="module" src="./html.complete.2.js"></script><script async src="./independent.load.js"></script><script async type="module" src="./independent.load.2.js"></script>Minimal implementation:
Coordinated asynchronous component execution, dependency chaining, and error propagation (view demonstration).Note that the previous minimal implementation resolves the asynchronous dependency synchronization problem, since each component typically requires logic (JS), markup (HTML), and styling (CSS), which can be loaded viaconst Queue = { state: false, load: [], pending: [], fail: [], unlockQueue: () => { Queue.state = false; if (Queue.load.length > 0 || Queue.pending.length > 0) { Queue.process(); } }, flushLoad: () => { const gates = Queue.load.splice(0); for (const loadFn of gates) { try { Queue.pending.push(loadFn()); } catch (e) { console.error('Component error:', e); } } }, execute: () => { const toProcess = Queue.pending.splice(0); return Promise.all(toProcess).then(() => { if (Queue.load.length > 0 || Queue.pending.length > 0) { Queue.flushLoad(); return Queue.execute(); } const fails = Queue.fail.splice(0); return fails.reduce((promise, failFn) => { return promise.then(() => failFn()).catch(Queue.unhandledFail); }, Promise.resolve()); }); }, process: () => { Queue.flushLoad(); if (!Queue.state && Queue.pending.length > 0) { Queue.state = true; queueMicrotask(() => { Queue.execute() .then(Queue.unlockQueue, (errorResponse) => { Queue.unlockQueue(); Queue.unhandledFail(errorResponse); }); }); } }, unhandledFail: (errorResponse) => { console.error('Unhandled Fail:', errorResponse); } }; class Component { constructor(name, fn) { this.name = name; const fails = []; this.fail = (failFn) => { fails.push(failFn); return this; }; let current = Promise.resolve(name); let error = false; let lastError = null; this.load = (loadFn) => { let openGate; const gate = new Promise((resolve) => { openGate = resolve; }); const currentFirst = (current = current .then((prevResult) => gate.then(() => prevResult)) .then((result) => { if (error) { return; } return loadFn(result); }) .catch((e) => { if (!error) { error = true; lastError = e; Queue.fail.push(() => { return fails.reduce( (promise, failFn) => promise.then((prevResult) => { return Promise.resolve(failFn(prevResult)).then((errorResult) => { return errorResult === undefined ? prevResult : errorResult; }); }), Promise.resolve(e) ); }); } })); Queue.load.push(() => { openGate(); return currentFirst; }); Queue.process(); return this; } if (typeof fn === 'function') { this.load(fn); } Object.defineProperty(this, 'ok', { get: () => current.then((result) => { if (error) { return Promise.reject(lastError); } return result; }), configurable: false }); } }import(),fetch(), orXMLHttpRequestinside ofnew Component()logic and then wrapped in aWeb Componentto inject the HTML and CSS via<template>and<style>withShadow DOMin modern JavaScript. Although this can be achieved just as well with ES6, see the additional patterns at the end of the following usage examples.Usage example:
Optionally, view the "Asynchronous Proxy-Based Synchronization" pattern used where components are declared in HTML index viaconst CompA = new Component('CompA', () => { console.log('1'); }) .load(() => { const CompB = new Component('CompB', () => { console.log('2'); throw new Error('Something went wrong.'); }); return CompB.ok; }); // This example uses async/await (ES2017+) for convenience, // but it is not required. const CompC = new Component('CompC', async () => { const req = await fetch('./test/data.json'); if (!req.ok) { throw new Error('Request failed: ' + req.status); } return await req.json(); }) .load((r) => { console.log(3); console.info('JSON Request:', r, '...'); return r; }) .fail((e) => { console.warn('CompC failed:', e); }); // Listen to component completion or errors via the .ok promise CompA.ok.then((r) => { console.info('Result A:', r); }) .catch((e) => { console.error('Error A:', e); }); CompC.ok.then((r) => { console.info('Result C:', r); }) .catch((e) => { console.error('Error C:', e); });data-*attributes, and automatically fetched on demand from self-hosted endpoints or CDNs, structured in dedicated directories (name/style.css,name/component.html,name/functionality.js), and automatically synchronized, orchestrated and injected by the prototype framework implemented in Components PrototypePOC (ES6+). Or explore advanced patterns with another implementation in ComponentsEXT (RC2, ES6+).
-
Specific context:
Efficient centralized or decentralized state management:
-
Specific context:
At its core, state management receives and integrates data, controls how it is read and written (optionally enforcing rules), and usually emits events to notify of mutations—excluding advanced paradigms like finite-state machines, the actor model, event sourcing, or others that imply declarative programming. -
Bypass:
Proxyprovides everything needed to establish a complete, predictable state lifecycle while avoiding unnecessary object recreation during mutations. Deeply observable state trees, lifecycle interceptors (onGet,onSet,onDelete), and reference caching can be implemented natively using ES6+:Minimal implementation:
Observable deep state tree with granular mutation hooks and identity preservation (view demonstration combined with synchronized DOM updates).Combining this previous minimal implementation withconst StateHandlers = (options, path, cache) => { return { get: (_data, property, receiver) => { const value = Reflect.get(_data, property, receiver); // Pass symbols through unmodified if (typeof property === 'symbol') { return value; } (!options.onGet || options.onGet({ type: 'get', value, path: path.concat(property) })); if (value !== null && typeof value === 'object') { return State(Object.assign({}, options, { data: value }), path.concat(property), cache); } return value; }, set: (_data, property, value, receiver) => { const oldValue = _data[property]; const success = Reflect.set(_data, property, value, receiver); if (success && oldValue !== value) { (!options.onSet || options.onSet({ type: 'set', oldValue, value, path: path.concat(property) })); } return success; }, deleteProperty: (_data, property) => { const exists = property in _data; const oldValue = _data[property]; const success = Reflect.deleteProperty(_data, property); if (exists && success) { (!options.onDelete || options.onDelete({ type: 'delete', oldValue, path: path.concat(property) })); } return success; } } }; function State(options = {}, path = [], cache = new WeakMap()) { // In-scope secure state with flexibility to use external objects (risk of external mutation) const data = options.data || Object.create(null); // Reuse existing proxy for identity preservation and to avoid memory leaks if (cache.has(data)) { return cache.get(data); } const proxy = new Proxy(data, StateHandlers(options, path, cache)); cache.set(data, proxy); return proxy; }CustomEvent,EventTarget, anddispatchEvent()in the state-change hooks natively achieves the Publisher/Subscriber pattern in modern JavaScript.Usage example:
Or explore other patterns like "Safe Auto-Vivification", with prototype pollution guards, array mutator tracking, and depth limits implementation in DXObjectGIT (RC3, ESM, ES6+), and reactivity store patterns implemented in ReactiveEXT (RC1, ES6+).const state = State({ onSet: (mutation) => { console.log(mutation.type, mutation.path, mutation.value, mutation.oldValue); }, onDelete: (mutation) => { console.log(mutation.type, mutation.path, mutation.value, mutation.oldValue); } }); state.name = 'John'; // set (1)["name"] John undefined delete state.name; // delete (1)["name"] undefined John
-
Specific context:
Synchronized, granular DOM updates:
-
Specific context:
This pattern is typically used to bind DOM nodes to the application's internal state variables, managing their lifecycle through mounting, unmounting, and state changes. Flawed implementations can quickly cause UI jank or severe memory leaks, particularly during high-frequency node mount and unmount cycles, requiring rigorous optimization. Granular updates demand precise reference tracking and automatic cleanup as elements leave the DOM tree.
Beyond basic state binding, it is also frequently used for integrating third-party imperative libraries, managing browser APIs (such as Observers), handling focus trapping and accessibility workflows, implementing complex interactions like click-outside detection and drag-and-drop, and executing imperative animations to bypass rendering overhead. -
Bypass:
MutationObservercan be used to scan the initial HTML, parse, and map nodes, as it does not rely onDOMContentLoadedand makes it possible to capture the creation phase of all nodes across thedocument. And with the necessary adjustments and optimizations, it can precisely control everything happening in the DOM asynchronously, yet synchronously for batched updates withqueueMicrotaskorrequestAnimationFramedepending on the type of update. This can be implemented natively (for HTML only) using ES6+:MutationObserver,requestAnimationFrame,queueMicrotask,Node,Reflect,WeakMap,WeakSet,Map,Set,...Minimal implementation:
Granular DOM node mapping, state binding, and content updates batching (view demonstration).Note that the previous minimal implementation is mainly intended for initial DOM parsing, mapping, and binding, followed by aconst UpdaterExcludedNodes = new Set([ '#document-fragment', 'SCRIPT', 'STYLE', 'LINK', 'NOSCRIPT', 'META', 'BASE', 'TITLE', 'TEMPLATE', 'SLOT', 'IFRAME', 'OBJECT', 'EMBED', 'SOURCE', 'TRACK', 'PORTAL', 'CANVAS', 'SVG', 'MATH', 'svg', 'math', 'semantics', 'annotation', 'annotation-xml', 'script', 'style', 'link', 'desc', 'title', 'metadata', 'defs', 'symbol', 'clipPath', 'mask', 'pattern', 'foreignObject', 'g', 'path', 'rect', 'circle', 'line', 'polygon', 'use', 'text', 'polyline', 'ellipse', 'image', 'tspan', 'linearGradient', 'radialGradient', 'stop', 'marker', 'filter', ]); function UpdaterStart(targetNode, handlers) { function Updater(mutations) { for (const mutation of mutations) { let target = mutation.target; switch (mutation.type) { case 'attributes': { if (!IncludedNodes.has(target)) { break; } const attributeName = mutation.attributeName; const nodeAttributes = IncludedAttrs.get(target); const oldValue = nodeAttributes[attributeName]; const newValue = target.getAttribute(attributeName); if (oldValue === newValue) { break; } if (oldValue === undefined) { nodeAttributes[attributeName] = newValue; handlers.attributes.added(target, attributeName, newValue, oldValue); } else if (newValue === null) { Reflect.deleteProperty(nodeAttributes, attributeName); handlers.attributes.removed(target, attributeName, newValue, oldValue); } else { nodeAttributes[attributeName] = newValue; handlers.attributes.modified(target, attributeName, newValue, oldValue); } break; } case 'characterData': { if (!IncludedNodes.has(target)) { break; } let oldValue = IncludedCommentsAndTexts.get(target); if (oldValue === target.data || !handlers.characterData[target.nodeType]) { break; } IncludedCommentsAndTexts.set(target, target.data); handlers.characterData[target.nodeType].modified(target, target.data, oldValue); break; } case 'childList': { if (UpdaterExcludedNodes.has(target.nodeName) || !IncludedNodes.has(target)) { break; } if (mutation.removedNodes.length) { ProcessNodes(target, mutation.removedNodes, 'removed'); } if (mutation.addedNodes.length) { ProcessNodes(target, mutation.addedNodes, 'added'); } break; } } } } function ProcessNodes(parentNode, nodes, action) { for (let i = 0; i < nodes.length; i++) { ProcessTree(parentNode, nodes[i], action); } } function ProcessTree(parentNode, rootNode, action) { const added = (action === 'added'); if (UpdaterExcludedNodes.has(rootNode.nodeName) || (added && IncludedNodes.get(rootNode) === parentNode) || (!added && !IncludedNodes.has(rootNode))) { return; } const type = rootNode.nodeType; switch (type) { case Node.COMMENT_NODE: case Node.TEXT_NODE: if (added) { IncludedNodes.set(rootNode, parentNode); IncludedCommentsAndTexts.set(rootNode, rootNode.data); handlers.childList[type][action](rootNode, parentNode, rootNode.data); } else { handlers.childList[type][action](rootNode, parentNode, IncludedCommentsAndTexts.get(rootNode)); IncludedCommentsAndTexts.delete(rootNode); IncludedNodes.delete(rootNode); } break; case Node.ELEMENT_NODE: const hasAttrs = handlers.attributes && rootNode.hasAttributes(); if (added) { IncludedNodes.set(rootNode, parentNode); handlers.childList[type][action](rootNode, parentNode); let attrs = Object.create(null); IncludedAttrs.set(rootNode, attrs); if (hasAttrs) { for (const attr of rootNode.attributes) { attrs[attr.name] = attr.value; handlers.attributes.added(rootNode, attr.name, attr.value, undefined); } } } try { let child = rootNode.firstChild; while (child) { const current = child.nextSibling; ProcessTree(rootNode, child, action); child = current; } } catch (e) { if (e instanceof RangeError) { throw new Error('Updater > ProcessTree: ' + e.message); } throw e; } if (!added) { if (hasAttrs) { for (const attr of rootNode.attributes) { handlers.attributes.removed(rootNode, attr.name, null, attr.value); } } IncludedAttrs.delete(rootNode); handlers.childList[type][action](rootNode, parentNode); IncludedNodes.delete(rootNode); } } } const IncludedCommentsAndTexts = new WeakMap(); const IncludedAttrs = new WeakMap(); const IncludedNodes = new WeakMap(); try { const ObserverConfig = Object.create(null); ObserverConfig.subtree = true; try { ObserverConfig.attributes = !!handlers.attributes; if (ObserverConfig.attributes) { if(!(handlers.attributes.added && handlers.attributes.removed && handlers.attributes.modified)) { throw new Error('attributes: added, removed, modified required functions.'); } } ObserverConfig.characterData = !!handlers.characterData; if (ObserverConfig.characterData) { if (!(handlers.characterData[Node.COMMENT_NODE].modified && handlers.characterData[Node.TEXT_NODE].modified)) { throw new Error('characterData: [Node.COMMENT_NODE].modified && [Node.TEXT_NODE].modified required functions.'); } } ObserverConfig.childList = !!handlers.childList; if (ObserverConfig.childList) { if (!(handlers.childList[Node.COMMENT_NODE].added && handlers.childList[Node.COMMENT_NODE].removed && handlers.childList[Node.TEXT_NODE].added && handlers.childList[Node.TEXT_NODE].removed && handlers.childList[Node.ELEMENT_NODE].added && handlers.childList[Node.ELEMENT_NODE].removed) ) { throw new Error('childList: [Node.ELEMENT_NODE], [Node.TEXT_NODE], [Node.COMMENT_NODE] each with added && removed required functions.'); } } } catch (e) { throw new Error('ObserverConfig: ' + e.message); } const Observer = new MutationObserver(Updater); Observer.observe(targetNode, ObserverConfig); if (targetNode.nodeType === Node.DOCUMENT_NODE) { IncludedNodes.set(targetNode, null); if (targetNode.documentElement) { ProcessTree(targetNode, targetNode.documentElement, 'added'); } return Observer; } ProcessTree(targetNode.parentNode, targetNode, 'added'); return Observer; } catch (e) { throw new Error('UpdaterStart > Observer > Initialization: ' + e.message); } }disconnect()call upon full application load. If handling tens of thousands of node-bound reactive variables, refer to these other demos to evaluate its viability: x100, x1000, x5000, x10000, x50000. Successfully tested up to x10000 without UI jank on entry-level and legacy hardware (e.g., Samsung A12 and AMD A8 APU notebooks).Usage example:
JavaScriptconst XVars_prefix = '${'; const XVars_postfix = '}'; const XVarsNamesRE = /[^a-z_0-9]/i; const XVarsNodes = new WeakMap(); const XVarsSuscriptors = new Map(); const XElementDataStr = 'data-x'; const XElements = new WeakSet(); const UpdaterObserver = UpdaterStart(document, { childList: { [Node.ELEMENT_NODE]: { added: (elementNode, parentNode) => { const hasX = elementNode.hasAttribute(XElementDataStr); if (hasX) { console.log('X ELEMENT ADDED:', elementNode); XElements.add(elementNode); } }, removed: (elementNode, parentNode) => { if (XElements.has(elementNode)) { XElements.delete(elementNode); console.log('X ELEMENT REMOVED:', elementNode); } } }, [Node.COMMENT_NODE]: { added: (commentNode, parentNode, newValue) => { // console.log('COMMENT ADD:', commentNode, parentNode, newValue); }, removed: (commentNode, parentNode, oldValue) => { // console.log('COMMENT DEL:', commentNode, parentNode, oldValue); } }, [Node.TEXT_NODE]: { added: (textNode, parentNode, newValue) => { if (newValue.trim() === '') { return; } const XParent = parentNode.closest('[' + XElementDataStr + ']'); if (XParent && XElements.has(XParent) && newValue.includes(XVars_prefix)) { const varsList = []; const varsTemplate = []; const vars = newValue .split(XVars_prefix) .reduce((array, str) => { if (str.includes(XVars_postfix)){ let varPos = str.indexOf(XVars_postfix) + 1; let varName = str.slice(0, varPos - 1); if (!XVarsNamesRE.test(varName)) { varsList.push(varName); varsTemplate.push(() => { return XState[varName]; }); varsTemplate.push(str.slice(varPos)); return array.concat(str); } } varsTemplate.push(str); return array.concat(str); }, []); if (varsList.length) { for (let varName of varsList) { if (!XVarsSuscriptors.has(varName)) { XVarsSuscriptors.set(varName, new Set()); } const xVarSuscriptor = XVarsSuscriptors.get(varName); if (!xVarSuscriptor.has(textNode)){ xVarSuscriptor.add(textNode); } if (!XVarsNodes.has(textNode)) { XVarsNodes.set(textNode, varsTemplate); } } console.log('X TEXT ADD:', varsList, varsTemplate); for (let varName of varsList) { XState[varName] = XState[varName] || ''; } } } }, removed: (textNode, parentNode, oldValue) => { // console.log('TEXT DEL:', textNode, parentNode, oldValue); for (const [varName, nodeSet] of XVarsSuscriptors.entries()) { nodeSet.delete(textNode); if (nodeSet.size === 0) { XVarsSuscriptors.delete(varName); } } } } } }); let XStateBatchState = false; let XStateBatch = new Set(); const XState = State({ onSet: (mutation) => { const xVarName = mutation.path[0]; if (XVarsSuscriptors.has(xVarName)) { const subs = XVarsSuscriptors.get(xVarName); if (subs) { for (const node of subs) { XStateBatch.add(node); } } } XStateBatchExecution(); }, onDelete: (mutation) => { } }); function XStateBatchExecution() { if (XStateBatchState) { return; } XStateBatchState = true; requestAnimationFrame(() => { XStateBatchState = false; for (const suscriptor of XStateBatch.values()) { if (XVarsNodes.has(suscriptor)) { const varValue = XVarsNodes.get(suscriptor).map((varPart) => (typeof varPart === 'function' ? varPart() : varPart)).join(''); switch (suscriptor.nodeType) { case Node.TEXT_NODE: suscriptor.data = varValue; break; } } } XStateBatch.clear(); }); }HTMLOr explore the "Declarative HTML-First DOM Pipelines & Lifecycle Orchestrator Pattern" implementation in HandlersEXT (ES6+), providing an event-delegated, middleware-enabled, clear abstraction between nodes and update logic, and classic direct handling of nodes with utilities implemented in DOMEXT (ES5+).<head> <!-- [Previous STATE Minimal Implementation JavaScript Code File] --> <script src="./test/State.js"></script> <!-- [Previous UPDATER Minimal Implementation JavaScript Code File] --> <script src="./test/Updater.js"></script> <!-- [Previous UPDATER Usage Example JavaScript Code] --> <script src="./test/Updater.usage.js"></script> <script> // TESTING REACTIVE VALUES setInterval(() => { XState['VALUE_1'] = Math.round(Math.random() * Date.now()); XState['VALUE_2'] = Math.round(Math.random() * Date.now()); XState['VALUE_3'] = Math.round(Math.random() * Date.now()); }, 567); </script> </head> <body> <div data-x> <p><b>Reactive value:</b> ${VALUE_1}, ${VALUE_2}</p> <p><b>Another reactive value:</b> ${VALUE_3}</p> </div> </body>
-
Specific context:
Routing control without page reloads, coordinated with the UI:
-
Specific context:
Core routing control mechanisms enable URL changes without full page reloads, typically by leveraging the History API and intercepting DOM anchor (<a>) tags to handle client-side navigation. Routes are defined via configuration objects, custom syntax, or file-system-based routing (transformed into SPA-compatible code at build time).
Additionally, these systems enable on-demand module loading, controlled visual transitions, route and data prefetching (triggered by user events or viewport visibility viaIntersectionObserver), and browser scroll restoration.
Nested route support prevents unnecessary parent re-renders while preserving logical application state and navigation history. Routing engines also provide navigation guards, synchronous or lazy per-route data fetching, optional caching, robust error handling, UI state restoration upon page reload, and accessibility (a11y) management across transitions. -
Bypass:
Through an agnostic, declarative routing engine that leverageswindow.location.hashalongside ID-based anchors for native scroll restoration, pure CSS transitions (transitionoranimation), inter-route middleware patterns, support for both synchronous and asynchronous loading depending on the handler, intelligent server-side caching, and standard HTML for accessibility (role,tabindex,aria-*), most routing requirements are effectively resolved.
Furthermore, UI restoration upon reload and cross-view state management can be handled programmatically through various approaches, such as conditional nested route chaining, user activity tracking withlocalStorageorsessionStoragepersistence, and declarative route configuration via JS or data-bound HTML—all of which can be implemented natively using ES6+ and standard Web APIs, including:Minimal implementation:
Prioritized route matching, sync/async middleware pipelines, History API orchestration, and native link interception (view demonstration)Note that the previous minimal implementation relies on regular expressions for route matching, which is well-suited for most SPAs. However, when registering over 250 routes, implementing route-matching patterns such as aclass Router { constructor() { this.routes = []; } _safeDecode(val) { if (typeof val !== 'string') { return val; } try { return decodeURIComponent(val); } catch (e) { return val; } } _flattenCallbacks(callbacks) { const flat = callbacks.reduce((array, fn) => { return array.concat(Array.isArray(fn) ? this._flattenCallbacks(fn) : [fn]); }, []); for (let i = 0; i < flat.length; i++) { if (typeof flat[i] !== 'function') { throw new TypeError('Middleware handlers must be functions'); } } return flat; } _register(pattern, callbacks, isMiddleware) { if (typeof pattern !== 'string') { throw new TypeError('Route pattern must be a string'); } const flatCallbacks = this._flattenCallbacks(callbacks); if (flatCallbacks.length === 0) { throw new Error('At least one middleware/handler is required'); } const cleanPattern = pattern.split(/[?#]/)[0].replace(/\/+/g, '/').replace(/^\/+|\/+$/g, ''); const normalizedPattern = '/' + cleanPattern; const segments = (cleanPattern === '' ? [] : cleanPattern.split('/')); const score = []; const paramNames = []; let wildcardCount = 0; let regexSource = '^'; let hasOptional = false; if (segments.length === 0) { regexSource += '\\/?$'; score.push(3); } else { for (let i = 0; i < segments.length; i++) { const seg = segments[i]; const isLast = i === segments.length - 1; const isOptional = seg.charCodeAt(0) === 58 && seg.endsWith('?'); if (hasOptional && !isOptional) { throw new Error(`Optional parameter in pattern "${pattern}" must be at the end of the route`); } if (seg === '*') { const name = wildcardCount === 0 ? 'wildcard' : `wildcard_${wildcardCount}`; paramNames.push(name); wildcardCount++; regexSource += isLast ? '\\/(.*)' : '\\/(.*?)'; score.push(1); } else if (isOptional) { hasOptional = true; const paramName = seg.slice(1, -1); if (!paramName) { throw new Error(`Invalid optional parameter format in pattern "${pattern}"`); } regexSource += '(?:\\/([^\\/]+))?'; paramNames.push(paramName); score.push(1.5); } else if (seg.charCodeAt(0) === 58) { const paramName = seg.slice(1); if (!paramName) { throw new Error(`Invalid parameter format in pattern "${pattern}"`); } regexSource += '\\/([^\\/]+)'; paramNames.push(paramName); score.push(2); } else { regexSource += '\\/' + seg.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); score.push(3); } } regexSource += '\\/?$'; } this.routes.push({ index: this.routes.length, isMiddleware: isMiddleware, pattern: normalizedPattern, regex: new RegExp(regexSource), paramNames: paramNames, score: score, callbacks: flatCallbacks }); return this; } use(...args) { if (args.length === 0) { throw new TypeError('use() requires at least one middleware handler'); } if (typeof args[0] === 'string') { const pattern = args[0]; const callbacks = args.slice(1); const clean = pattern.split(/[?#]/)[0].replace(/\/+/g, '/').replace(/^\/+|\/+$/g, ''); if (clean === '' || clean === '*') { return this._register('*', callbacks, true); } this._register(`/${clean}`, callbacks, true); return this._register(`/${clean}/*`, callbacks, true); } return this._register('*', args, true); } add(pattern, ...callbacks) { return this._register(pattern, callbacks, false); } find(targetPath) { const matches = []; for (let i = 0; i < this.routes.length; i++) { const route = this.routes[i]; const match = route.regex.exec(targetPath); if (match) { const params = {}; for (let j = 0; j < route.paramNames.length; j++) { const rawVal = match[j + 1]; params[route.paramNames[j]] = rawVal !== undefined ? this._safeDecode(rawVal) : undefined; } matches.push({ index: route.index, isMiddleware: route.isMiddleware, pattern: route.pattern, score: route.score, params: params, callbacks: route.callbacks }); } } return matches; } score(matches) { matches.sort((a, b) => { if (a.isMiddleware && !b.isMiddleware) { return -1; } if (!a.isMiddleware && b.isMiddleware) { return 1; } if (a.isMiddleware && b.isMiddleware) { return a.index - b.index; } const minLen = Math.min(a.score.length, b.score.length); for (let i = 0; i < minLen; i++) { if (b.score[i] !== a.score[i]) { return b.score[i] - a.score[i]; } } if (a.score.length !== b.score.length) { return a.score.length - b.score.length; } return a.index - b.index; }); return matches; } dispatch(rawPath, contextExtra = {}, options = {}) { if (typeof rawPath !== 'string') { throw new TypeError('The path must be a string'); } const cleanPath = '/' + rawPath.split(/[?#]/)[0].replace(/\/+/g, '/').replace(/^\/+|\/+$/g, ''); const targetPath = cleanPath === '/' ? '/' : cleanPath; const matches = this.score(this.find(targetPath)); const pipeline = []; for (let i = 0; i < matches.length; i++) { const match = matches[i]; for (let j = 0; j < match.callbacks.length; j++) { pipeline.push({ fn: match.callbacks[j], params: match.params, pattern: match.pattern }); } } const initialParams = (contextExtra && typeof contextExtra.params === 'object' && contextExtra.params !== null) ? Object.assign({}, contextExtra.params) : {}; const initialRoutePath = (contextExtra && contextExtra.routePath !== undefined) ? contextExtra.routePath : ''; const ctx = Object.assign({ pathname: cleanPath, rawPath: rawPath, params: Object.assign({}, initialParams), routePath: initialRoutePath }, contextExtra ); const isAsync = Boolean((options && options.async === true) || (contextExtra && contextExtra.async === true)); let lastIndex = -1; if (isAsync) { const runAsync = (index) => { if (index <= lastIndex) { return Promise.reject(new Error('next() called multiple times within the same middleware')); } lastIndex = index; if (index >= pipeline.length) { return Promise.resolve(); } const current = pipeline[index]; const prevParams = ctx.params; const prevRoutePath = ctx.routePath; ctx.params = Object.assign({}, current.params); ctx.routePath = current.pattern; try { const result = current.fn(ctx, () => runAsync(index + 1)); return Promise.resolve(result).then( (val) => { ctx.params = prevParams; ctx.routePath = prevRoutePath; return val; }, (e) => { ctx.params = prevParams; ctx.routePath = prevRoutePath; return Promise.reject(e); } ); } catch (e) { ctx.params = prevParams; ctx.routePath = prevRoutePath; return Promise.reject(e); } }; return runAsync(0).then( (finalVal) => { ctx.params = initialParams; ctx.routePath = initialRoutePath; return finalVal; }, (e) => { ctx.params = initialParams; ctx.routePath = initialRoutePath; return Promise.reject(e); } ); } const runSync = (index) => { if (index <= lastIndex) { throw new Error('next() called multiple times within the same middleware'); } lastIndex = index; if (index >= pipeline.length) { return; } const current = pipeline[index]; const prevParams = ctx.params; const prevRoutePath = ctx.routePath; ctx.params = Object.assign({}, current.params); ctx.routePath = current.pattern; try { return current.fn(ctx, () => runSync(index + 1)); } finally { ctx.params = prevParams; ctx.routePath = prevRoutePath; } }; try { return runSync(0); } finally { ctx.params = initialParams; ctx.routePath = initialRoutePath; } } } function RouterStart(options = {}) { const router = new Router(); const normalizeBase = (base) => { if (!base || typeof base !== 'string'){ return ''; } const clean = base.split(/[?#]/)[0].replace(/\/+/g, '/').replace(/^\/+|\/+$/g, ''); return clean ? '/' + clean : ''; }; let basePath = normalizeBase(options.basePath); const extractInternalPath = (fullPath) => { if (!fullPath || typeof fullPath !== 'string') return '/'; let path = fullPath; try { if (path.startsWith('http://') || path.startsWith('https://')) { const urlObj = new URL(path); path = urlObj.pathname + urlObj.search + urlObj.hash; } } catch (e) {} if (!path.startsWith('/')) { path = '/' + path; } if (basePath) { if (path === basePath || path === basePath + '/') { path = '/'; } else if (path.startsWith(basePath + '/') || path.startsWith(basePath + '?') || path.startsWith(basePath + '#')) { path = path.slice(basePath.length); } } return path.startsWith('/') ? path : '/' + path; }; const toBrowserUrl = (internalPath) => { const clean = internalPath.startsWith('/') ? internalPath : '/' + internalPath; if (!basePath){ return clean; } if (clean === basePath || clean.startsWith(basePath + '/') || clean.startsWith(basePath + '?') || clean.startsWith(basePath + '#')) { return clean; } return basePath + clean; }; const executeDispatch = (internalPath, extraContext = {}) => { let redirectedTo = null; const extendedContext = Object.assign({}, extraContext, { basePath: basePath, redirect: (targetUrl) => { redirectedTo = targetUrl; } }); const result = router.dispatch(internalPath, extendedContext, options); if (result && typeof result.then === 'function') { return result.then((val) => { if (redirectedTo) { return router.go(redirectedTo, true, extraContext); } return val; }); } if (redirectedTo) { return router.go(redirectedTo, true, extraContext); } return result; }; router.go = (url, replace = false, extraContext = {}) => { const internalPath = extractInternalPath(url); const browserUrl = toBrowserUrl(internalPath); if (replace) { window.history.replaceState({}, '', browserUrl); } else { window.history.pushState({}, '', browserUrl); } return executeDispatch(internalPath, extraContext); }; window.addEventListener('popstate', () => { const currentInternal = extractInternalPath(window.location.pathname + window.location.search + window.location.hash); executeDispatch(currentInternal); }); document.addEventListener('click', (e) => { const link = e.target.closest('a'); if ( link && link.hasAttribute('href') && link.target !== '_blank' && !link.hasAttribute('download') && link.origin === window.location.origin && e.button === 0 && !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey ) { const rawHref = link.getAttribute('href'); if (link.hasAttribute('data-router-exclude')) { return; } if (rawHref.startsWith('mailto:') || rawHref.startsWith('tel:') || rawHref.startsWith('javascript:')) { return; } e.preventDefault(); const targetPath = link.pathname + link.search + link.hash; router.go(targetPath); } }); router.listen = (customBase) => { if (typeof customBase === 'string') { basePath = normalizeBase(customBase); } const fullCurrent = window.location.pathname + window.location.search + window.location.hash; const internalPath = extractInternalPath(fullCurrent); const browserUrl = toBrowserUrl(internalPath); if (window.location.pathname + window.location.search !== browserUrl.split('#')[0]) { window.history.replaceState({}, '', browserUrl); } return executeDispatch(internalPath); }; return router; }Radix Tree (Trie)inside thefind()function and omitting properties likeroute.regexandregexSourcefrom_register()(or using alternative algorithms) is recommended to ensure maximum performance.Usage example:
JavaScriptconst app = RouterStart({ async: false/*true*/ }); app.use((ctx, next) => { console.log('Navigation event:', ctx.pathname); return next(); }); let isLogged = false; app.use('/dashboard', (ctx, next) => { if (!isLogged) { ctx.redirect('/login'); return; } return next(); }, (ctx, next) => { console.info('Access granted.'); return next(); } ); let viewBox; document.addEventListener('DOMContentLoaded', () => { viewBox = document.getElementById('view'); }); app.add('/', (ctx) => { viewBox.innerHTML = '<h2>Home</h2>'; }); app.add('/login', (ctx) => { viewBox.innerHTML = '<h2>Login (click Auth)</h2>'; }); app.add('/auth', (ctx) => { isLogged = !isLogged; viewBox.innerHTML = '<h2>Auth toggle: ' + (isLogged ? 'on' : 'off') + '</h2>'; }); app.add('/dashboard', (ctx) => { viewBox.innerHTML = '<h2>Dashboard</h2>'; }); const lastSlash = (window.location.pathname.lastIndexOf('/') + 1); const currentPathDirname = (lastSlash ? window.location.pathname.substring(0, lastSlash) : window.location.pathname); app.listen(currentPathDirname);HTMLOr view a more comprehensive implementation that includes error handling and query parameter parsing in RoutingEXT (ES6+).<head> <!-- [Previous ROUTER Minimal Implementation JavaScript Code File] --> <script src="./test/Router.js"></script> <!-- [Previous ROUTER Usage Example JavaScript Code] --> <script src="./test/Router.usage.js"></script> <script> // ROUTING TEST setTimeout(() => { app.go('/dashboard'); }, 4567); </script> </head> <body> <div> <p>Router links:</p> <ul> <li><a href="/">Home</a></li> <li><a href="/login">Login</a></li> <li><a href="/auth">Auth</a> (toggle)</li> <li><a href="/dashboard">Dashboard</a> (Auth click required first)</li> <li><a data-router-exclude href="#last-view">Anchor Link</a> ([data-router-exclude])</li> </ul> <p>Views:</p> <div id="view"> Start view. </div> </div> <br><br><br><br><br> <br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br> <br><br><br><br><br><br><br><br><br> <br><br><br><br><br> <div id="last-view"> Last view. </div> </body>
-
Specific context:
Conventions that facilitate interoperable collaboration:
-
Specific context:
Interoperable collaboration in the frontend is grounded in a set of architectural standards and technical contracts that enable different teams to integrate heterogeneous modules and frameworks within a single interface in a predictable and conflict-free manner. This model is realized through design systems based on Design Tokens, Headless components, and native Web Components, which ensure visual consistency and strict style isolation through Shadow DOM or CSS Modules, all centralized in living catalogs like Storybook.
At the runtime integration level, it relies on Micro-frontend architectures typically orchestrated by Module Federation, with defined lifecycle contracts and decoupled communication leveraging the URL, theBroadcast Channel API, andCustomEventsas neutral channels. This entire structure usually follows the Feature-Sliced Design (FSD) architectural methodology and strictly typed TypeScript contracts for Props and events, synchronizing reactivity through framework-agnostic state primitives (such as Signals or Nanostores), and maintaining quality via reusable UI packages along with integrated accessibility (a11y) and automated linting rules within unified repository strategies (like monorepos).
Furthermore, the durability of this interoperability is enforced through Semantic Versioning (SemVer) across internally published UI packages, allowing consumer teams to anticipate breaking changes without inspecting implementation details. Visual integrity is safeguarded through automated Visual Regression Testing using tools such as Chromatic or Playwright snapshots, which catches unintended style drift that type contracts and Storybook cataloging alone cannot guarantee.
Cross-team consistency extends into internationalization through a sharedi18nlayer, preventing each micro-frontend from changing translation logic independently. At the security boundary, third-party or untrusted Web Components are constrained through sandboxing techniques, including iframe isolation, restricted Custom Elements registries, and Shadow DOM encapsulation, to prevent global DOM or style pollution. Finally, organizational scalability is sustained through independent CI/CD pipelines per micro-frontend, enabling isolated deployment and rollback of a single module without redeploying the orchestrating environment. -
Bypass:
Across the aforementioned architectural stack, most of these underlying mechanisms operate decoupled from any frontend framework. At the Web Platform / Browser level, native web standards (Web Components, encapsulation via Shadow DOM, iframe sandboxing, and neutral channels such as the URL, theBroadcast Channel API, andCustomEvents) run directly in the browser without depending on any framework.
At the build layer, Module Federation, strict TypeScript contracts, and automated linters define interface boundaries and resolve dependencies before code reaches the rendering engine. This independence also extends to design and domain logic: JSON Design Tokens, Feature-Sliced Design (FSD) conventions, sharedi18nlogic, and in-memory reactive state handle design, translations, and business logic separately, leaving the frontend framework as a simple, interchangeable view-rendering layer.
Finally, the governance, testing, and delivery cycle (isolated catalogs in Storybook, pixel-level visual regression testing via Chromatic and Playwright, SemVer versioning, monorepos, and autonomous CI/CD pipelines) operates at the level of infrastructure, quality, and operations, ensuring scalability without tying the application's lifespan to the lifecycle of frontend libraries.
Conversely, the responsibilities that remain intrinsically bound to frontend frameworks must be handled directly within their component paradigms and rendering engines. This includes Headless components, which rely on framework-specific abstractions like Hooks, Composables or Services to encapsulate complex behavior, selection, and keyboard navigation while delegating markup to JSX or templates. Similarly, strictly typed TypeScript contracts govern unidirectional data flow through component Props and event callbacks across the virtual render tree.
At integration boundaries, micro-frontend runtime orchestration requires explicit lifecycle contracts (bootstrap(),mount(), andunmount()) to initialize dependencies, invoke root renderers (e.g.,createRoot().render()orcreateApp().mount()), and clean up listeners to prevent memory leaks.
Furthermore, reusable UI component packages (distributed as.tsx,.vue, or.sveltefiles) and CSS Modules depend on build-time tooling, such as bundlers and loaders, to generate and bind hashed class names into component templates.
Finally, bridging framework-agnostic state primitives (such as reactive state primitives) requires dedicated reactivity adapters (e.g.,useStore(),useSignal()) to trigger localized re-renders. Component-level accessibility workflows (dynamicaria-*bindings, modal focus trapping, and synthetic keyboard event listeners such asonKeyDownor@keydown) must likewise be programmed and executed directly within the component's internal state and lifecycle.
-
Specific context:
Conclusion
To achieve this native decoupling across all the previously mentioned layers (Components, State, DOM, Routing, and Interoperable Conventions) and replace custom abstractions, modern browsers provide a robust foundation of widely available Web Platform Baseline features:-
CSS
min()(2020, Safe)
Sets the smallest value from a comma-separated list of expressions.max()(2020, Safe)
Sets the largest value from a comma-separated list of expressions.clamp()(2020, Safe)
Clamps a flexible value between a defined minimum and maximum threshold.::part()(2020, Safe)
Styles exposed internal elements of a Shadow DOM tree from the host page.::slotted()(2020, Safe)
Styles elements projected inside a Shadow DOM slot from the component stylesheet.aspect-ratio(2021, Safe)
Sets a preferred aspect ratio (width/height) for an element box.:is()(2021, Safe)
Matches any selector in a list, adopting the highest specificity within the group.:where()(2021, Safe)
Matches any selector in a list while applying zero (0) specificity for easy overrides.@layer(2022, Safe)
Declares cascade layers to explicitly control rule precedence and style evaluation order.CSS Nesting(2023)
Enables native nesting of style rules inside one another without preprocessors.@container(2023)
Applies styles conditionally based on the size or query of an ancestor container.subgrid(2023)
Allows a grid item to inherit and align directly with its parent grid track definitions.color-mix()(2023)
Mixes two color values in a specified color space and percentage.:has()(2023)
Relational pseudo-class that styles a parent based on its descendant or sibling conditions.@starting-style(2024)
Defines initial property values to enable entry transitions when an element first renders.transition-behavior(2024)
Enables transitions for discrete properties such as display and content-visibility.
-
JavaScript & Web APIs
CustomEvent(2015, Safe)
Creates synthetic DOM events capable of transmitting payload data via the detail property.Intl(2015, Safe)
Provides language-sensitive string comparison, number, currency, and date/time formatting.import()(2020, Safe)
Dynamically and asynchronously loads ECMAScript modules on demand.ResizeObserver(2020, Safe)
Monitors and reports changes to the content or border-box dimensions of DOM elements.Clipboard API(2020, Safe)
Provides asynchronous system-level access to read and write clipboard data.navigator.clipboard.writeText()(2020, Safe)
Asynchronously writes plain text directly to the system clipboard.matchMedia()(with addEventListener: 2020, Safe)
Evaluates CSS media queries programmatically and listens for viewport/state changes.EventTarget(standalone constructor: 2021, Safe)
Constructible native base to implement custom event-driven publish/subscribe architectures.AbortController(event listener signal support: 2021, Safe)
Cancels async tasks (e.g., fetch) and cleans up event listeners via AbortSignal.structuredClone()(2022, Safe)
Creates deep copies of JavaScript objects, cyclic references, and complex data types.HTMLDialogElement.showModal()(2022, Safe)
Opens a <dialog> as a top-layer modal with native backdrop and focus containment.Array.toSorted()(2023)
Returns a new sorted copy of an array without mutating the original reference.Array.toReversed()(2023)
Returns a new reversed copy of an array without mutating the original reference.Intl.Segmenter(2024)
Performs locale-aware text segmentation into graphemes, words, or sentences.URL.canParse()(2024)
Returns a boolean indicating whether a string is a valid, parseable absolute/relative URL.navigator.clipboard.readText()(2024)
Asynchronously resolves with the textual contents of the system clipboard.
-
HTML & Web Components
Shadow DOM(v1 standard: 2020, Safe)
Encapsulates DOM trees and CSS scope inside self-contained web components and dom elements.Web Components(Custom Elements v1: 2020, Safe)
Standards-based APIs for registering and creating custom, reusable HTML tags.<dialog>(2022, Safe)
Native semantic HTML element for interactive dialogs, modals, and alerts.<img loading="lazy">(2022, Safe)
Defers image downloading until the element approaches the calculated viewport margin.inert(2023)
Removes an entire DOM subtree from user interaction, tab order, and the accessibility tree.Popover API(2025)
Provides native top-layer overlays with built-in light-dismiss and focus management.
Upcoming article:
Steps to bypass / Between Point 3 and 4:
Point 3 bridges development with bundling (Point 4) — covered in the upcoming article, since it depends on that transition.
Key points and bypasses covered in the next article are bundling (point 4), the interpreter (point 5), and the end user (point 6), where additional tooling is optional.
EXTAN EXTENSION of the main Runtime-Type-Driven Multiple Dispatch JS Framework implementation as a TypeScript compile-time alternative using ES3+, maintained by this article's author. POCPROOF OF CONCEPT, a small-scale demonstration designed to verify that a specific technical idea or theory is feasible and actually works in real life. GITGITHUB public repository of implementation shown as demonstration.