Vugu: A modern UI library for Go+WebAssembly (experimental)



Travis CI GoDoc stability-experimental

Vugu is an experimental library for web UIs written in Go and targeting webassembly. Guide and docs at Godoc at

If you've ever wanted to write a UI not in JS but pure Go... and run it in your browser, right now... That (experimental;) future is here!

Introducing Vugu (pronounced /ˈvuː.ɡuː/), a VueJS-inspired library in Go targeting wasm.

No node. No JS. No npm. No node_modules folder competing with your music library for disk space.


  • 2020-11-08 Work in progress on a UI component library, the current concept is strongly influenced by both Bootstrap and Material Design. Some specific components, code and documentation will follow soonest.
  • 2020-09-13 v0.3.3 Lifecycle callbacks implemented (Init, Compute, Rendered, Destroy) plus documentation
  • 2020-06-21 v0.3.2 Vugu+TinyGo is now functional; test suite updated so most tests are run with both default Go and TinyGo compilation; docs updated; Vugu+TinyGo example works
  • 2020-04-26 v0.3.0 Slots are now implemented. Plus vg-js-create/vg-js-populate, vg-template, vg-var; vgform package has initial prototype for form inputs; docs written for these features plus for router and wiring (several pages added to plus other individual sections). There are two small but breaking changes with this release: vg-html now escapes markup by default and vugu.DOMEvent was changed from a struct to an interface. For the earlier vg-html behavior use vg-html='vugu.HTML("...")' (see and existing DOMEvent code should fix by simply removing the pointer i.e. change event *vugu.DOMEvent to event vugu.DOMEvent - and also make sure to go get -u again. I generally try to avoid these sorts of breaking changes but it's better to do them sooner rather than later.
  • 2020-04-13 v0.2.3 much more flexible attribute support and SVGs now work (thanks to @tbe!); vugu-examples/simple set up, more to come; nested component rendering bug fixed (#117); tools doc page added to the site; devutil package; vgrun working
  • 2020-04-06 v0.2.0 released. and playground ported over to it; vugugen now supports recursive and merge-single modes and output files end with _vgen.go; improved tests; various documentation updates; vgrgen route generator supports recursive and clean options
  • 2020-03-29 Vugu URL router is now functional ( Features include optional fragment support, client and server-side use, two-way data binding for query and path parameters, and automatic route generation based on folder structure. The vg-comp tag now allows programmatic component selection. A pattern for wiring large applications with lots of components is in place and will be tested further as dev moves forward. Next steps include just a bit more dev and testing on the router and then updating to use these new features and bring the documentation up to date.
  • 2019-12-08 First Vugu program successfully compiles with Tinygo. Testing and a bit more alternate implementation is still required but at least the compilation works now.
  • 2019-11-24 WASM test suite now working in Travis CI; getting closer on TinyGo support and merged refactor into master.
  • 2019-11-10 Support for tinygo is in-progress on the tinygo branch. No known blocking issues as yet, some minor refactor required but looks promising.
  • 2019-09-29 Router is work-in-progress. Will use radix tree to efficiently combine common prefixes. Struct tags will usable to two-way-bind path and query params, or it can be done manually. Some similarities to Angular and Vue routers but will be less declarative and more functional (instead of a big tree of objects with various config, you write path handler functions to set whatever properties need to be set, establish binding, etc). Plan is to get the bulk of this coded by next week.
  • 2019-09-22 Static HTML renderer (re)implemented. EventEnv bug fix and added it to to JS renderer to allow background requests at startup. Some initial work on a router:
  • 2019-09-15 Refactor changes merged into master. Includes: updated sample code, component resolution at code-generation time, type-safe component params, optional component param map, BeforeBuild lifecycle callback, modification tracking system, JS property assignment syntax, "full HTML" support, improved DOM event handling, Go 1.13 support, import deduplication, and a brand new rendering pipeline! Initial documentation at
  • 2019-09-08 Implemented ModTracker to keep track of changes to components and their data (this is also the beginning of Vuex-like functionality but without wrappers or events). Worked out the lifecycle of components in much more detail and work in progress on nested components implementation (component-refactor branch currently broken, but finally the core nested component functionality is going in - hopefully will finish next week).
  • 2019-09-07 Updated everything for Go 1.13, including both master and component-refactor branches, Vugu's js wrapper package, site documentation.
  • 2019-09-01 On component-refactor branch: Form element values and other related data now available on DOMEvent, .prop= syntax implemented, various cleanup, imports are deduplicated automatically now, started on nested component implementation and all of that craziness.
  • 2019-08-25 CSS now supported on component-refactor branch, including in full-HTML mode, working sample that pulls in Bootstrap CSS. Vugu's js wrapper package copied to master and made available.
  • 2019-08-18 Full HTML (root component can start with tag) now supported on component-refactor branch, updated CSS and JS support figured out and implementation in-progress
  • 2019-08-12 Refactored DOM event listener code in-progress, event registration/deregistration works(-ish), filling out the remaining functionality to provide event summary, calls like preventDefault(), etc.
  • 2019-08-04 Some basic stuff in there on the DOM syncing rewrite and the new instruction workflow from VGNode -> binary encoded to raw bytes in Go -> read with DataView in JS -> DOM tree manipulation. With the pattern in place the rest should get easier.
  • 2019-07-28 Making some hard choices on how to do DOM syncing in a performant and reliable way.
  • 2019-07-20 Some design info on how "data binding" (hashing actually) will work in Vugu:
  • 2019-07-16 Vugu has a logo! Good things are in the works, the plan is to get a bunch of much-awaited updates pushed to master before the end of the month.
  • 2019-05-19 Refactor still in progress - this is the cleaned-up architecture concept:
  • 2019-04-07 The Vugu Playground is up at:
  • 2019-04-05 Thanks to @erinpentecost, vugufmt is now available and provides gofmt-like functionality on your .vugu files. ("go get && go install")
  • 2019-04-05 The component playground should be available soon; followed by some internal work to properly handle nested components in a type-safe way; then probably a router...

Join the conversation: Gophers on Slack, channel #vugu


  • Runs in-browser using WebAssembly
  • Single-file components
  • Vue-like markup syntax
  • Write idiomatic Go code
  • Rapid prototyping
  • ~3 minute setup
  • Standard Go build tools


Get started:

Still a work in progress, but a lot of things are already functional. Some work really well.

Abbreviated Roadmap

  • Single-file components (looks similar to .vue); .vugu -> .go code generation.
  • Includes CSS in components.
  • Basic flow control with vg-if, vg-for and output with vg-content.
  • Dynamic attributes with .
  • Nested components with dynamic properties
  • Efficiently syncs to browser DOM.
  • Static HTML output (great for tests).
  • DOM Events, click, etc.
  • Modification tracking to avoid unnecessary computation where possible.
  • Basic dev and prod server tooling, easy to get started
  • Rewrite everything so it is not so terrible internally
  • URL Router (in-progress)
  • Tinygo compilation support
  • Server-side rendering (works, needs more documentation and examples)
  • Go-only component events
  • Slots
  • Component library(s) (wip!)
  • Performance optimizations
  • And much more...


It's built more like a library than a framework. While Vugu does do code generation for your .vugu component files, (and will even output a default main_wasm.go for a new project and build your program automatically upon page refresh), fundamentally you are still in control. Overall program flow, application wiring and initialization, the render loop that keeps the page in sync with your components - you have control over all of that. Frameworks call your code. Vugu is a library, your code calls it (even if Vugu generates a bit of that for you in the beginning to make things easier). One of the primary goals for Vugu, when it comes to developers first encountering it, was to make it very fast and easy to get started, but without imposing unnecessary limitations on how a project is structured. Go build tooling (and now the module system) is awesome. The idea is to leverage that to the furthest extent possible, rather than reprogramming the wheel.

So you won't find a vugu command line tool that runs a development server, instead you'll find in the docs an appropriate snippet of code you can paste in a file and go run yourself. For the code generation while there is an http.Handler that can do this upon page refresh, you also can (and should!) run vugugen via go generate. There are many small decisions in Vugu which follow this philosophy: wherever reasonably possible, just use the existing mechanism instead of inventing anew. And keep doing that until there's proof that something else is really needed. So far it's been working well. And it allows Vugu to focus on the specific things it brings to the table.

  • Fix non captured loop variables

    Fix non captured loop variables

    Related to #89


    This is a quick fix, that probably requires embellishment. I'm not 100% sure it the best way to do it.

    opened by tbruyelle 13
  • vugufmt - make formatter for .vugu files

    vugufmt - make formatter for .vugu files

    Can we make the HTML all nice and pretty, do some basic indentation on the CSS, and then run the script tag through gofmt? We could do this during code conversion, could provide gofmt-like functionality overall and help a lot with the dev experience. VSCode and other editors are going to want to call it too.

    opened by bradleypeabody 13
  • I want get input field from user

    I want get input field from user

    Question ...your question... get user a inbox field , how to get it and use in HandleClick of example ?

    in root.vugu I have a input and a function call,


    in root-data.go have a function

    func (data *RootData) HandleCick(event *vugu.DOMEvent){

    I want to use input field as value when I click button, and fetch server api Is your question related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

    Suggested Changes If applicable, please provide any suggestions of how to improve.

    Additional context Add any other context, info, files, etc. related to your question.

    opened by awkj 11
  • Run code before a component renders

    Run code before a component renders

    Question How do I run code before a component is rendered?

    Additional context Example: There is a vugu-based site When visited by unauthenticated user, I would like to call c.Navigate("/", url.Values{}). I don't know where I should put it so it gets executed before the site gets rendered. Right now, an empty site gets rendered because a backend service prevents unauthenticated user from loading the secret.

    opened by jprukner 8
  • vg-for and events: value and key are not captured

    vg-for and events: value and key are not captured

    Describe the bug Inside a loop, when using value or key variable inside a event attribute (like @click), the last value of key/value of the loop is always used, because they are not captured.

    Software Versions Vugu version: d1cd4bcee583c7d794f2d1278962e98662b39a6e Go version: 1.13.5 Browser and version: Brave Version 1.0.0 Chromium: 78.0.3904.97 (Official Build) unknown (64-bit)

    To Reproduce A PR will follow with a failing test case.

    Expected behavior key/value inside event attribute should keep their value at the moment they are used.

    Additional Notes There's a TODO for that, but I have no idea on how to achieve that properly :

    opened by tbruyelle 8
  • Sync html, head and body elements

    Sync html, head and body elements

    Fix #81

    This a first and naive attempt to sync html tags attributes from root.vugu to the final rendered result. I'm not very familiar with the code base but I think the change should be located in the vuguRender js function.

    At first I tried to use the existing opcode opcodeSetAttrStr but it appears it's really tied to the mount point, and I wasn't able to use it with the html tag. Thus I created a new opcode `opcodeSetAttrHTML specific for the html tag. I'm not very happy with it so tell me if there's a better way.

    I didn't expect such optimization for the rendering phase, but I assume this is mainly for performance reason.

    I added comments where I'm not very confident.

    I also have to fix a small bug in domrender/renderer-js-script-maker.go, the generated package name was wrong, probably because of a relocation.

    opened by tbruyelle 8
  • Multiple elements to wire

    Multiple elements to wire

    Question I am trying to wire 2 components in the buildEnv.SetWireFunc method. For that I was following this. The code I come up with is:

    func VuguSetup(buildEnv *vugu.BuildEnv, eventEnv vugu.EventEnv, opts *VuguSetupOptions) vugu.Builder {
    	router := vgrouter.New(eventEnv)
    	api := middleware.NewAPI("")
    	state := middleware.NewState()
    	buildEnv.SetWireFunc(func(b vugu.Builder) {
    		if c, ok := b.(vgrouter.NavigatorSetter); ok {
    			fmt.Println("Setting Router")
    		if c, ok := b.(middleware.APISetter); ok {
    			fmt.Println("Setting API")
    		if c, ok := b.(middleware.StateSetter); ok {
    			fmt.Println("Setting State")
    	root := &components.Root{}
    	router.MustAddRouteExact("/", vgrouter.RouteHandlerFunc(func(rm *vgrouter.RouteMatch) {
    		root.Body = &pages.Index{}
    	if router.BrowserAvail() {
    		err := router.ListenForPopState()
    		if err != nil {
    		err = router.Pull()
    		if err != nil {
    	return root

    If you have realized inside buildEnv.SetWireFunc there are three conditionals where the argument b type of vugu.Builder is being casted into different types to see if any of them match. If it does, then a print statement is displaying a message and the setter is called.

    The Root struct looks like this:

    type Root struct {
        Body vugu.Builder

    The Router, State, and API are there. However, I only see Setting Router message, instead of all three.

    Is your question related to a problem? Please describe. No, as far as I know.

    Suggested Changes None at the moment

    Additional context The setter interface is as defined in the link I said before.

    opened by Xumeiquer 7
  • Chewing Through Memory

    Chewing Through Memory

    Describe the bug I load up what looks to be a simple VUGU app and the memory utilization goes through the roof until the app crashes/is reaped.

    Software Versions Vugu version: latest (v0.3.2) Go version: 1.15 Browser and version: Chrome Latest Stable

    To Reproduce Load the following into root.vugu

        <main role="main" class="login">
        	<vgform:Input type="email" :Value='vgform.StringPtr{&c.LoginBoxValue}' required="required" placeholder="Login"></vgform:Input>
            <vgform:Input type="password" :Value='vgform.StringPtr{&c.PasswordValue}' placeholder="Password" required="required" ></vgform:Input>
            <button type="submit" class="btn btn-primary btn-block btn-large" @click='c.LoginButtonEvent(event)'>Login</button>
    		<button type="signup" class="btn btn-primary">Signup</button>
    		<button type="forgot" class="btn btn-primary">Forgot Password?</button>
    @import url(;
    .btn { display: inline-block; *display: inline; *zoom: 1; padding: 4px 10px 4px; margin-bottom: 0; font-size: 13px; line-height: 18px; color: #333333; text-align: center;text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; background-color: #f5f5f5; background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; filter:, endColorstr=#e6e6e6, GradientType=0); border-color: #e6e6e6 #e6e6e6 #e6e6e6; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border: 1px solid #e6e6e6; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); cursor: pointer; *margin-left: .3em; }
    .btn:hover, .btn:active,, .btn.disabled, .btn[disabled] { background-color: #e6e6e6; }
    .btn-large { padding: 9px 14px; font-size: 15px; line-height: normal; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; }
    .btn:hover { color: #333333; text-decoration: none; background-color: #e6e6e6; background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; -moz-transition: background-position 0.1s linear; -ms-transition: background-position 0.1s linear; -o-transition: background-position 0.1s linear; transition: background-position 0.1s linear; }
    .btn-primary, .btn-primary:hover { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); color: #ffffff; } { color: rgba(255, 255, 255, 0.75); }
    .btn-primary { background-color: #4a77d4; background-image: -moz-linear-gradient(top, #6eb6de, #4a77d4); background-image: -ms-linear-gradient(top, #6eb6de, #4a77d4); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#6eb6de), to(#4a77d4)); background-image: -webkit-linear-gradient(top, #6eb6de, #4a77d4); background-image: -o-linear-gradient(top, #6eb6de, #4a77d4); background-image: linear-gradient(top, #6eb6de, #4a77d4); background-repeat: repeat-x; filter:, endColorstr=#4a77d4, GradientType=0);  border: 1px solid #3762bc; text-shadow: 1px 1px 1px rgba(0,0,0,0.4); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.5); }
    .btn-primary:hover, .btn-primary:active,, .btn-primary.disabled, .btn-primary[disabled] { filter: none; background-color: #4a77d4; }
    .btn-block { width: 100%; display:block; }
    * { -webkit-box-sizing:border-box; -moz-box-sizing:border-box; -ms-box-sizing:border-box; -o-box-sizing:border-box; box-sizing:border-box; }
    html { width: 100%; height:100%; overflow:hidden; }
    body { 
    	width: 100%;
    	font-family: 'Open Sans', sans-serif;
    	background: #092756;
    	background: -moz-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%),-moz-linear-gradient(top,  rgba(57,173,219,.25) 0%, rgba(42,60,87,.4) 100%), -moz-linear-gradient(-45deg,  #670d10 0%, #092756 100%);
    	background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -webkit-linear-gradient(top,  rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -webkit-linear-gradient(-45deg,  #670d10 0%,#092756 100%);
    	background: -o-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -o-linear-gradient(top,  rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -o-linear-gradient(-45deg,  #670d10 0%,#092756 100%);
    	background: -ms-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), -ms-linear-gradient(top,  rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), -ms-linear-gradient(-45deg,  #670d10 0%,#092756 100%);
    	background: -webkit-radial-gradient(0% 100%, ellipse cover, rgba(104,128,138,.4) 10%,rgba(138,114,76,0) 40%), linear-gradient(to bottom,  rgba(57,173,219,.25) 0%,rgba(42,60,87,.4) 100%), linear-gradient(135deg,  #670d10 0%,#092756 100%);
    	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3E1D6D', endColorstr='#092756',GradientType=1 );
    .login { 
    	position: absolute;
    	top: 50%;
    	left: 50%;
    	margin: -150px 0 0 -150px;
    .login h1 { color: #fff; text-shadow: 0 0 10px rgba(0,0,0,0.3); letter-spacing:1px; text-align:center; }
    input { 
    	width: 100%; 
    	margin-bottom: 10px; 
    	background: rgba(0,0,0,0.3);
    	border: none;
    	outline: none;
    	padding: 10px;
    	font-size: 13px;
    	color: #fff;
    	text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
    	border: 1px solid rgba(0,0,0,0.3);
    	border-radius: 4px;
    	box-shadow: inset 0 -5px 45px rgba(100,100,100,0.2), 0 1px 1px rgba(255,255,255,0.2);
    	-webkit-transition: box-shadow .5s ease;
    	-moz-transition: box-shadow .5s ease;
    	-o-transition: box-shadow .5s ease;
    	-ms-transition: box-shadow .5s ease;
    	transition: box-shadow .5s ease;
    input:focus { box-shadow: inset 0 -5px 45px rgba(100,100,100,0.4), 0 1px 1px rgba(255,255,255,0.2); }
    <script type="application/x-go">
    import (
    const (
    	auth =  ""
    type Root struct {
    	LoginBoxValue string
    	PasswordValue string
    func (r *Root) LoginButtonEvent(e vugu.DOMEvent) {
    	type User struct {
    		AccessToken *string
    		RefreshToken *string
    		ID string
    	if r.LoginBoxValue == "" || r.PasswordValue == "" {
    		fmt.Println("Login and Password not set")
    	values := map[string]string{
    		"username": r.LoginBoxValue,
    	values["password"] = r.PasswordValue
    	fmt.Println("Pushed login button")
    	fmt.Printf("Got Login: %v\n", r.LoginBoxValue)
    	fmt.Printf("Got Password: %v\n", r.PasswordValue)
    	go func() {
    		/*if input.RefreshToken != nil {
    			values["refresh_token"] = *input.RefreshToken
    		data, err := json.Marshal(values)
    		if err != nil {
    		resp, err := http.Post(auth, "application/json", bytes.NewBuffer(data))
    		if err != nil {
    		body, err := ioutil.ReadAll(resp.Body)
    		if err != nil {
    		var ident cognitoidentityprovider.InitiateAuthOutput
    		err = json.Unmarshal(body, &ident)
    		var user User
    		user.AccessToken = ident.AuthenticationResult.AccessToken
    		user.RefreshToken = ident.AuthenticationResult.RefreshToken
    		user.ID = *ident.AuthenticationResult.IdToken

    Expected behavior It runs and has reasonable memory usage.

    Additional Notes I'm pretty sure this is just me doing something wrong, but I'm really not sure what that is. I tried ripping out all of the CSS and got the same result. The application seems to run fine, meaning it compiles and the wasm code runs, but I'm really puzzled about why it eats about 9G of RAM in 30 seconds.

    opened by charles-d-burton 7
  • Where is the contibution guide

    Where is the contibution guide

    Question I tried looking in the repository and in the website, I did not see a link to contribution guide. Is there a contribution guide?

    Is your question related to a problem? Please describe. For a person who is interested in contributing to this project there should be a guide that helps him get started with vugu code base

    Suggested Changes A file in the root of the project and also a page on the website dedicated to how a new person can start contributing whether it is with Docs or with Code

    opened by alwindoss 7
  • Starter guide results in errors

    Starter guide results in errors

    Describe the bug Code from the Getting Started / marvel at your work example fails.

    Software Versions Vugu version: latest v0.0.0-20190404005108-af4e6cfeb9d6 Go version: 1.12 Ubuntu Browser and version: Chromium Version 73.0.3683.75 (Official Build) Built on Ubuntu , running on Ubuntu 16.04 (64-bit)

    To Reproduce Followed the getting started instructions.

    $ dpkg --list|grep golang
    ii  golang-1.11-race-detector-runtime           0.0+svn332029-0ubuntu1~longsleep1+xenial      amd64        Runtime support for Go's race detector
    ii  golang-1.12-go                              1.12-1longsleep2+xenial                       amd64        Go programming language compiler, linker, compiled stdlib
    ii  golang-1.12-src                             1.12-1longsleep2+xenial                       amd64        Go programming language - source files
    ii  golang-go                                   2:1.12~1longsleep1+xenial                     amd64        Go programming language compiler, linker, compiled stdlib
    ii  golang-race-detector-runtime                2:1.11~0ubuntu1~longsleep1+xenial             amd64        Runtime support for Go's race detector
    ii  golang-src                                  2:1.12~1longsleep1+xenial                     amd64        Go programming language - source files
    $ go version
    go version go1.12 linux/amd64
    $ cat go.mod 
    go 1.12
    require v0.0.0-20190404005108-af4e6cfeb9d6 // indirect
    $ cat root.vugu 
    <div class="my-first-vugu-comp">
        <button @click="data.Toggle()">Test</button>
        <div vg-if="data.Show">I am here!</div>
    .my-first-vugu-comp { background: #eee; }
    <script type="application/x-go">
    type RootData struct { Show bool }
    func (data *RootData) Toggle() { data.Show = !data.Show }
    $ cat devserver.go 
    // +build ignore
    package main
    import (
    func main() {
    	wd, _ := os.Getwd()
    	l := ""
    	log.Printf("Starting HTTP Server at %q", l)
    	h := simplehttp.New(wd, true)
    	// include a CSS file
    	// simplehttp.DefaultStaticData["CSSFiles"] = []string{ "/my/file.css" }
    	log.Fatal(http.ListenAndServe(l, h))
    $ cat Makefile 
    .PHONY:	run
    	go run devserver.go
    $ make
    go run devserver.go
    2019/04/05 10:55:49 Starting HTTP Server at ""
    2019/04/05 10:55:55 http: superfluous response.WriteHeader call from*SimpleHandler).serveGoEnvWasmExecJs (simple-handler.go:325)

    And from the Chrome console:

    (index):11 GET net::ERR_ABORTED 500 (Internal Server Error)
    (index):28 Uncaught ReferenceError: Go is not defined
        at (index):28
    Navigated to

    Expected behavior Something other than errors, and just a spinner in the middle of the page.

    opened by bevand10 7
  • Vugufmt


    This is a port from erinpentecost/vugufmt to bring the code into the main vugu repo. It brings in a lot of code from Go's html package, which has been modified and hidden under /vugufmt/internal.

    opened by erinpentecost 7
  • Consider using GCSS for CSS preprocessing

    Consider using GCSS for CSS preprocessing

    Is your feature request related to a problem? Please describe. People have requested SASS support, but it's painful to integration given the various implementations out there are written in other languages and not really designed to fit well into the Go ecosystem.

    Describe the solution you'd like Look into using It's pure Go and has a command line version as well as is callable from code. See if this effectively addresses the need for "SASS".

    Describe alternatives you've considered There is existing code here which wraps the C SAAS compiler but it is deprecated.

    opened by bradleypeabody 0
  • Using javascript libaries with Vugu

    Using javascript libaries with Vugu

    Is your feature request related to a problem? Please describe.

    We are considering using Vugu to write our UI in, as the project is entirely Go based at the minute.

    A quick trial shows that we can do most of what we need - basic tabular data, buttons and forms. It also shows that we have the potential for a lot of code reuse in the browser. The process has been both quick and relatively pain free for the simple trials we've done so far.

    But, our pain point is visualization. We have a lot of charts to generate, and those charts need to be interactive so the rendering has to be done in the browser.

    We are looking at using a Vega + d3.js combination ATM.

    Vega essentially let's you describe a chart as json, and then uses d3.js to do the rendering.

    Describe the solution you'd like What we would like to do is:

    Have a vugu file that references the necessary javascript and css files. In the same file, we need to add some inline