All Projects → prism-rb → Prism

prism-rb / Prism

Licence: mit
Build frontend web apps with Ruby and WebAssembly

Programming Languages

ruby
36898 projects - #4 most used programming language

Projects that are alternatives of or similar to Prism

Wasmplay
WASM Web "Framework" Playground
Stars: ✭ 105 (-58.17%)
Mutual labels:  webassembly, wasm, frontend
Zwitterion
A web dev server that lets you import anything*
Stars: ✭ 514 (+104.78%)
Mutual labels:  webassembly, wasm, spa
imgalign
Webapplication for image stitching and aligning
Stars: ✭ 162 (-35.46%)
Mutual labels:  spa, webassembly, wasm
Percy
Build frontend browser apps with Rust + WebAssembly. Supports server side rendering.
Stars: ✭ 1,856 (+639.44%)
Mutual labels:  webassembly, wasm, frontend
Argon2 Browser
Argon2 library compiled for browser runtime
Stars: ✭ 197 (-21.51%)
Mutual labels:  webassembly, wasm
Rustmart Yew Example
Single Page Application (SPA) written using Rust, Wasm and Yew
Stars: ✭ 196 (-21.91%)
Mutual labels:  wasm, spa
Wasmtime Go
Go WebAssembly runtime powered by Wasmtime
Stars: ✭ 239 (-4.78%)
Mutual labels:  webassembly, wasm
Sandspiel
Creative cellular automata browser game
Stars: ✭ 2,476 (+886.45%)
Mutual labels:  webassembly, wasm
Wasm Examples
WebAssembly Examples
Stars: ✭ 191 (-23.9%)
Mutual labels:  webassembly, wasm
Koa Vue Notes Web
🤓 This is a simple SPA built using Koa as the backend, Vue as the first frontend, and React as the second frontend. Features MySQL integration, user authentication, CRUD note actions, and Vuex store modules.
Stars: ✭ 200 (-20.32%)
Mutual labels:  frontend, spa
Artichoke
💎 Artichoke is a Ruby made with Rust
Stars: ✭ 2,557 (+918.73%)
Mutual labels:  webassembly, wasm
Wapm Cli
📦 WebAssembly Package Manager (CLI)
Stars: ✭ 236 (-5.98%)
Mutual labels:  webassembly, wasm
Ruukh
An experimental next-gen frontend framework for the Web in Rust.
Stars: ✭ 194 (-22.71%)
Mutual labels:  wasm, frontend
Awesome Wasm Langs
😎 A curated list of languages that compile directly to or have their VMs in WebAssembly
Stars: ✭ 2,966 (+1081.67%)
Mutual labels:  webassembly, wasm
Wasmpatch
🧱Yet Another Patch Module for iOS/macOS via WebAssembly
Stars: ✭ 192 (-23.51%)
Mutual labels:  webassembly, wasm
Webhook.site
⚓️ Easily test HTTP webhooks with this handy tool that displays requests instantly.
Stars: ✭ 2,842 (+1032.27%)
Mutual labels:  frontend, spa
Pont
An online board game in Rust and WebAssembly
Stars: ✭ 218 (-13.15%)
Mutual labels:  webassembly, wasm
Wasm Worker
Move a WebAssembly module into its own thread
Stars: ✭ 215 (-14.34%)
Mutual labels:  webassembly, wasm
Wasmer Postgres
💽🕸 Postgres library to run WebAssembly binaries.
Stars: ✭ 245 (-2.39%)
Mutual labels:  webassembly, wasm
Wasm By Example
Wasm By Example is a website with a set of hands-on introduction examples and tutorials for WebAssembly (Wasm)
Stars: ✭ 226 (-9.96%)
Mutual labels:  webassembly, wasm

Prism

Join the chat at https://gitter.im/prism-rb/community Build Status Financial Contributors on Open Collective Join the chat at https://gitter.im/prism-rb/community

Build frontend web apps with Ruby and WebAssembly

Introduction

Prism is a framework that helps you make frontend web applications with Ruby and WebAssembly. It uses mruby and emscripten to compile ruby code to WebAssembly. It also provides a runtime layer for working with the DOM and events.

