Router implementation
Hey, just did a quick first pass on a client-side router for Vecty, open to any feedback. I still need to work out what testing looks like under GopherJS, and will probably implement history API in addition to hash routing, but I think the base API should work.
https://github.com/pdf/vectyx/tree/master/router
Thanks for filing this :) this is something I really want to look into soon.
hi, I want to rerender the body when the store changes like the todomvc example does.
p := &components.PageView{}
store.Listeners.Add(p, func() {
p.Items = store.Items
vecty.Rerender(p)
})
vecty.RenderBody(p)
I tried
r := router.New(nil)
...
b := r.Body()
store.Listeners.Add(b, func() {
vecty.Rerender(b)
})
vecty.RenderBody(b)
but I got the following error.
Uncaught Error: vecty: next child render must not equal previous child render (did the child Render illegally return a stored render variable?)
at $callDeferred (client.js:1414)
at $panic (client.js:1453)
at Object.$packages.github.com/gopherjs/vecty.HTML.ptr.restoreHTML (dom.go:175)
at Object.$packages.github.com/gopherjs/vecty.HTML.ptr.Restore (dom.go:216)
at doRestore (dom.go:336)
at Object.Rerender (dom.go:299)
at $b (client.go:22)
at Object.$packages.github.com/gopherjs/vecty/storeutil.ListenerRegistry.ptr.Fire (storeutil.go:31)
at Object.Dispatch (store.go:63)
at main (client.go:26)
at $init (client.js:33575)
at $goroutine (client.js:1473)
at $schedule (client.js:1530)
at $go (client.js:1506)
at client.js:33586
at client.js:33589
You're running into #70 / #78. I'm not sure if I've tested the router without the patch I posted in #78.
I made a repo to reproduce the bug. I haven't tested with your patch. https://github.com/newlix/todomvc
You can fetch https://github.com/pdf/vecty/tree/reuse-components or cherry-pick 22146ed23190ea1aa42ca1a165492c00d3548db2 if you want to try the patch.
I can see why the router may trigger that panic if Rerender is called when the route hasn't changed, but I think the router logic is sound if #78 can be solved - I think I'd like to wait and see what happens there before making any dramatic changes.
There's no need to duplicate work on the router. There is one that is already functioning at https://github.com/go-humble/router.
/cc @albrow who created go-humble/router, FYI, your project was mentioned here.
@xoviat this router supports nested routes, and rendering only the changed route component (provided #94 or similar is merged), plus url params - things that the humble router does not.
Experience with client-side routers in complex applications with large numbers of elements has informed me that rendering only the changed route component in particular is a worthwhile goal.
@shurcooL thanks for the heads up. Firstly, I'm totally okay with having multiple GopherJS router implementations if that's the direction the community wants to go. Ultimately it's up to the Vecty maintainers to decide what makes the most sense for the project.
Just to clarify a few things about go-humble/router:
- We recently added support for query parameters in version 0.5.
- It supports nested routes, i.e. routes of the form
"account/{account_id}/invoices/{invoice_id}". - It is view layer agnostic. I want to keep it this way, so that might be one reason it's not a good fit for you.
- It automatically uses the Browser History API if it detects support for it, and otherwise it seamlessly falls back to fragments (e.g. the
#part of a URL).
It might be worth looking into using go-humble/router as a starting point. It should be possible to hook into the callback and do whatever additional logic you want to do (e.g., re-rendering certain components). I also totally understand if you choose not to head in this direction.
Happy to answer any questions, and I'm eager to see what you decide. Vecty looks like a cool project!
@albrow to clarify - when I mentioned nested routes, I meant hierarchical nesting - this router probably has more in common with react-router than mux-style http routers. I think this is a more natural fit on the client-side since you can map routes into the DOM for nested views, and this is what allows the router to determine which sub-trees are affected by a route change, and to re-render only those. The latter would be non-trivial to achieve using the callback method in go-humble/router, which is why I put this together.
This is pretty much just a PoC currently, which is why it's not in its own repo, however I may extend and publish with a couple of features it's missing if there's interest, or if some other strategy ends up being preferred here.
I posted here mostly to generate discussion, so I appreciate the input.
@pdf Out of curiosity, do you know whether there is any meteor-equivalent library that exists?
@xoviat I'm afraid I don't have any experience with meteor.
No clue why I tagged this as long term, this seems important for 1.0.
@slimsag I don't think I'd predicate a v1.0 release of Vecty on having a canonical router implementation. Even React doesn't include one as part of core - react-router was developed entirely independently.
Respectfully, I disagree.
IMHO the React ecosystem is a mess because there are so many options and non-canonical ways to do things. This has led to the creation of projects like https://github.com/facebookincubator/create-react-app and a myriad of 'react starter kits'. Additionally the split between babel/webpack, npm/yarn, using redux or something else, etc.
There are so many choices in the React ecosystem that it's hard to start a project, especially as a beginner. I don't disagree that those choices should be offered, but there should always be one path that is deemed "official".
I feel this is similar to how Go encourages the use of the go tool rather than just using its compiler + linker and suggesting you choose between Makefiles, CMAKE, bash scripts, etc.
I think that if we do not have a batteries-included approach by 1.0, then we're not much better than React and it will be very hard to get the majority of (backend) Gophers being able to write some frontend code.
But in reality, the only difference in saying that v1.0 relies on a router, dispatcher, store, etc. is that:
- I will not publicize or encourage folks to write about Vecty on social media/blogs until then.
- I will not host documentation in a super-public area (for example, it'll be on a separate git branch).
That doesn't mean I will say "Vecty's core APIs are not stable until we get a router" though :P I think Vecty will be very useful, even for some daring production users, for quite some time before 1.0 is released.
Those goals are certainly sensible, and I appreciate the clarification of definitions. My thinking was that it may be useful to be able to communicate the core as stable, without having to have all the value-adds solidified, though I suppose the development of them may inform some design changes, so the exercise may prove worthwhile any way.
Yes, issues like #148 come to mind actually.
Currently, I view the arch-design tag as issues that may affect the core in some way (but obviously, some issues like this one I expect to affect it much less or perhaps not at all)
Once the core is stable, we can also communicate this in https://github.com/gopherjs/vecty#current-status by changing APIs will change to something like Core APIs will not change etc 😄
Just throwing this out there, but one idea could be to wrap a javascript router with a shim for 1.0 and then possibly reimplement it later in Go. It seems that re-using react router would save a significant amount of software design and it might get Vecty out the door sooner.
@xoviat that doesn't really work, I'm afraid. A router implementation is not that much work anyway.
I was wondering, what is the state of this? I would love to use vecty on a big personal project instead of vuejs, and component routing is crucial .
Neither @slimsag nor I have had any real time to dedicate to Vecty over the past couple of months I'm afraid @gernest.
What's going on with this great enhancement? Any update on this?
has anyone tried this? https://github.com/marwan-at-work/vecty-router
has anyone tried this? https://github.com/marwan-at-work/vecty-router
I do, it works quite a bit.
EDIT: to follow up on this, I just had to apply a small fix about routes duplications (https://github.com/tbruyelle/vecty-router/commit/27b1d572f0b0f2f260ac95cf1f95acf3d22ad86f), and added support for go modules and syscall/js (https://github.com/tbruyelle/vecty-router/commit/7d7405a23a3a9f7503bb4a308a064e0342173261)