Skip to content

Commit bb7078a

Browse files
authored
Merge pull request #72 from koculu/performance-refactor
Performance + Runtime Simplification: keyed `r-for` diff as default, binder/directive cleanup, benchmark/docs upgrades
2 parents 36f157c + 7caf22f commit bb7078a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+2658
-1081
lines changed

README.md

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@
22

33
# Regor
44

5-
Regor is a powerful UI framework designed to streamline the development of HTML5-based applications for both web and desktop environments. With a template syntax that closely follows Vue.js, transitioning from VueJS to Regor is seamless for developers familiar with Vue.
5+
Regor is a runtime-first UI framework for teams that want direct DOM control, strong TypeScript ergonomics, and precise reactivity behavior without being forced into a Virtual DOM architecture.
6+
7+
Its template syntax is familiar to Vue users (`r-if`, `r-model`, `r-for`, `r-bind`), but its runtime model is intentionally different: Regor is built for progressive enhancement, mixed-rendering environments, and incremental adoption.
68

79
### [![Published on npm](https://img.shields.io/npm/v/regor.svg)](https://www.npmjs.com/package/regor)
810

911
[**`Try Regor Online`**](https://stackblitz.com/edit/regor-sample-1?file=index.ts)
1012

1113
## Key Features
1214

13-
- **Simplicity:** Develop UIs without a Virtual DOM for a more straightforward implementation and easier debugging.
14-
- **TypeScript:** Enjoy native TypeScript support without workarounds.
15-
- **No Build Step Required:** Define components in TypeScript using tagged string templates, no build step needed.
15+
- **No VDOM Layer:** Bind directly to real DOM for transparent runtime behavior and straightforward debugging.
16+
- **TypeScript-Native:** Use standard TypeScript interfaces, classes, and generics without framework-specific file formats.
17+
- **No Build Step Required:** Define components in TypeScript using tagged string templates with npm, CDN ESM, or global build workflows.
1618
- **Secure Evaluation:** Regor's secure JavaScript VM ensures safe runtime compilation. You can enable security policy in your page without removing runtime compilation support.
1719

1820
```html
@@ -22,9 +24,9 @@ Regor is a powerful UI framework designed to streamline the development of HTML5
2224
/>
2325
```
2426

25-
- **Flexible Reactivity:** Empowering developers with a highly flexible reactivity system.
26-
- **Non-JS SSR:** Bind to the existing DOM without removing already mounted HTML elements, suitable for non-JavaScript server-side rendering.
27-
- **Reentrance:** Regor supports multiple mountings in the previously mounted area using the same or different app contexts. This enables creating and mounting new directives dynamically.
27+
- **Flexible Reactivity:** Combine `ref`, `sref`, `batch`, `pause`, `resume`, and `entangle` for explicit state orchestration.
28+
- **Static-First + Islands:** Bind to existing DOM without removing server-rendered HTML, ideal for progressive enhancement.
29+
- **Reentrance:** Mount multiple times in already-mounted regions with same or different app contexts.
2830
- **Compatibility:** Rendered pages are designed for seamless integration with other libraries manipulating the DOM.
2931

3032
## Documentation
@@ -72,16 +74,13 @@ const template = html`<button @click="count++">
7274

7375
const props = ['message']
7476

75-
const myComponent = createComponent<MyComponent>(
76-
template,
77-
{
78-
context: (head) => ({
79-
message: head.props.message,
80-
count: ref(0),
81-
}),
82-
props,
83-
},
84-
)
77+
const myComponent = createComponent<MyComponent>(template, {
78+
context: (head) => ({
79+
message: head.props.message,
80+
count: ref(0),
81+
}),
82+
props,
83+
})
8584

8685
createApp({
8786
components: { myComponent },
@@ -161,7 +160,31 @@ or
161160

162161
## Comparison with VueJs
163162

164-
Regor shares core functionality with VueJs but differs in implementation, TypeScript support, template evaluation, reactivity, server-side rendering support, compatibility.
163+
Regor is openly inspired by Vue’s concepts (even adopting a similar directive syntax like r-if / r-model instead of v-if / v-model), but it fundamentally diverges in its implementation. It prioritizes runtime flexibility, build-less environments, and strict TypeScript integration over the Virtual DOM (VDOM) paradigm.
164+
165+
### Architecture and rendering model
166+
167+
- **Vue:** Uses a Virtual DOM. This provides excellent performance for highly dynamic Single Page Applications (SPAs) because Vue calculates diffs in memory before updating the browser. However, it usually requires a compilation step to optimize templates, and hydrating existing server-rendered HTML can be notoriously strict (hydration mismatches).
168+
- **Regor:** Ditches the VDOM entirely. It binds directly to the actual DOM. Regor explicitly supports Static-first + dynamic islands and "Reentrance." You can mount an application multiple times over already-mounted regions or existing server-rendered HTML without destroying the elements.
169+
- **Verdict:** Regor is significantly more flexible for integrating into existing applications, multi-page applications (MPAs), or legacy backends.
170+
171+
### Runtime and deployment model
172+
173+
- **Vue:** Commonly paired with a build pipeline for SFCs and tooling depth.
174+
- **Regor:** Designed to require no build step. You can write standard TypeScript using tagged string templates (e.g., `html` tags for templates) and it will evaluate at runtime. Crucially, Regor features a Secure JavaScript VM for runtime compilation that adheres to strict Content Security Policies (CSP)—a common pain point when using Vue's runtime compiler in enterprise environments.
175+
- **Verdict:** Regor wins in deployment flexibility and zero-config setups. It respects modern security policies out of the box without demanding a bundler.
176+
177+
### Reactivity control model
178+
179+
- **Vue:** Uses ES6 Proxies for a highly automated, "magical" reactivity system. You update an object, and Vue figures out what to re-render. However, this magic can sometimes abstract away performance bottlenecks, leading to over-rendering if you aren't careful with deep reactivity.
180+
- **Regor:** Provides fine-tuned, manual control. It offers `ref` (deep reactivity) and `sref` (simple/shallow reactivity without nested observation). Furthermore, Regor provides advanced control APIs like `pause()` and `resume()` to stop a ref's auto-triggers, `entangle()` to sync two refs effortlessly, and `batch()` for precise state grouping.
181+
- **Verdict:** Vue's reactivity is easier for beginners.. Regor’s reactivity is more flexible and transparent, giving engineers exact tools to orchestrate update semantics and prevent unwanted DOM paints.
182+
183+
### TypeScript ergonomics
184+
185+
- **Vue:** TypeScript support in Vue has improved massively, but it still relies on heavy IDE plugins (Volar) and specialized compilers (vue-tsc) to understand .vue files. The separation between the `<template>` and `<script>` requires tooling to bridge the gap.
186+
- **Regor:** Offers native TypeScript support without workarounds. Because components and templates are defined using standard TypeScript functions, class-based contexts, and `ComponentHead<T>`, standard TypeScript compilers and IDEs understand 100% of the code immediately.
187+
- **Verdict:** Regor offers a purer, higher-quality TypeScript experience. It leverages the language itself rather than relying on framework-specific compiler magic to provide type safety.
165188

166189
## Supported Directives
167190

benchmarks/index.html

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
--fg: #e5e7eb;
1212
--muted: #9ca3af;
1313
--accent: #22c55e;
14+
--winner: #4ade80;
1415
}
1516
body {
1617
margin: 0;
@@ -60,6 +61,17 @@
6061
padding: 8px;
6162
text-align: left;
6263
}
64+
#scenario-results tbody tr.scenario-pair-a {
65+
background: #11243a;
66+
}
67+
#scenario-results tbody tr.scenario-pair-b {
68+
background: #162f4b;
69+
}
70+
#results .winner-metric,
71+
#scenario-results .winner-metric {
72+
color: var(--winner);
73+
font-weight: 700;
74+
}
6375
.roots {
6476
display: grid;
6577
grid-template-columns: 1fr 1fr;
@@ -92,6 +104,35 @@ <h1>DOM Benchmark: Regor vs Vue (latest)</h1>
92104
<button id="run-regor">Run Regor</button>
93105
<button id="run-vue">Run Vue</button>
94106
<button id="run">Run Both</button>
107+
<label style="margin-left: 12px; color: var(--muted)">
108+
Row count
109+
<select id="row-count">
110+
<option value="500" selected>500</option>
111+
<option value="1000">1000</option>
112+
<option value="2000">2000</option>
113+
<option value="5000">5000</option>
114+
</select>
115+
</label>
116+
<label style="margin-left: 12px; color: var(--muted)">
117+
Warmups
118+
<select id="warmup-runs">
119+
<option value="0">0</option>
120+
<option value="2">2</option>
121+
<option value="4">4</option>
122+
<option value="6" selected>6</option>
123+
<option value="10">10</option>
124+
</select>
125+
</label>
126+
<label style="margin-left: 12px; color: var(--muted)">
127+
Samples
128+
<select id="sample-runs">
129+
<option value="1">1</option>
130+
<option value="10">10</option>
131+
<option value="20" selected>20</option>
132+
<option value="30">30</option>
133+
<option value="50">50</option>
134+
</select>
135+
</label>
95136
<table id="results">
96137
<thead>
97138
<tr>
@@ -108,6 +149,18 @@ <h1>DOM Benchmark: Regor vs Vue (latest)</h1>
108149
</thead>
109150
<tbody></tbody>
110151
</table>
152+
<table id="scenario-results">
153+
<thead>
154+
<tr>
155+
<th>Framework</th>
156+
<th>Scenario</th>
157+
<th>Median (ms)</th>
158+
<th>P90 (ms)</th>
159+
<th>Samples</th>
160+
</tr>
161+
</thead>
162+
<tbody></tbody>
163+
</table>
111164
<div id="log" class="note"></div>
112165
<div class="roots">
113166
<div class="panel rootbox">

benchmarks/initial-load.html

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
--fg: #e5e7eb;
1212
--muted: #9ca3af;
1313
--accent: #22c55e;
14+
--winner: #4ade80;
1415
}
1516
body {
1617
margin: 0;
@@ -60,6 +61,10 @@
6061
padding: 8px;
6162
text-align: left;
6263
}
64+
#results .winner-metric {
65+
color: var(--winner);
66+
font-weight: 700;
67+
}
6368
.roots {
6469
display: grid;
6570
grid-template-columns: 1fr 1fr;
@@ -89,6 +94,35 @@ <h1>Initial Load Benchmark: Regor vs Vue</h1>
8994
<button id="run-regor">Run Regor</button>
9095
<button id="run-vue">Run Vue</button>
9196
<button id="run">Run Both</button>
97+
<label style="margin-left: 12px; color: var(--muted)">
98+
Row count
99+
<select id="row-count">
100+
<option value="500" selected>500</option>
101+
<option value="1000">1000</option>
102+
<option value="2000">2000</option>
103+
<option value="5000">5000</option>
104+
</select>
105+
</label>
106+
<label style="margin-left: 12px; color: var(--muted)">
107+
Warmups
108+
<select id="warmup-runs">
109+
<option value="0">0</option>
110+
<option value="2">2</option>
111+
<option value="4">4</option>
112+
<option value="6" selected>6</option>
113+
<option value="10">10</option>
114+
</select>
115+
</label>
116+
<label style="margin-left: 12px; color: var(--muted)">
117+
Samples
118+
<select id="sample-runs">
119+
<option value="1">1</option>
120+
<option value="10">10</option>
121+
<option value="20" selected>20</option>
122+
<option value="30">30</option>
123+
<option value="50">50</option>
124+
</select>
125+
</label>
92126
<table id="results">
93127
<thead>
94128
<tr>

0 commit comments

Comments
 (0)