⚡️ Prism is currently in extremely early alpha. Expect bugs, breaking API changes, missing functionality and rough edges. ⚡️

Getting started

You can install Prism from RubyGems using gem install prism-cli.

CLI Usage

You can initialize a new Prism app by running prism init. This simply creates a hello world sample application, by default at ./app.rb but you can customize the location by providing an argument to prism init.

You can then run prism server, which will start a development server. If you then navigate to localhost:3042/app.rb, you should see the sample application. Try changing the code and reloading the page, and the app will update.

If an error occurs, it will be printed out to the browser console.

Building production releases of Prism apps through the command line is still a work in progress.

Writing a Prism App

Prism apps are written in mruby. mruby is a lightweight implementation of Ruby that's suitable for compiling to the web.

mruby is similar in many ways to cruby and will be a familiar experience for someone who has only used the mainline interpreter. The most notable exception is that mruby only supports syntax up to ruby 1.9, which means there are no keyword arguments or safe traversal operator.

There are a number of other small differences, and it's worth reviewing the mruby limitations documentation. You might also want to refer to the mruby API docs.

If you run prism init, it will create a sample application that makes a good starting point. This is the code it outputs:

class HelloWorld < Prism::Component
  attr_accessor :name

  def initialize(name = "World")
    @name = name
  end

  def render
    div(".hello-world", [
      input(onInput: call(:name=).with_target_data(:value)),
      div("Hello, #{name}")
    ])
  end
end

Prism.mount(HelloWorld.new)

Let's break this down piece by piece.


class HelloWorld < Prism::Component

Much like Rails, Prism provides most of its functionality through base classes that you should inherit from.

The key concept in Prism is a Component, which should be familiar to anyone who has worked with JS frameworks like React, Vue or similar.

Prism::Component provides helper methods for creating virtual dom elements, and for handling events.


  attr_accessor :name

  def initialize(name = "World")
    @name = name
  end

This is fairly standard Ruby, and there's nothing actually unique to Prism or mruby going on. Note that we're defining an attr_accessor rather than just an attr_reader, so that we can set the name directly when it changes.


  def render
    div(".hello-world", [
      input(onInput: call(:name=).with_target_data(:value)),
      div("Hello, #{name}")
    ])
  end

It's expected that Prism components implement a #render method that returns a representation of what the current view should be.

This should be familiar to anyone who has worked with React, Cycle.js or Elm. There is a method defined for each different dom element. You can provide a class name or id as a string (".todo-list-item" or "#login"), an object with options to configure the attributes, props, styles, classes and event listeners, and an array of child elements.

Prism's virtual dom is powered by snabddom, a tried and true lightweight JavaScript vdom library. For the most part, the API is simply passed through to snabbdom, so it's worth reading the snabddom docs.


  input(onInput: call(:name=).with_target_data(:value)),

The most interesting line in this example is the event handler for the input event.

Prism::Component defines a #call method that you can use to call methods on your component when events occur.

#call takes a symbol that is the method name to call, and any arguments you want passed to the method.

You can also include data from the event or target element using .with_event_data and .with_target_data. These methods can be chained as needed.


Prism.mount(HelloWorld.new)

The last line mounts the HelloWorld component. Prism is currently hardcoded to mount to an element with id #root on load. In future this will be configurable.

Components and State

Prism aims to provide a component system that should feel very similar to most virtual dom based JavaScript frameworks.

You can nest Prism components, and use instances of Prism components directly when rendering in place of dom elements.

Prism has no explicit state management built in, preferring to rely on Ruby's built-in state management tools, primarily instance variables in class instances.

Components in a Prism app persist in memory, and will often have multiple methods call over their lifetime.

Larger Prism applications would likely benefit from adapting a more structured approach to managing certain parts of state, a la Redux.

API

Prism::Component

#div(identifier, options, children), #img, #p, ...

Helpers for creating virtual dom elements. There is a method for every type DOM element.

The arguments are all optional and can be provided in any order for convenience.

