vaadin / router Goto Github PK
View Code? Open in Web Editor NEWSmall and powerful client-side router for Web Components. Framework-agnostic.
Home Page: https://vaadin.com/router
License: Apache License 2.0
Small and powerful client-side router for Web Components. Framework-agnostic.
Home Page: https://vaadin.com/router
License: Apache License 2.0
As a developer I want to add CSS animations to route transitions so that I can implement the common app-like visual design patterns for page transitions (like swipes).
Use the FLIP animation technique to ensure smooth 60fps animations.
As a developer I want to add sub-routes dynamically to allow non-monolithic app structures so that the teams working on different parts of the app are free to define the routing structures for their sub routes without a central coordination.
As a Polymer developer I want to do that by adding a router outlet into a bundle layout component's template (that is itself rendered in a router outlet).
DoD:
The common DoD applies.
As a developer I want to define ambiguous URL matching rules (i.e. several routes would match at the same time) so that I could have shorter URLs in my app. E.g. /company, /about and /:user instead of /company, /about and /users/:user. When the rules are ambiguous the order in which the rules are defined should determine the matching route.
DoD:
/
matches the home view, /about
matches the about view, /anything/else
matches the user view)router.setRoutes([
{ path: '/', exact: true, component: 'src/x-home-view.html' },
{ path: '/about', component: 'src/x-about-view.html' },
{ path: '/:user', component: 'src/x-user-view.html' },
]);
The common DoD applies.
As a developer I want to have a JS API to add / remove routes at the run time, so that I can add routes from a bundle or a route component.
Adding sub-routes dynamically allows non-monolithic app structures so that the teams working on different parts of the app are free to define the routing structures for their sub routes without a central coordination.
DoD:
/users/:user
route inside the /user
route action so that calling context.next()
after router.addRoutes()
would go to the new route).The common DoD applies.
As a developer I want to extract route parameters from the current URL and render the route content based on them. This story includes path parameters (/users/:userid) but not query string parameters (/users?userid=123).
As a Polymer developer I want to access route parameters in inline route templates.
DoD:
Polymer.Templatize
is defined the route parameters are available for Polymer data binding inside inline route templates both as named properties and as route.parameters
.The common DoD applies.
As a developer I want to update the browser window title when the current route changes.
While there is no special support for this use case, it is straightforward to implement via the onAfterEnter
route component lifecycle callback (see #23):
onAfterEnter() {
document.title = 'Title';
}
The Vaadin.Resolver class in the vaadin-router-core package has an API / offers a feature set similar to that of the universal-router
library. However it cannot use the existing library 'as-is' because there are also a few significant differences. Since the universal-router
library is MIT licensed it is possible to make a custom fork of it and use that in the source code of the vaadin-router-core package.
This task is to incorporate the source and the tests of the universal-router
library into the vaadin-router-core package (and remove an NPM dependency). This will set the stage for further extensions and customization.
DoD:
universal-router
packageuniversal-router
library is included into the vaadin-router-core sourceuniversal-router
package are a part of the vaadin-router-core test suiteuniversal-router
library license need to be included / distributed with the vaadin-router-core package?As a developer I want to display different content on the page depending on the current URL. As a Polymer developer I want to do that with HTML markup, but I also want to interact with the router via a JS API.
DoD:
<vaadin-router>
JS API allows<vaadin-router>
JS API can be combined with its DOM API. e.g. the routes defined in the DOM are included into the list returned by the getRoutes()
method<vaadin-router>
JS API usageThe common DoD applies.
As a developer I want to perform asynchronous operations in my route's action()
method (e.g. make a network request and return a result based on the response).
The functionality is implemented by design in #13, but the demo is missing.
DoD:
action(context)
method is a PromiseThe common DoD applies.
As a developer I want to generate URLs that link to other routes of my app, so that when I define a component template I do not have to hard-code the URLs in that template. That is, instead of defining a template like
<nav>
<a href="/myapp/users/">All Users</a>
<a href="/myapp/users/42">Your profile</a>
<nav>
I would define it like
<nav>
<a href="${Router.linkTo({path: '/users'})}">All Users</a>
<a href="${Router.linkTo({path: '/users/:userid', params: {userid: 42}})}">Your profile</a>
<nav>
DoD:
linkTo(route)
method on the Vaadin.Router
class. It accepts a route descriptor with the following properties:
path
: a string, same as any other route path (e.g. /users/:userid
)params
: a map where keys are route parameter names and / or indices, and values are parameter values (the same structure as the params
property of a location
object)name
: a string, name of a named route. Either name
or path
should be provided. If both a provided, name
is ignored and a warning is triggered.The common DoD applies.
As a developer I want in-app URLs to work in non-root deployments by default so that I do not have to change the source code for those cases.
DoD:
baseUrl
property via the options
argument<base>
tag (if any)router.baseUrl
property is a part of the public APIbaseUrl
property is available for view Web Components as location.baseUrl
/ui
and /ui/users/guest
respectively and the corresponding view Web Component is rendered without reloading the page.<base href="/ui/">
<nav>
<a href=".">Home</a>
<a href="user/guest">Profile</a>
<a href="/shop">Shop</a>
</nav>
<main></main>
<script>
const router = new Router(
document.querySelector('main'),
{baseUrl: '/ui/'} // this is optional because it's exactly the same as the <base> tag
);
router.setRoutes([
{path: '/', component: 'home-view'},
{path: '/user/:id', component: 'user-list-view'},
{path: '(.*)', component: 'not-found-view'},
]);
</script>
<base>
tag or the baseUrl
property, how to write appropriate hrefs in <a>
tags, how to use the location.baseUrl
property in view components to generate correcr in-app URLs)Investigate whether or not using the Google Closure Compiler reduces the minified gzipped bundle size for the core package. If so, switch from uglify-es onto google-closure-compiler for production builds.
DoD:
As a developer I want to handle the case when the current URL does not match any of the routes I have defined, and display fallback content in that case.
DoD:
render()
method gets rejected if no content is rendered.path='*'
. It matches any path and if it is the last in the list of routes, it works as a fallback option. (The exact syntax for the match all pattern may vary)./users/*
)/repeating///slashes/in//path
The common DoD applies.
As a developer I want to define a common parent layout for a list of child routes so that the common parts of the page layout are defined only once.
As a JavaScript developer, I want to do that purely in JS without using special additional Web Components.
DoD:
<slot>
s and light DOM childrenThe common DoD applies.
As a developer I want to display different content on the page depending on the current URL. As a JS developer I want to do that purely with JavaScript.
DoD:
import {Router} from '@vaadin/router';
const router = new Router(document.body);
router.setRoutes([
{ path: '/', component: 'x-home-view' },
{ path: '/users',
children: [
{ path: '/', component: 'x-user-list' },
{ path: '/:user', component: 'x-user-profile' }
]
},
{ path: '', component: 'x-not-found-view' }
]);
The common DoD applies.
As a developer I want to have an easy way to style differently the navigation link that leads to the currently active route in order to support the common UX pattern in navigation menus.
DoD:
active
property should automatically be updated when the current URL changesactive
property should trigger active-changed
events (non-bubbling)active
property should be set if the current path matches the href
propertyactive-path
string property is set, the active
property should be set if the current path matches the path specified in the active-path
propertyactive-path
property is set, the default is prefix-matching. It can be changed to exact matching by adding an exact
boolean propertyThe common DoD applies.
In order to make the vaadin-router-core product comparable to Vaadin UI components, Vaadin Ltd. needs to gather the same usage statistics for it as are gathered for Vaadin Web Components. The existing way of gathering it is designed for Web Components and is not designed for non-WC NPM packages. This task is to figure a way of gathering it for vaadin-router-core (or to conclude that it's not needed).
DoD:
As a developer I want to dynamically redirect users from one URL to another to support authentication flows (e.g. if the user is not authenticated /profile -> /login?return=/profile).
DoD:
redirect
property.redirect
property as a parameter to the resolve(pathnameOrContext)
method.action()
method so that it returns an object with a redirect
property.onBeforeEnter
callback.onBeforeEnter
callbackaction()
methodThe common DoD applies.
A feature-complete set of web components for client-side routing.
As a developer I want to install the vaadin/vaadin-router
package from Bower so that I can use <vaadin-router>
in my Polymer 2 projects.
bower install --save vaadin/vaadin-router
works (installs a package)vaadin/vaadin-router
package contains HTML imports for the Polymer 2 versions of web components (vaadin-router, vaadin-route, etc) and the UMD bundle from the @vaadin/router
package (without the Polymer 3 versions of web components)vaadin/vaadin-router
package does not contain unnecessary files (tests, demos, linter configs, etc)As a developer I want to use Vaadin Router with Polymer-based route components.
DoD:
The common DoD applies.
As a developer I want route bundle URLs to work in non-root deployments by default so that I do not have to change the source code for those cases.
In order to ensure the required product quality level there should be continuous automatic quality control.
DoD:
master
branch there is a full check:As Flow I want Vaadin.Router to support restoring scroll position on navigation in the same way it works in Flow 1.0 so that the future versions of Vaadin Flow could switch to Vaadin.Router instead of the own implementation.
NOTE: react-router does not have any explicit support for scroll position restoration. Their position is that browsers do that by default quite well already: https://reacttraining.com/react-router/web/guides/scroll-restoration
As a developer I want to add sub-routes dynamically to allow non-monolithic app structures so that the teams working on different parts of the app are free to define the routing structures for their sub routes without a central coordination.
As a JS developer I want to do that without having to add additional web components to my app.
DoD:
config
property which can be an object or a function that returns such object synchronously or asynchronously (via a Promise)//-- routes/user.js:
export default [
{ path: '/', component: 'x-user-home' },
{ path: '/:user', component: 'x-user-profile' },
];
import {Router} from '@vaadin/router';
import userRoutes from './routes/user.js';
const router = new Router(document.body);
router.setRoutes([
{ path: '/', component: 'x-home-view' },
{ path: '/users', children: userRoutes },
{ path: '(.*)', component: 'x-not-found-view' }
]);
import {Router} from '@vaadin/router';
const router = new Router(document.body);
router.setRoutes([
{ path: '/', component: 'x-home-view' },
{ path: '/users', children: (context) => import('./routes/user.js') },
{ path: '(.*)', component: 'x-not-found-view' }
]);
The common DoD applies.
As a developer I want to add links that trigger an in-app navigation and change the current URL (without a full page reload).
DoD:
<a>
tag but instead of triggering a network request update the HTML5 History state and triggers a popstate
event.<vaadin-router-link>
elementsThe common DoD applies.
As a Polymer developer I want to define route properties declaratively using the element, and have access to all the same features that the JS API provides.
DoD:
component.main="x-home-view"
/ component.sidebar="x-home-sidebar"
bundle
property works (including the implicit component names feature)redirect
property worksThe common DoD applies.
As a developer I want to extract route parameters from the current URL and render the route content based on them. This story includes path parameters (/users/:userid) but not query string parameters (/users?userid=123).
DoD:
route.parameters
property.The common DoD applies.
As a developer I want to display different content on the page depending on the current URL.
As a Polymer developer I want to do that with HTML markup.
DoD:
<vaadin-router>
DOM API allows creating a router with a default router outlet, and setting a routes config with <vaadin-route>
elements.<vaadin-route>
element.<template>
child of a <vaadin-route>
element.<template>
element to a <vaadin-route>
<vaadin-route>
elements to a <vaadin-router>
<vaadin-router>
DOM API usage<vaadin-router>
<vaadin-route path="/">
<template>
<h1>Home</h1>
</template>
</vaadin-route>
<vaadin-route path="/users" component="x-user-list"></vaadin-route>
</vaadin-router>
The common DoD applies.
As a developer I want to install the @vaadin/router
package from npm so that I can use Vaadin.Router in my npm-based front-end projects.
DoD:
npm install --save @vaadin/router
works (installs a package)@vaadin/router
package has an ES module bundle (it works in any browser that supports static ES modules: <script type="module">
)@vaadin/router
package has an UMD bundle (it works in the browsers that do not support static ES modules: <script nomodule>
)global.Vaadin
namespace. If the namespace object does not exist, it is created. If does exist, the exports are appended into the existing object.@vaadin/router
package does not contain unnecessary files (tests, demos, linter configs, etc)As a developer I want to lazily load the bundles required to render a route, so that page load times remain low and user experience is good.
DoD:
bundle
property. If the property is set for a route, during the resolve pass the router would automatically load the bundle from the given URL before returning the route component.html
the router loads the bundle as an HTML import.js
the router loads the bundle as a ES modulerouter.setRoutes([
{
path: '/about',
bundle: 'bundles/about-bundle.html',
component: 'x-about-view'
}, {
path: '/user',
bundle: 'bundles/user-view.js',
component: 'x-user-view'
}
]);
The common DoD applies.
As a developer I want to trigger navigation imperatively from JS, and to add custom listeners for navigation events.
DoD:
go(pathname)
method that updates the browser URL, triggers a popstate event and calls the router's render(pathname)
method (returns its result).vaadin-router:route-changed
event on window
every time after completing a render passThe common DoD applies.
As a developer I want to have several sections on the page that change their content based on the current route to support the use case when both the main part of the page and the sidebar have the route-dependent content.
DoD:
component
property to be either a string or an object where property names are outlet names, and property values are components that should be rendered in the corresponding outlets.import {Router} from '@vaadin/router';
const router = new Router({
main: document.getElementById('main'),
sidebar: document.getElementById('sidebar')
});
router.setRoutes([
{ path: '/',
exact: true,
component: {
main: 'x-home-view',
sidebar: 'x-home-sidebar'
}
}
]);
Run 5 DX test sessions for the scenario created in #77. Collect the findings into https://docs.google.com/document/d/1OIvVynmfEKbHhCiwqMkiLR_IYYkcbfic0uUIfdV1U9I
As a developer I want to use Vaadin.Router with regular <a>
links. If the href
property on the link points to the same origin as the app's base URL, and Vaadin.Router is configured to listen to click events, then clicks on such links should be handled by Vaadin.Router instead of the browser's default handler (that triggers a full page reload).
As Flow I want Vaadin.Router to support using <a router-link>
links for in-app navigation so that the future versions of Vaadin Flow could switch to Vaadin.Router instead of the own implementation.
This should be an opt-in feature (i.e. the app should not include any source code for it unless it's actually used) because some non-Flow apps may choose to use <vaadin-router-link>
links instead.
DoD:
<vaadin-router-link>
s.The common DoD applies.
As a developer I want to use Vaadin Router with Stencil-based route components.
DoD:
The common DoD applies.
In order to make the vaadin-router-core a commercial product, Vaadin Ltd. needs to add a license checker to it (same as is used for commercial Vaadin web components). The existing front-end license checker is designed for Web Components and is not designed for non-WC NPM packages. This task is to figure a way of using the license checker component with vaadin-router-core.
As a developer I want to use Vaadin Router with Vue-based route components.
DoD:
The common DoD applies.
As a developer I want to control when route components are disposed after the user navigates away from them, so that I can set the right balance between resource consumption, performance and UX:
As a developer I want to extract route parameters from the current URL and render the route content based on them. This include path parameters (/users/:userId) and query string parameters (/users?sort=asc).
As a developer I want to define handlers for navigation lifecycle events for a route component:
DoD:
onBeforeEnter
method, this method is called (during the resolve pass) every time before a navigation to the component happens.onBeforeEnter
method returns something (not null
nor undefined
), that return value is used as a resolve pass result for the component (instead of the component itself).onBeforeLeave
method, this method is called (during the resolve pass) every time before a navigation to the component happens.onBeforeLeave
method returns something (not null
nor undefined
), the resolve pass ends before actually navigating to where it was going to, and that return value is used as the resolve pass result.The common DoD applies.
As a developer I want to see interactive demos for the router component on the docs page (similar to the react-router online demos).
DoD:
The common DoD does not apply.
As a developer I want to detect events when a route becomes 'active' (i.e. it gets visited in a resolve pass, while it was skipped by the previous resolve pass), and 'inactive' (i.e. an 'active' route does not get visited in a resolve pass).
While this feature might not have a direct user value, it is a prerequisite for a number of other stories.
DoD:
there is an activeRoutes
read-only array property on the router object. It is an array containing the full chain of routes that were traversed in the last render's resolve pass--from the root to a leaf. Initially it is an empty array.
the activeRoutes
array is updated to the new routes chain every time when a render pass is completed, after the router outlet content is updated.
a route object may have an inactivate
property (function (context) => Promise<RenderResult>
). During each render's resolve pass a new activeRoutes
chain is constructed (starting from the root route). As each new route is added to the new activeRoutes
chain, the new chain is compared to the last activeRoutes
chain. As long as the active routes in the new chain remain the same as they were in the last chain, no additional actions are taken. When the new active chain is about to diverge from the last active chain (i.e. when the new resolve pass is about to resolve a route which was not a part of the last resove chain), the tail of the last active route chain is 'inactivated' before the new route resolution starts.
Example:
Routes config:
[
{path: '/', component: 'x-home-view'},
{path: '/users', component: 'x-users-list-view'},
{path: '/users/new', component: 'x-new-user-view'},
{path: '/users/:user', component: 'x-user-profile-view'},
]
Last active route chain: ['/', '/users', '/users/:user']
The new pathname to render: '/users/new'
The new active route chain before calling resolveRoute()
for the '/users/new'
route: ['/', '/users']
. It matches the beginning of the last active route chain.
The '/users/new'
route, when appended to the new active routes chain, would make it diverge from the last active route chain: the 3rd item in the array is going to be different.
At that point, before calling 'resolveRoute'
for the '/users/new'
route, the tail of the last active route chain after the divergence point is 'inactivated'. It's only one route in this example: '/users/:user'
. In a generic case, all views in that chain should be inactivated in sequence starting from the end of the chain.
inactivate
property is a no-op.inactivate
property means that the function defined by that property is called with the current render context. If the inactivate
function returns a non-null, non-undefined result, the render pass ends with that result and the active route chain does not change (i.e. inactivation is prevented).'/users/sam'
to '/users'
the '/users/:user'
route should be successfully inactivated before the new view chain can become active.The common DoD applies.
As a developer I want exact route matching to be the default so that the routing config is more intuitive and wrong URLs are easier to detect.
DoD:
exact
property it matches a route only if the given pathname exactly matches the route path (trailing slashes are optional).resolveRoute
and Vaadin.Resolver
are updatedAs a developer I want to unconditionally redirect users from one URL to another so that when a page changes its URL the old URL would still work (e.g. /team -> /company/team).
DoD:
redirect
property. If a route with this property is visited during the resolve pass, the resolve pass completes with a 'redirect' result.redirect
property as a parameter to the resolve(pathnameOrContext)
method.router.setRoutes([
{ path: '/about', redirect: '/company/about' },
{ path: '/company/about', component: 'x-about-view' },
{ path: '/users/:user', component: 'x-user-view' },
{ path: '/u/:user', redirect: '/users/:user' },
]);
The common DoD applies.
As a developer I want to use Vaadin Router with SkateJS-based route components.
DoD:
The common DoD applies.
As a developer I want to review / debug the routing structure in a large app with dynamic routing, so I want to automatically generate the effective global routing table in the run time of the app (when running in the dev mode).
Implemented by design in #27 and #51.
DoD:
getRoutes()
method that returns the current routing configuration as a single JSON object.The common DoD does not apply (because this story does not introduce new code).
As a developer I want to avoid boilerplate and rely on smart defaults when defining routes config. For instance, for routes with the bundle
property if
HTMLElement
then the bundle's default export should be used as the route component by default.
If a route has both the bundle
and the component
properties, the explicit component
property should be used.
DoD:
component
property is unnecessaryrouter.setRoutes([
{
path: '/about',
bundle: './src/x-about-view.mjs',
component: 'x-about-view'
}
]);
The common DoD applies.
As a developer I want to subscribe to navigation events and prevent a transition (e.g. when navigating from a view that has unsaved data).
DoD:
cancel: true
property.inactivate()
method so that it returns an object with a cancel
property.onBeforeLeave
callback.onBeforeLeave
callbackinactivate()
methodThe common DoD applies.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.