Float64 Vertex
01. Obtaining vertex.js Vertex is a 1kloc SPA framework containing everything you need from React, Ractive-Load and jQuery while still being jQuery-compatible. vertex.js is a single, self-contained file with no build step and no dependencies. Download it from the Gist below and drop it wherever your project serves static assets. gist gist.githubusercontent.com/LukeB42/…/vertex.js Or fetch it from the command line: # save to your project's static directory curl -o static/vertex.js \ https://gist.githubusercontent.com/LukeB42/ef5b142325fc2bcd4915ba9b452f6230/raw/867cf609e8ec6bcb6700eda7f81c7c60e9ee01c9/vertex.js It ships as a UMD module, so it works equally as a plain <script> tag, a CommonJS require() , or an AMD define() .
02. Loading in the <head> Add a single <script> tag. Place it before any code that references Vertex or V$ . <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>My App</title> < src= "/static/vertex.js" ></ > <!-- If you also use jQuery, load it BEFORE vertex.js. vertex.js detects $ and leaves it untouched. --> <!-- <script src="/static/jquery.min.js"></script> --> </head> <body> <div id= "root" ></div> </body> </html> After loading, the following globals are available: Global Description Vertex Full namespace — all features live here V$ Shorthand DOM wrapper — always available $ Also set to the DOM wrapper only when jQuery is absent
03. Setting a templates directory Set Vertex.template.load.baseUri once at startup and every subsequent load() call that receives a relative path will automatically prepend it. Absolute URLs (starting with http:// , https:// , or / ) are always used as-is, so fully-qualified paths continue to work unchanged. // main.js — set the base once, then use short names everywhere Vertex.template.load.baseUri = "/static/templates/" ; // "user-card" resolves to /static/templates/user-card Vertex.template. ( "user-card" , { el: "#sidebar" , data: { name: "Alice" , role: "Engineer" } }). (instance => { instance. ( "change" , e => . ( "changed:" , e)); }); // Absolute paths bypass baseUri entirely Vertex.template. ( "/other/path/special.html" , { el: "#special" }); Vertex.template. ( "https://cdn.example.com/tmpl.html" , { el: "#remote" }); A template file at /static/templates/user-card.html is just a regular HTML fragment wrapped in a <template> tag: <!-- /static/templates/user-card.html --> < > <div class= "card" > <h2>{{name}}</h2> <p>{{role}}</p> {{ #if email}}<a href= "mailto:{{email}}" >{{email}}</a>{{ /if }} </div> </ > Note: If the file has no <template> tag, Vertex.template.load() uses the entire response body as the template string. Both forms work.
04. DOM layer — V$ / VQuery V$(selector) returns a chainable wrapper around a set of matched elements — identical in spirit to hn.js with a fuller jQuery surface. Every method returns this for chaining. Selecting & creating elements // CSS selector ( ".card" ). ( "active" ); // HTML creation const el = ( '<li class="item">Hello</li>' ); // Scoped query (2nd arg = context) ( "li" , "#my-list" ). ( function () { . ( this .textContent); }); // Document ready ( function () { . ( "DOM ready" ); }); Events — .on() / .off() / .trigger() // Direct event binding ( "button" ). ( "click" , function (e) { ( this ). ( "pressed" ); }); // Multiple events at once ( "input" ). ( "focus blur" , function () { ( this ). ( "active" ); }); // Event delegation (bubbles up from ".row" to "#table") ( "#table" ). ( "click" , ".row" , function (e) { . ( "row clicked:" , this .dataset.id); }); // Remove handler const = e => (e); ( "#btn" ). ( "click" , handler); ( "#btn" ). ( "click" , handler); // Custom event dispatch ( "#root" ). ( "app:ready" , { version: "1.0" }); Attributes, styles & values // .attr(name) → get // .attr(name, val) → set (chainable) // .css(prop) → get computed value // .css(prop, val) → set style property // .css({ prop: val }) → set multiple // .val() → get input value // .val(v) → set input value ( "img" ) . ( "alt" , "A scenic photo" ) . ({ borderRadius: "4px" , opacity: "0.9" }); const username = ( "#name-input" ). (); ( "#name-input" ). ( "" ). ( "placeholder" , "Enter name…" ); Content & traversal // Content ( "#output" ). ( "<strong>Done.</strong>" ); ( "#label" ). ( "Status: OK" ); ( "ul" ). ( "<li>New item</li>" ); ( "ul" ). ( "<li>First item</li>" ); // Traversal ( ".panel" ). ( "input" ). ( "" ); // clear all inputs inside .panel ( "li.active" ). (). ( "has-active" ); ( "li" ). (). ( "leader" ); ( "li" ). (2). (); ( "li" ). ( function (el, i) { return i % 2 === 0; }). ( "even" ); ( ".item" ). ( ".disabled" ). ( "click" , );
05. AJAX Vertex.ajax() wraps the Fetch API with a jQuery-shaped surface: success/error callbacks, dataType, content-type handling, and .done() / .fail() on the returned Promise. // Full options form Vertex. ({ url: "/api/tracks" , method: "GET" , data: { genre: "bass" , limit: 20 }, dataType: "json" , success: tracks => (tracks), error: err => . (err) }); // POST with JSON body Vertex. ({ url: "/api/session" , method: "POST" , contentType: "application/json" , data: { token: myToken }, success: session => (session) }); // Promise style Vertex. ({ url: "/api/ping" }) . (res => . ( "ok" , res)) . (err => . ( "failed" , err)); // Shorthand GET / POST Vertex. ( "/api/user" , data => . (data)); Vertex. ( "/api/save" , { title: "Mix A" }, res => . (res));
06. Fiber reconciler — createElement & render Vertex's reconciler follows the same fiber architecture described at pomb.us. The public API is intentionally React-compatible. createElement const { createElement: h, render, Fragment } = Vertex; // Host element ( "div" , { className: "card" }, ( "h2" , null , "Hello" ), ( "p" , null , "World" ) ) // Function component function ({ label, colour }) { return ( "span" , { style: { background: colour } }, label); } (Badge, { label: "Bass" , colour: "#c8ff00" }) // Fragment — renders children with no wrapper element (Fragment, null , ( "dt" , null , "BPM" ), ( "dd" , null , "174" ) ) render // Mount your root component once — Vertex handles all subsequent updates function () { return ( "div" , { className: "app" }, ( "h1" , null , "Vertex" ) ); } Vertex. ( (App, null ), document. ( "root" ) ); Lazy / async components // Vertex.lazy() follows the React.lazy Suspense protocol. // The component is fetched once; Vertex re-renders automatically. const HeavyChart = Vertex. (() => ( "/static/js/chart.js" )); function () { return (HeavyChart, { data: chartData }); }
07. Hooks All hooks follow React's rules: call them only at the top level of a function component, never inside conditionals or loops. useState function () { const [count, setCount] = Vertex. (0); return ( "div" , null , ( "span" , null , String(count)), ( "button" , { onClick: () => (c => c + 1) }, "+" ), ( "button" , { onClick: () => (0) }, "reset" ) ); } useReducer function (state, action) { switch (action.type) { case "add" : return { ...state, items: [...state.items, action.item] }; case "clear" : return { ...state, items: [] }; default : return state; } } function () { const [state, dispatch] = Vertex. (reducer, { items: [] }); return ( "ul" , null , ...state.items. (t => ( "li" , { key: t.id }, t.title)) ); } useEffect function ({ src }) { const audioRef = Vertex. ( null ); // Run once on mount — teardown on unmount Vertex. ( function () { const ctx = new (); audioRef.current = ctx; return () => ctx. (); // cleanup }, []); // Re-run when src changes Vertex. ( function () { if (audioRef.current) (audioRef.current, src); }, [src]); return ( "div" , { className: "player" }, "Playing: " + src); } useMemo & useCallback function ({ tracks, filter }) { // Only re-computed when tracks or filter changes const filtered = Vertex. ( () => tracks. (t => t.genre === filter), [tracks, filter] ); // Stable function reference — safe to pass to child components const handleClick = Vertex. ( t => . ( "selected:" , t.title), [] ); return ( "ul" , null , ...filtered. (t => ( "li" , { onClick: () => (t) }, t.title) ) ); } useRef function () { const inputRef = Vertex. ( null ); Vertex. (() => { if (inputRef.current) inputRef.current. (); }, []); return ( "input" , { ref: inputRef, // Vertex will write the DOM node here placeholder: "Type…" }); } createContext & useContext const ThemeCtx = Vertex. ( "dark" ); function () { return (ThemeCtx.Provider, { value: "dark" }, (Toolbar, null ) ); } function () { const theme = Vertex. (ThemeCtx); return ( "nav" , { className: "toolbar theme-" + theme }); }
08. Template engine — Vertex.template / Mustache The Vertex.template constructor takes an element target, a mustache template string, and a data object. It renders immediately and re-renders on every .set() or .update() . Basic usage const r = new Vertex. ({ el: "#app" , template: ` <h1>{{title}}</h1> <ul> {{#each tracks}} <li>{{@index}}. {{name}} — {{bpm}} BPM</li> {{/each}} </ul> ` , data: { title: "My Set" , tracks: [ { name: "Vortex" , bpm: 174 }, { name: "Subsonic" , bpm: 140 }, ] } }); // Update a single key — triggers re-render r. ( "title" , "Night Set" ); // Merge multiple keys at once r. ({ title: "Morning Set" , tracks: [] }); // Listen for data changes r. ( "change" , ({ keypath, value }) => { . (keypath, "→" , value); }); Mustache syntax reference Syntax Behaviour {{key}} HTML-escaped interpolation {{{key}}} Raw / unescaped HTML {{user.name}} Nested dot-path resolution {{#each items}} … {{/each}} Loop — keys from each item available directly; @index for position {{#if flag}} … {{/if}} Conditional block {{#if flag}} … {{else}} … {{/if}} Conditional with fallback Two-way binding Add data-bind="keypath" to any <input> inside a template and Vertex will keep the input and the data object in sync automatically: new Vertex. ({ el: "#form" , template: '<input data-bind="username" placeholder="Username">' , data: { username: "" }, oncomplete() { . ( "mounted, username =" , this . ( "username" )); } }); Vertex.template.load() — remote templates // Set base once at startup Vertex.template.load.baseUri = "/static/templates/" ; // Short name resolves to /static/templates/player.html Vertex.template. ( "player" , { el: "#player-container" , data: { track: "Vortex.wav" , playing: false } }). (instance => { instance. ( "change" , e => (e)); }); Want to understand how to safely mix Moustache templates and React components? Read the interop guide.
09. Hash router — Backbone style Vertex.Router is a singleton. Routes are matched against the URL fragment ( #/… ) using named parameters ( :name ) and splats ( *rest ). Singleton API const { Router } = Vertex; Router . ( "" , params => ()) . ( "projects" , params => ()) . ( "projects/:id" , params => (params.id)) . ( "files/*path" , params => (params.path)) . (); // begins listening; dispatches current fragment // Navigate programmatically Router. ( "projects/42" ); // sets #/projects/42 Router. ( "projects/42" , { trigger: true }); // + fire handler // Remove a route Router. ( "files/*path" ); // Stop / reset Router. (); Router. (); Class-based router (Backbone.Router syntax) const AppRouter = Vertex.RouterClass. ({ routes: { "" : "home" , "projects" : "projects" , "projects/:id" : "project" , "files/*path" : "file" }, home() { . ( "home" ); }, projects() { . ( "projects" ); }, project({ id }) { . ( "project" , id); }, file({ path }) { . ( "file" , path); } }); const router = new (); Vertex.Router. ();
... continue reading