Arguments:

  • identifier string, optional - A shorthand for setting the id and classes. E.g. "#login", .alert, #header.flex.dark

  • options object, optional - Element configuration

    • attrs object, optional - Attributes that are set when the element is created. Equivalent to putting items directly into the element in the HTML.
    • props object, optional - Props to be set on the object.
    • style object, optional - Element styles, keys are css properties and values are strings.
    • class object, optional - Keys are class names, values are booleans indicating whether or not the class is active. An easy way to add or remove classes based on a condition.
    • on function, optional - Keys are browser events (like click or input), values are Prism::EventHandler instances. See below on how to create EventHandler instances. Additionally, there are a number of aliases that let you set event handlers directly on the options object. The full list that is currently aliased is: onClick, onChange, onInput, onMousedown, onMouseup, onKeydown, onKeyup and onScroll
  • children array or string, optional - Either a string of content for the element or an array of children. Each child should either be a string, a virtual dom tree, or an instance of a Prism::Component with #render.

#call(method_name, *arguments)

Arguments:

  • method_name symbol - The name of the method to call when the event occurs. Returns a Prism::EventHandler.
  • *arguments any, variadic - You can provide arguments that will be passed to the method after the method name. Please note any argument currently needs to be serializable, this will change in future.
#prevent_default

Takes no arguments, returns a Prism::EventHandler that does nothing but call event.preventDefault().

#stop_propagation

Takes no arguments, returns a Prism::EventHandler that does nothing but call event.stopPropagation().


Prism::EventHandler

Represents a handler for an event, with a method to call and arguments to pass. The arguments are a mixture of values passed from Ruby and values pulled from the event and targed in JS. The order of arguments is based on how the event handler was constructed.

#with_args(*args)

Adds arguments to an existing event handler.

#with_event

Add an event argument to the handler. When the method is called, a serialized version of the event will be passed.

#with_event_data(*properties)

Add arguments that contain data from the event. The properties should be either a string or a symbol. One property you might want to extract from the event is :key for keydown events.

#with_target_data(*properties)

Add arguments that contain data from the target element. The properties should be either a string or a symbol. You could for example extract the :value of an input or the :checked field of a tickbox.

#prevent_default

Calls .preventDefault() on the event when it occurs.

#stop_propagation

Calls .stopPropagation() on the event when it occurs.

Examples:

call(:name=).with_target_data(:value) - calls a setter with the content of the target element call(:goto_page, 5).with_event - calls a method with the number 5 as the first argument and the event data as the second

Prism.mount(component)

Takes an instance of a Prism::Component and returns a Prism::MountPoint.

The MountPoint should be the result of the last expression in the file, as it is used by the Prism C and JS runtime to interact with the application.

Future

As mentioned above, Prism is still in extremely early development. The following would be nice to have but has yet to be implemented.

  • support for require
  • transpile modern ruby syntax to 1.9
  • a way for users to make their own IO drivers
  • built in support for HTTP
  • compile time improvements
  • fallback to asm.js for old browsers
  • rails integration
  • SSR
  • sourcemaps for mruby code
  • linting for incompatibilities with cruby
  • elm-reactor style dev server

If you're interested in helping implement any of those features, or you want to contribute in any way, please make an issue or a pull request or just get in touch with me.

Prism is currently developed by a single person (who also has a lot of other ambitious projects). I would love to have some other people to help share the load. There's lots of low hanging fruit still to be plucked.

Supporting Prism Development

Most open source projects are built on a mountain of unpaid labour. Even hugely successful projects that have good funding tend to have a history of excess unpaid labour to get to that point.

Prism is taking a different approach, by launching with an Open Collective page. We're using Open Collective because it enables us to fund Prism as a project rather than one particular person. Funds in the Open Collective will only go towards future development.

If you think this is a worthwhile project, please support us on Open Collective. If you think your company could benefit from Prism in the future, please advocate for your company to financially support Prism.

My main goal around starting Prism with funding is that I want as much of the work that's done on Prism as possible to be reimbursed, no matter who's doing it. The other aspect is that I don't have very much spare time for projects but if I can get paid for my work I can do Prism as part of my day to day contract work.

Support Prism on Open Collective

Contributors

Code Contributors

This project exists thanks to all the people who contribute. [Contribute].

Financial Contributors

Become a financial contributor and help us sustain our community. [Contribute]

Individuals

Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]

License

Prism is available under the MIT license. Please see the LICENSE file for more details.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].