-
Notifications
You must be signed in to change notification settings - Fork 396
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: The Official Router™ #3134
Comments
I've applied a router in ScadaJS, by using the "Component-based" approach. At the end, a router design will have to answer the following questions at least:
IMHO, a router is both easy to implement (either from scratch or by integrating a 3rd party router) and very application specific. The hard part is making the design decisions. So it won't worth it. I'm not sure, but it might add a little more complexity to the design decisions (which makes it more application specific) when it comes to async components. (eg. How will it handle the async component fetching process?) |
I will answer the question I have integrated Page.js with Ractive, bundling the two as a single tool*. *although always available, it was never really officially launched, and today I'm remaking it with Svelte before finally launching, transforming it into a development tool It followed the "config-based" routing approach, and the syntax for the (still available) Ractive version was: ...
<body>
<script src='js/altiva.min.js'></script>
<script>
var app = new Altiva ()
/* Here you define the dynamic areas that will host comonents */
app.sessions( [ 'header', 'content', 'footer', 'modals' ] )
app.route( '/',
{
header: 'Menu'
content: 'Feed'
footer: 'NewFooter'
});
app.route( '/login',
{
content: 'Login'
modals: 'ErrorModal'
});
app.start();
</script>
</body>
... Internally, it registers all the components used in each route and create functions (only once in runtime) that asynchronously load every (not already loaded) component for each route. Each of these functions are passed to page.js, so after this integration, everything runs automatically. Obs 1: my code level if far lower than yours, even more two years ago when I have made this tool, so if you take a look in my code, do not be scared. I know that I have a lot to learn and improve 😬 I'm working to do something better in the second version, with everything that I have learned since then, but it's based on Svelte. Obs 2: The tool isn't small (82 kB gzipped) since there are also other features in it, like code compatibility with both browsers and mobile environments (including Cordova, Cocoon and others), already included and transparent PouchDB functionality with Ractive variables, including auto sync with CouchDB servers, ajax functionality, JWT authentication, and other things. |
This is one of those things that's going to vary pretty widely based on preferences, but I think we should probably have something that's set up to be beginner friendly. At this point, Ractive's biggest draw is probably how easy it is to get started, while still being not too overly huge and still reasonably fast. It also scales pretty well from hello world to medium-sized app (on an enterprise scale - up to a hundred or so major views pulled in async), though I'd be surprised if a generic router would make it that far. Given that, I really like the declarative approach where you start with a shell and use sub-component-ish things to wire up routes. Here's what just popped out of my head, so it may be crazy: <shell>
<left>
{{#if ~/user.loggedIn}}
<menu>...base menu...</menu>
<route bind-match='/^\/foo/'>...menu to show if in /foo/ sub...</route>
{{else}}
<route not-match="/log/in" redirect="/log/in" />
{{/if}}
</left>
<center>
<route match="/log/in">
...login form...
</route>
<route match="/foo/bar" view="./foo/BarList" bind-list="~/bars" />
<route match="/foo/bar/:id" view="./foo/Bar" bind-bar="getBar(route.id)" />
<route-target />
<footer>
<route match="/">...footer content when at root route...</route>
</footer>
</center>
</shell> That example's a bit all over the place, but it illustrates content rendered on route match, (possibly) async loading of view components, and binding view data based on a route-local variable. I don't think it would be particularly hard for all of that to be feasible, and I may try plop it into an extension of my Shell component if I get some free cycles. Macro partials and pre-processing component templates can go a really long way to making declarative components quite comfortable to use. I think it's pretty obvious that declarative routing isn't going to scale beyond a few tens of routes at the most, so I think the routing component should also have an API that allows defining routes similar to page.js so that other middleware-ish things can be accomplished too. The only major difference between declarative routes and the API, aside from lower-level access for the API, would be that the API version wouldn't get automatic data binding, so there'd have to be special config for setting up links. Another thing I think would be really cool to have would be a way to anchor a set of routes into their own container so that they could operate independently of other containers. I think most moderately complex apps are too limited by a single route destination, so having multiple containers that could share the url would allow pseudo-independent portions of a page to be in different states at the same time while still having a representative url. That's probably beyond the scope of an Official™ router, though. |
+1 to what @evs-chris said, plus I really like some concepts of Vue router like In-Component Guards, Lazy Loading Routes, Scroll Behavior etc and the way route instance is available to all child components. |
Maybe it will be a little bit impudently, but I try to suggest one more way to implement navigation and routing. I believe that is the best way for Ractive, too. A few years ago, I've touched many-many solutions for routing, including this two ways you described. My main conclusions: "Config-based (Angular and family) " - too many boilerplate. And one more that is peculiar to both - low flexibility, you know: So, I decided to find the way, how to make it more simple and in too time more flexible. The main idea is that the client "state" is more complicated than just URL you have. Simple example, you've a modal and you want to show it by fragment in your URL "/<any_path>#myModal", but you also have one more condition - only authorized users can see it. And what are we gonna to do? Include this info into URL or check it inside the component? But Modal-component has a general purpose, so basically, we shouldn't specify it with such things. So, I've thought why not to make router state is just a usual reactive state? To make it, I use Page.js - most simple but powerful router I ever used. My first, most simple solution was something like this:
now we have reactive url state and can use it in different ways:
Besides, we can use all built-in opportunities of Ractive:
One more awesome thing is that this solution isomorphic, so we can simply use it on both - client and server. This's an example of minimum implementation: page.js, 1 adaptor, about 10 line of code. As I use my own extension above Ractive called 'ractive-app' module (200 line of code with few useful features and boring boilerplate), I wrap this router solution in plugin and use it like this:
It's similar to the Vue's plugins: https://vuejs.org/v2/guide/plugins.html, but improved. Using the plugin, we have collected solution in one separated module. p/s I know that page.js not maintained now (visionmedia/page.js#384) and it's very sad. (((( In my work, I use my own version with few insignificant improvements. If you guys will choose this solution, I think it would be great to appropriate page.js (or it's fork) to Ractive's family. Or you can replace page.js with any other router module in this solution, but my request - let's it will be isomorphic. And sorry for my bad English. update: Almost forgot to say about one more advantage - Ractive's transitions work out-of-box. ))))) So, we can use them to switch between pages:
|
Has anyone used Ractive with flatiron/director - it seems mature and well supported. Or maybe riot/route? There is also Roadtrip |
Hi, Julian! I'm glad you so active recently! Yep, I tried to use Director as an isomorphic router, but it works really bad for this purpose, I think. Because it has two separate routers inside of it, for client and server sides. It's weird. Also, Flatron and Director not maintained about 2 years.
It's a nice thing, but I'm not using it yet. But I plan to test could it work on the server and if yes, maybe I switch from pagejs to this one.
Nothing know about it. Also, you can try Ractive's integrated routers like: Cheers! |
Hi again Paul. No problem - just trying to learn quickly. Thanks for listing those options. I've not got to FE routing yet in my project but I will do. |
Oh, well, since it's full of RFCs here, I'll add my opinion to this one too. To me, routing is most useful if the URLs and navigation history reflect the particular state we are in. Therefore, I would tie it to the data, not the components. Something like:
Everytime the value of
The history would be updated as well. The other way round too, upon loading the page, arguments would be read and the data initialized accordingly. It would be trivial to then implement a template like:
|
@dagnelies I think your approach is very similar to mine I described above. Btw, Page.js maintains again! |
Description:
By popular demand, this is a placeholder issue to discuss The Official Router™ for Ractive.
There's two schools of thought when it comes to routing:
Config-based (Angular and family) which defines a list of paths and the matching component to render. There's usually a special element-like item (I think they call it "outlet") defined in the template where the component will be rendered.
Component-based (React and friends) which defines the routing on the template itself. Feels very natural to Ractive, inner-HTML + yielders and all.
I'm no expert in routing (I personally use page.js/history API + redux-like state management) so I'm not entirely sure why one framework did it this way, but the other that way. I'd like to know how people prefer their routing.
The text was updated successfully, but these errors were encountered: