README

Vecty is a library for building responsive and dynamic web frontends in Go instead of in JavaScript, HTML & CSS. It competes with modern web frameworks like React & VueJS, and supports compilation to both WebAssembly and vanilla JavaScript.

Build Status GoDoc codecov

Benefits

  • Go developers can be competitive frontend developers.
  • Share Go code between your frontend & backend.
  • Reusability by sharing components via Go packages so that others can simply import them.

Goals

  • Simple
    • Designed from the ground up to be easily mastered by newcomers (like Go).
  • Performant
    • Efficient & understandable performance, small bundle sizes, same performance as raw JS/HTML/CSS.
  • Composable
    • Nest components to form your entire user interface, seperating them logically as you would any normal Go package.
  • Designed for Go (implicit)
    • Written from the ground up asking the question "What is the best way to solve this problem in Go?", not simply asking "How do we translate $POPULAR_LIBRARY to Go?"

Features

  • Compiles to WebAssembly (via standard Go compiler) and vanilla JavaScript (via GopherJS).
  • Small bundle sizes: 0.5 MB hello world (see section below).
  • Fast expectation-based browser DOM diffing ('virtual DOM', but less resource usage).

Current Status

Vecty is currently considered to be an experimental work-in-progress. Prior to widespread production use, we must meet our v1.0.0 milestone goals, which are being completed slowly and steadily as contributors have time (Vecty is over 4 years in the making!).

Early adopters may make use of it for real applications today as long as they are understanding and accepting of the fact that:

  • APIs will change (maybe extensively).
  • A number of important things are not ready:
    • Extensive documentation, examples and tutorials
    • URL-based component routing
    • Ready-to-use component libraries (e.g. material UI)
    • Server-side rendering
    • And more, see milestone: v1.0.0
  • The scope of Vecty is only ~80% defined currently.
  • There are a number of important open issues.

For a list of projects currently using Vecty, see the doc/projects-using-vecty.md file.

Small bundle sizes

Vecty uses extremely minimal dependencies and prides itself on producing very small bundle sizes (mostly limited by the compiler), making it suitable for modern web development:

Example Compiler Bundle size Compressed (gzip)
hellovecty Go + WebAssembly 2.3 MB 0.5 MB
markdown Go + WebAssembly 4.2 MB 0.9 MB
todomvc Go + WebAssembly 3.4 MB 0.7 MB
hellovecty GopherJS 0.5 MB 0.1 MB
markdown GopherJS 2.6 MB 0.4 MB
todomvc GopherJS 1.7 MB 0.3 MB

Community

Changelog

See the doc/CHANGELOG.md file.

Expand ▾ Collapse ▴

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddStylesheet

