NODERYX
FRAMEWORK v0.7.1

GETTING STARTED

BUILDING

PRODUCTION

DEVICES

REFERENCE

NODERYX / DOCS / BUILDING / 01
BUILDING / 01

Views & Noderframe

The template language that renders HTML on the server and compiles to native widgets on a device.

01

What a Noderframe view is

A .noderframe file describes a page as indented lines. Each line is one element: a tag, optional classes and id, optional attributes, and optional quoted text. Nesting is expressed by indentation, so there are no closing tags to mismatch.

resources/views/home.noderframe
main.cool-container header.cool-stack h1 "Welcome" p.cool-muted "Server-rendered, no client framework required." a.cool-btn href="/docs" "Read the documentation"
NOTE

The tree the parser produces knows nothing about HTML—that is what lets the same file compile to Android and iOS widgets.

02

Elements, classes, ids, and attributes

A leading tag name is optional; a line starting with a class produces a div. Attributes use name="value" and accept placeholders. Text is whatever remains, in quotes.

NODERFRAME
.cool-card → <div class="cool-card"> section#pricing.cool-stack → <section id="pricing" class="cool-stack"> img src="{{photo}}" alt="Team" width="800" height="600" a href="/posts/{{post.id}}" "{{post.title}}"
03

Placeholders are escaped for you

Every {{path}} is resolved against the render data and HTML-escaped by the compiler. A missing path renders as an empty string rather than the literal placeholder, so a partial data object never leaks template syntax onto the page.

server.js
app.get("/posts/:id", async ({ params, render }) => { const post = await Post.find(params.id); return render("posts/show", { post }); });
NOTE

{{csrfToken}} is available in every rendered view without passing it, and {{nonce}} can be passed from the context for inline scripts.

04

Conditions

A condition is a dotted path, optionally negated, optionally compared to a literal. Views decide what to show—not what to compute.

NODERFRAME
if user.name p "Welcome back, {{user.name}}." else if guest p "Browsing as a guest." else a.cool-btn href="/login" "Sign in" if !posts p.cool-muted "Nothing published yet." if status == "live" span.cool-badge "Live"
NOTE

Empty arrays are falsy, so if !posts is the empty-state check you want.

05

Loops

There are two loop forms because the choice matters on a phone. for renders inline; list becomes a virtualized FlatList in native builds. Both bind an optional index.

NODERFRAME
for tag in tags span.cool-badge "{{tag}}" for tag, position in tags span "{{position}}: {{tag}}" list post in posts PostCard post="{{post}}"
NOTE

Use list for data of unknown size; a screen containing a list is not wrapped in a scroll view, which is what keeps virtualization working.

06

Components

A capitalised name declares or uses a component. A prop that is exactly one placeholder passes the value itself, so objects and arrays survive; anything else is interpolated as text.

NODERFRAME
component PostCard(post, tone) article.cool-card h3 "{{post.title}}" p.cool-muted "{{post.excerpt}}" list post in posts PostCard post="{{post}}" tone="warm"
NOTE

Components compile to memoized native components, and a component that renders itself is reported instead of hanging.

07

Supported elements

The HTML renderer allows a deliberate subset. Anything outside it raises a compile error rather than emitting unchecked markup.

ALLOWED TAGS
html head body title meta link script main section article header footer nav div span h1 h2 h3 p a strong code form label input textarea select option button ul ol li img
NOTE

meta, link, input, and img are void elements and cannot contain children.

08

Rendering a view

render(view, data, status) resolves a view by path under resources/views, compiles it, and sends it as HTML. Controllers use the same call through this.render().

JAVASCRIPT
// route handler app.get("/pricing", ({ render }) => render("pricing", { plans })); // controller action return this.render("docs/page", { title, sections }, 200);
NOTE

In production, view discovery and parsed trees are cached; in development every request re-reads the file.

09

Error pages are views too

resources/views/errors/ holds 403, 404, 500, and 502. They are ordinary Noderframe files, so error pages match the rest of your design instead of looking like a framework default.

PROJECT
resources/views/errors/404.noderframe
10

Inline scripts and the nonce

The Content-Security-Policy carries a fresh nonce per request and permits no unsafe-inline. Pass the nonce to a view when you genuinely need an inline script; prefer the declarative data-noderyx attributes for common actions.

server.js
app.get("/", ({ render, nonce }) => render("home", { nonce }));
NOTE

script nonce="{{nonce}}" runs. An inline onclick does not, on purpose.

11

Compile views to static HTML

The build command renders every view once and writes plain HTML—useful for previews, static hosting, or checking what search engines receive.

TERMINAL
npm run build # resources/views → public/generated