Are you an LLM? You can read better optimized documentation at /guide/overview.md for this page in Markdown format
Vue Compatibility
Lune uses Vue-style template syntax and a port of Vue's reactivity package, but it is not the full Vue runtime. Use this page to check which Vue features are supported, partially supported, or intentionally omitted.
Supported
| Feature | Notes |
|---|---|
| Interpolation | Text interpolation with {{ }} or custom delimiters. |
lu-scope | Creates a reactive scope for an element. |
lu-if, lu-else-if, lu-else | Conditional rendering. |
lu-for | Arrays, objects, numbers, and basic destructuring. |
lu-model | Text inputs, textareas, checkboxes, radios, and selects. |
lu-bind / : | Attribute, class, style, object, and :ref bindings. |
lu-on / @ | DOM event listeners, common modifiers, key modifiers, and @lune:mounted / @lune:unmounted. |
lu-show | Toggles inline display. |
lu-text, lu-html, lu-cloak, lu-pre, lu-once | Supported as lightweight directives. |
ref | Stores DOM elements on $refs. |
reactive() | Re-exported from @lune-js/core, a port of @vue/reactivity built on Alien Signals. |
effect() | Re-exported from @lune-js/core; returns the effect runner. |
Different from full Vue
| Area | Lune behavior |
|---|---|
| Components | Components are plain functions or objects returned from lu-scope; there are no SFCs, render functions, props validation, emits, slots, or setup(). |
| Refs | ref stores DOM elements, including elements that also have lu-scope. It does not return a Vue component instance. |
| Reactivity exports | reactive(), readonly(), shallowReactive(), shallowReadonly(), effect() and nextTick() are exported from lune-js. There is no ref(), computed(), watch() or effectScope() — use getters for derived values and effect() for side effects, or install @vue/reactivity alongside Lune. |
| Event listeners | @event listeners are attached to DOM elements. app.unmount() stops reactive effects and directive cleanup callbacks, but native event listeners remain attached until the DOM elements are removed or the browser releases them. |
| Expressions | Template expressions are parsed and compiled by Lune's own engine rather than new Function(), so Lune runs under a Content Security Policy without unsafe-eval. The engine implements a subset of JavaScript and resolves identifiers against an allow list — see Security. |
| Mounting | app.mount(selector) returns undefined if the selector does not match an element. |
Unsupported Vue syntax
| Vue feature | What to use instead |
|---|---|
Single-file components (.vue) | Plain HTML plus lu-scope objects/functions. |
createApp(Component) root components | createApp(initialData).mount(target). |
setup(), data(), methods, computed options | Return or pass a plain object with fields, methods, and JavaScript getters. |
props, emits, provide / inject | Pass values through functions, parent scopes, or shared reactive stores. |
| Slots and scoped slots | Use normal HTML/template fragments and lu-scope functions. |
| Transitions | Use CSS and lifecycle events manually. |
lu-on="object" | Use individual event bindings like @click="onClick". |
| Full Vue app config/plugins | Lune plugins only receive the app instance and can register directives or mutate app state. |
Loops, function/class, async/await inside expressions | Keep that logic in a scope method, where it is ordinary JavaScript. |
| Browser globals inside expressions | Register what the template needs with allowGlobals(), or pass it through the scope. |
When to choose full Vue instead
Use full Vue if you need SFCs, router-driven SPA behavior, rich component contracts, SSR hydration, or the full Composition API from the vue package.