func AddStylesheet(url string)

    AddStylesheet adds an external stylesheet to the document.

    func RenderBody

    func RenderBody(body Component)

      RenderBody renders the given component as the document body. The given Component's Render method must return a "body" element or a panic will occur.

      This function blocks forever in order to prevent the program from exiting, which would prevent components from rerendering themselves in the future.

      It is a short-handed form for writing:

      err := vecty.RenderInto("body", body)
      if err !== nil {
      	panic(err)
      }
      select{} // run Go forever
      

      func RenderInto

      func RenderInto(selector string, c Component) error

        RenderInto renders the given component into the existing HTML element found by the CSS selector (e.g. "#id", ".class-name") by replacing it.

        If there is more than one element found, the first is used. If no element is found, an error of type InvalidTargetError is returned.

        If the Component's Render method does not return an element of the same type, an error of type ElementMismatchError is returned.

        func RenderIntoNode

        func RenderIntoNode(node SyscallJSValue, c Component) error

          RenderIntoNode renders the given component into the existing HTML element by replacing it.

          If the Component's Render method does not return an element of the same type, an error of type ElementMismatchError is returned.

          func Rerender

          func Rerender(c Component)

            Rerender causes the body of the given Component (i.e. the HTML returned by the Component's Render method) to be re-rendered.

            If the Component has not been rendered before, Rerender panics. If the Component was previously unmounted, Rerender is no-op.

            Rerender operates efficiently by batching renders together. As a result, there is no guarantee that a calls to Rerender will map 1:1 with calls to the Component's Render method. For example, two calls to Rerender may result in only one call to the Component's Render method.

            func SetTitle

            func SetTitle(title string)

              SetTitle sets the title of the document.

              Types

              type Applyer

              type Applyer interface {
              	// Apply applies the markup to the given HTML element or text node.
              	Apply(h *HTML)
              }

                Applyer represents some type of markup (a style, property, data, etc) which can be applied to a given HTML element or text node.

                func Attribute

                func Attribute(key string, value interface{}) Applyer

                  Attribute returns an Applyer which applies the given attribute to an element.

                  In most situations, you should use Property function, or the prop subpackage (which is type-safe) instead. There are only a few attributes (aria-*, role, etc) which do not have equivalent properties. Always opt for the property first, before relying on an attribute.

                  func Class

                  func Class(class ...string) Applyer

                    Class returns an Applyer which applies the provided classes. Subsequent calls to this function will append additional classes. To toggle classes, use ClassMap instead. Each class name must be passed as a separate argument.

                    func Data

                    func Data(key, value string) Applyer

                      Data returns an Applyer which applies the given data attribute.

                      func Key

                      func Key(key interface{}) Applyer

                        Key returns an Applyer that uniquely identifies the HTML element amongst its siblings. When used, all other sibling elements and components must also be keyed.

                        func MarkupIf

                        func MarkupIf(cond bool, markup ...Applyer) Applyer

                          MarkupIf returns nil if cond is false, otherwise it returns the given markup.

                          func Namespace

                          func Namespace(uri string) Applyer

                            Namespace is Applyer which sets the namespace URI to associate with the created element. This is primarily used when working with, e.g., SVG.

                            See https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS#Valid Namespace URIs

                            func Property

                            func Property(key string, value interface{}) Applyer

                              Property returns an Applyer which applies the given JavaScript property to an HTML element or text node. Generally, this function is not used directly but rather the prop and style subpackages (which are type safe) should be used instead.

                              To set style, use style package or Style. Property panics if key is "style".

                              func Style

                              func Style(key, value string) Applyer

                                Style returns an Applyer which applies the given CSS style. Generally, this function is not used directly but rather the style subpackage (which is type safe) should be used instead.

                                func UnsafeHTML

                                func UnsafeHTML(html string) Applyer

                                  UnsafeHTML is Applyer which unsafely sets the inner HTML of an HTML element.

                                  It is entirely up to the caller to ensure the input HTML is properly sanitized.

                                  It is akin to innerHTML in standard JavaScript and dangerouslySetInnerHTML in React, and is said to be unsafe because Vecty makes no effort to validate or ensure the HTML is safe for insertion in the DOM. If the HTML came from a user, for example, it would create a cross-site-scripting (XSS) exploit in the application.

                                  The returned Applyer can only be applied to HTML, not vecty.Text, or else a panic will occur.

                                  type ClassMap

                                  type ClassMap map[string]bool

                                    ClassMap is markup that specifies classes to be applied to an element if their boolean value are true.

                                    func (ClassMap) Apply

                                    func (m ClassMap) Apply(h *HTML)

                                      Apply implements the Applyer interface.

                                      type Component

                                      type Component interface {
                                      	// Render is responsible for building HTML which represents the component.
                                      	//
                                      	// If Render returns nil, the component will render as nothing (in reality,
                                      	// a noscript tag, which has no display or action, and is compatible with
                                      	// Vecty's diffing algorithm).
                                      	Render() ComponentOrHTML
                                      
                                      	// Context returns the components context, which is used internally by
                                      	// Vecty in order to store the previous component render for diffing.
                                      	Context() *Core
                                      	// contains filtered or unexported methods
                                      }

                                        Component represents a single visual component within an application. To define a new component simply implement the Render method and embed the Core struct:

                                        type MyComponent struct {
                                        	vecty.Core
                                        	... additional component fields (state or properties) ...
                                        }
                                        
                                        func (c *MyComponent) Render() vecty.ComponentOrHTML {
                                        	... rendering ...
                                        }
                                        

                                        type ComponentOrHTML

                                        type ComponentOrHTML interface {
                                        	// contains filtered or unexported methods
                                        }

                                          ComponentOrHTML represents one of:

                                          Component
                                          *HTML
                                          List
                                          KeyedList
                                          nil
                                          

                                          An unexported method on this interface ensures at compile time that the underlying value must be one of these types.

                                          type Copier

                                          type Copier interface {
                                          	// Copy returns a copy of the component.
                                          	Copy() Component
                                          }

                                            Copier is an optional interface that a Component can implement in order to copy itself. Vecty must internally copy components, and it does so by either invoking the Copy method of the Component or, if the component does not implement the Copier interface, a shallow copy is performed.

                                            type Core

                                            type Core struct {
                                            	// contains filtered or unexported fields
                                            }

                                              Core implements the Context method of the Component interface, and is the core/central struct which all Component implementations should embed.

                                              func (*Core) Context

                                              func (c *Core) Context() *Core

                                                Context implements the Component interface.

                                                type ElementMismatchError

                                                type ElementMismatchError struct {
                                                	// contains filtered or unexported fields
                                                }

                                                  ElementMismatchError is returned when the element returned by a component does not match what is required for rendering.

                                                  func (ElementMismatchError) Error

                                                  func (e ElementMismatchError) Error() string

                                                  type Event

                                                  type Event struct {
                                                  	Value  SyscallJSValue
                                                  	Target SyscallJSValue
                                                  }

                                                    Event represents a DOM event.

                                                    type EventListener

                                                    type EventListener struct {
                                                    	Name     string
                                                    	Listener func(*Event)
                                                    	// contains filtered or unexported fields
                                                    }

                                                      EventListener is markup that specifies a callback function to be invoked when the named DOM event is fired.

                                                      func (*EventListener) Apply

                                                      func (l *EventListener) Apply(h *HTML)

                                                        Apply implements the Applyer interface.

                                                        func (*EventListener) PreventDefault

                                                        func (l *EventListener) PreventDefault() *EventListener

                                                          PreventDefault prevents the default behavior of the event from occurring.

                                                          See https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault.

                                                          func (*EventListener) StopPropagation

                                                          func (l *EventListener) StopPropagation() *EventListener

                                                            StopPropagation prevents further propagation of the current event in the capturing and bubbling phases.

                                                            See https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation.

                                                            type HTML

                                                            type HTML struct {
                                                            	// contains filtered or unexported fields
                                                            }

                                                              HTML represents some form of HTML: an element with a specific tag, or some literal text (a TextNode).

                                                              func Tag

                                                              func Tag(tag string, m ...MarkupOrChild) *HTML

                                                                Tag returns an HTML element with the given tag name. Generally, this function is not used directly but rather the elem subpackage (which is type safe) is used instead.

                                                                func Text

                                                                func Text(text string, m ...MarkupOrChild) *HTML

                                                                  Text returns a TextNode with the given literal text. Because the returned HTML represents a TextNode, the text does not have to be escaped (arbitrary user input fed into this function will always be safely rendered).

                                                                  func (*HTML) Key

                                                                  func (h *HTML) Key() interface{}

                                                                    Key implements the Keyer interface.

                                                                    func (*HTML) Node

                                                                    func (h *HTML) Node() SyscallJSValue

                                                                      Node returns the underlying JavaScript Element or TextNode.

                                                                      It panics if it is called before the DOM node has been attached, i.e. before the associated component's Mounter interface would be invoked.

                                                                      type InvalidTargetError

                                                                      type InvalidTargetError struct {
                                                                      	// contains filtered or unexported fields
                                                                      }

                                                                        InvalidTargetError is returned when the element targeted by a render is invalid because it is null or undefined.

                                                                        func (InvalidTargetError) Error

                                                                        func (e InvalidTargetError) Error() string

                                                                        type KeyedList

                                                                        type KeyedList struct {
                                                                        	// contains filtered or unexported fields
                                                                        }

                                                                          KeyedList is produced by calling List.WithKey. It has no public behaviour, and List members are no longer accessible once wrapped in this stucture.

                                                                          func (KeyedList) Key

                                                                          func (l KeyedList) Key() interface{}

                                                                            Key implements the Keyer interface

                                                                            type Keyer

                                                                            type Keyer interface {
                                                                            	// Key returns a value that uniquely identifies the component amongst its
                                                                            	// siblings. The returned type must be a valid map key, or rendering will
                                                                            	// panic.
                                                                            	Key() interface{}
                                                                            }

                                                                              Keyer is an optional interface that a Component can implement in order to uniquely identify the component amongst its siblings. If implemented, all siblings, both components and HTML, must also be keyed.

                                                                              Implementing this interface allows siblings to be removed or re-ordered whilst retaining state, and improving render efficiency.

                                                                              type List

                                                                              type List []ComponentOrHTML

                                                                                List represents a list of components or HTML.

                                                                                func (List) WithKey

                                                                                func (l List) WithKey(key interface{}) KeyedList

                                                                                  WithKey wraps the List in a Keyer using the given key. List members are inaccessible within the returned value.

                                                                                  type MarkupList

                                                                                  type MarkupList struct {
                                                                                  	// contains filtered or unexported fields
                                                                                  }

                                                                                    MarkupList represents a list of Applyer which is individually applied to an HTML element or text node.

                                                                                    It may only be created through the Markup function.

                                                                                    func Markup

                                                                                    func Markup(m ...Applyer) MarkupList

                                                                                      Markup wraps a list of Applyer which is individually applied to an HTML element or text node.

                                                                                      func (MarkupList) Apply

                                                                                      func (m MarkupList) Apply(h *HTML)

                                                                                        Apply implements the Applyer interface.

                                                                                        type MarkupOrChild

                                                                                        type MarkupOrChild interface {
                                                                                        	// contains filtered or unexported methods
                                                                                        }

                                                                                          MarkupOrChild represents one of:

                                                                                          Component
                                                                                          *HTML
                                                                                          List
                                                                                          KeyedList
                                                                                          nil
                                                                                          MarkupList
                                                                                          

                                                                                          An unexported method on this interface ensures at compile time that the underlying value must be one of these types.

                                                                                          func If

                                                                                          func If(cond bool, children ...ComponentOrHTML) MarkupOrChild

                                                                                            If returns nil if cond is false, otherwise it returns the given children.

                                                                                            type Mounter

                                                                                            type Mounter interface {
                                                                                            	// Mount is called after the component has been mounted, after the DOM node
                                                                                            	// has been attached.
                                                                                            	Mount()
                                                                                            }

                                                                                              Mounter is an optional interface that a Component can implement in order to receive component mount events.

                                                                                              type RenderSkipper

                                                                                              type RenderSkipper interface {
                                                                                              	// SkipRender is called with a copy of the Component made the last time its
                                                                                              	// Render method was invoked. If it returns true, rendering of the
                                                                                              	// component will be skipped.
                                                                                              	//
                                                                                              	// The previous component may be of a different type than this
                                                                                              	// RenderSkipper itself, thus a type assertion should be used and no action
                                                                                              	// taken if the type does not match.
                                                                                              	SkipRender(prev Component) bool
                                                                                              }

                                                                                                RenderSkipper is an optional interface that Component's can implement in order to short-circuit the reconciliation of a Component's rendered body.

                                                                                                This is purely an optimization, and does not need to be implemented by Components for correctness. Without implementing this interface, only the difference between renders will be applied to the browser DOM. This interface allows components to bypass calculating the difference altogether and quickly state "nothing has changed, do not re-render".

                                                                                                type SyscallJSValue

                                                                                                type SyscallJSValue jsObject

                                                                                                  SyscallJSValue is an actual syscall/js.Value type under WebAssembly and GopherJS compilation.

                                                                                                  It is declared here just for purposes of testing Vecty under native 'go test', linting, and serving documentation under godoc.org.

                                                                                                  type Unmounter

                                                                                                  type Unmounter interface {
                                                                                                  	// Unmount is called before the component has been unmounted, before the
                                                                                                  	// DOM node has been removed.
                                                                                                  	Unmount()
                                                                                                  }

                                                                                                    Unmounter is an optional interface that a Component can implement in order to receive component unmount events.

                                                                                                    Directories

                                                                                                    Path Synopsis
                                                                                                    Package elem defines markup to create DOM elements.
                                                                                                    Package elem defines markup to create DOM elements.
                                                                                                    Package event defines markup to bind DOM events.
                                                                                                    Package event defines markup to bind DOM events.
                                                                                                    example module