A web client framework to build reactive web app in Ruby with WebAssembly.
The framwork use only standard Ruby libs which include ERB to render HTML.
The render is then morphed to the actual DOM.
It need less directive like v-if or v-for because it can be done using Ruby and ERB.
Some directive is still needed to register listener.
The classic simple counter example looks like this.
class CounterComponent < Component
attr_reactive :count
def initialize(count: 0)
@count = count
end
def template
<<~ERB
<%= count %>
<button r-on:click="self.count += 1">Count</button>
ERB
end
endSee it live https://bhacaz.github.io/vuerb/counter
More examples.
curl -s https://raw.githubusercontent.com/Bhacaz/vuerb/refs/heads/main/dist/init.rb | ruby - my_new_appThe structure of the project should look like this:
my_new_app/
├── index.html
├── app.rb
├──components
└── my_component.rb
Simply launch a web server in the root of the project like http-server or with Ruby:
ruby -run -e httpd . -p 8000Then open the browser at http://localhost:8000.
A component is a class that inherit from Component. They must be located in the ./components folder and the class
name must end with Component.
# ./components/MyComponent.rb
class MyComponent < Component
def template
<<-ERB
<h1>My new component</h1>
ERB
end
endTo use a component in another component, you need to:
- Import the component at the top of the file.
- Use the
r-sourcedirective to render the component, without theComponentsuffix.
require_relative 'components/my_component'
class App < Component
def template
<<-ERB
<div r-source="My"></div>
ERB
end
endTo make an attribute reactive, use the attr_reactive method. When the
value of the attribute is reassigned using the setter, the component will be re-rendered.
class CounterComponent < Component
attr_reactive :count
def initialize(count: 0)
@count = count
end
def template
<<~ERB
<%= count %>
<button r-on:click="self.count += 1">Count</button>
ERB
end
endImportant
Using Array#concat or Array#push will not trigger a re-render.
It must be reassigned self.array += ['new_item'].
- click
- change
The value to this attribute use inline Ruby code that will be evalutated in the context of the instance of the component.
<button r-on:click="self.count += 1">Count</button>Set the name of an attr_reactive so on input change the new value is assign to the
attr_reactive.
class MyComponent < Component
attr_reactive :message
def template
<<-ERB
<input r-model="message" value="<%= message %>">
<p>The message is: <%= message %></p>
ERB
end
endUsed to render a component. WIP will change to use custom HTML tag.
<div r-source="Count"></div>Will render the CountComponent
To pass initial data to the initializer of a component.
class CountComponent < Component
attr_reactive :count
def initialize(count:)
@count = count
end
end<div r-source="Count" r-data="{ count: 42 }"></div>To help during morphing.
<% todos.each do |todo|
<div data-key=<%= todo.id %>>
<h1><%= todo.title %></h1>
</div>
<% end %>