-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: stencil/store based router
- Router built on top of @stencil/store - No longer using router web components - Build-time static data generation
- Loading branch information
1 parent
228e1f3
commit 7b87f81
Showing
87 changed files
with
6,878 additions
and
12,740 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
dist/ | ||
www/ | ||
build/ | ||
|
||
*~ | ||
*.sw[mnpcod] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,225 @@ | ||
[![npm][npm-badge]][npm-badge-url] | ||
## Stencil Router | ||
# stencil-router-v2 | ||
|
||
A simple router, inspired by React Router v4, for Stencil apps and vanilla Web Component apps. | ||
Stencil Router V2 is an experimental new router for stencil that focus in: | ||
|
||
```jsx | ||
<stencil-router> | ||
<stencil-route-switch scrollTopOffset={0}> | ||
<stencil-route url="/" component="landing-page" exact={true} /> | ||
<stencil-route url="/demos" component="demos-page" /> | ||
<stencil-route url="/other" component="other-page" /> | ||
<stencil-route component="page-not-found" /> | ||
</stencil-route-switch> | ||
</stencil-router> | ||
- **Lightweight** (600bytes) | ||
- **Treeshakable** (not used features are not included in the final build) | ||
- **Simple**, provide the bare mininum but it make it extendable with hooks. | ||
- **No DOM**: Router is not render any extra DOM element, to keep styling simple. | ||
- **Fast**: As fast and lightweight as writing your own router with if statements. | ||
|
||
## How does it work? | ||
|
||
This router backs up the `document.location` in a `@stencil/store`, this way we can respond to changes in document.location is a much simpler, way, not more subscribes, no more event listeners events to connect and disconnect. | ||
|
||
Functional Components are the used to collect the list of routes, finally the `Switch` renders only the selected route. | ||
|
||
|
||
## Install | ||
|
||
```bash | ||
npm install stencil-router-v2 --save-dev | ||
``` | ||
|
||
## Examples | ||
|
||
```tsx | ||
import { createRouter, Route } from 'stencil-router-v2'; | ||
|
||
const Router = createRouter(); | ||
|
||
@Component({ | ||
tag: 'app-root', | ||
}) | ||
export class AppRoot { | ||
|
||
render() { | ||
return ( | ||
<Host> | ||
<Router.Switch> | ||
|
||
<Route path="/"> | ||
<h1>Welcome<h1> | ||
<p>Welcome to the new stencil-router demo</p> | ||
</Route> | ||
|
||
<Route path={/^\/account/}> | ||
<app-account></app-account> | ||
</Route> | ||
|
||
</Router.Switch> | ||
</Host> | ||
); | ||
} | ||
} | ||
``` | ||
|
||
### Redirects | ||
```tsx | ||
<Host> | ||
<Router.Switch> | ||
|
||
<Route path="/" to="/main"/> | ||
<Route path={/^account/} to="/error"/> | ||
|
||
</Router.Switch> | ||
</Host> | ||
``` | ||
|
||
### Params | ||
|
||
Route can take an optional `render` property that will pass down the params. This method should be used instead of JSX children. | ||
|
||
Regex or functional matches have the chance to generate an object of params when the URL matches. | ||
|
||
|
||
```tsx | ||
import { createRouter, Route, match } from 'stencil-router-v2'; | ||
|
||
const Router = createRouter(); | ||
|
||
<Host> | ||
<Router.Switch> | ||
|
||
<Route | ||
path={/^acc(ou)nt/} | ||
render={(params) => ( | ||
<p>{params[1]}</p> | ||
)} | ||
/> | ||
|
||
<Route | ||
path={match('/blog/:page')} | ||
render={({page}) => <blog-post page={page}>} | ||
/> | ||
|
||
<Route | ||
path={(url) => { | ||
if (url.includes('hello')) { | ||
return {user: 'hello'} | ||
} | ||
return undefined; | ||
}} | ||
render={({user}) => ( | ||
<h1>User: {user}</h1> | ||
)} | ||
/> | ||
|
||
</Router.Switch> | ||
</Host> | ||
``` | ||
Included components and all other information can be found in our [wiki]. | ||
### Links | ||
[wiki]: https://github.com/ionic-team/stencil-router/wiki | ||
The `href()` function will inject all the handles to an native `anchor`, without extra DOM. | ||
```tsx | ||
import { createRouter, Route, href } from 'stencil-router-v2'; | ||
|
||
const Router = createRouter(); | ||
|
||
<Host> | ||
<Router.Switch> | ||
|
||
<Route path="/main"> | ||
<a {...href('/main')} class="my-link">Go to blog</a> | ||
</Route> | ||
|
||
<Route path="/blog"> | ||
<a {...href('/main')}>Go to main</a> | ||
</Route> | ||
|
||
</Router.Switch> | ||
</Host> | ||
``` | ||
### Dynamic routes (guards) | ||
```tsx | ||
@Component({ | ||
tag: 'app-root', | ||
}) | ||
export class AppRoot { | ||
|
||
@State() logged = false; | ||
render() { | ||
return ( | ||
<Host> | ||
<Router.Switch> | ||
|
||
{this.logged && ( | ||
<Route path="/account"> | ||
<app-account></app-account> | ||
</Route> | ||
)} | ||
|
||
{!this.logged && ( | ||
<Route path="/account" to="/error"/> | ||
) | ||
|
||
</Router.Switch> | ||
</Host> | ||
); | ||
} | ||
} | ||
``` | ||
|
||
### Subscriptions to route changes | ||
|
||
Because the router uses `@stencil/store` its trivial to subscribe to changes in the locations, activeRoute, or even the list of routes. | ||
|
||
```tsx | ||
import { createRouter, Route } from 'stencil-router-v2'; | ||
|
||
const Router = createRouter(); | ||
|
||
@Component({ | ||
tag: 'app-root', | ||
}) | ||
export class AppRoot { | ||
componentWillLoad() { | ||
Router.onChange('url', (newValue: InternalRouterState['url'], _oldValue: InternalRouterState['url']) => { | ||
// Access fields such as pathname, search, etc. from newValue | ||
|
||
// This would be a good place to send a Google Analytics event, for example | ||
}); | ||
} | ||
|
||
render() { | ||
const activePath = Router.state.activeRoute?.path; | ||
|
||
return ( | ||
<Host> | ||
<aside> | ||
<a class={{'active': activePath === '/main'}}>Main</a> | ||
<a class={{'active': activePath === '/account'}}>Account</a> | ||
</aside> | ||
|
||
<Router.Switch> | ||
|
||
<Route path="/main"> | ||
<h1>Welcome<h1> | ||
<p>Welcome to the new stencil-router demo</p> | ||
</Route> | ||
|
||
<Route path='/account'> | ||
<app-account></app-account> | ||
</Route> | ||
|
||
</Router.Switch> | ||
</Host> | ||
); | ||
} | ||
} | ||
``` | ||
|
||
The routes state includes: | ||
|
||
```tsx | ||
url: URL; | ||
activeRoute?: RouteEntry; | ||
urlParams: { [key: string]: string }; | ||
routes: RouteEntry[]; | ||
``` | ||
|
||
[npm-badge]: https://img.shields.io/npm/v/@stencil/router.svg | ||
[npm-badge-url]: https://www.npmjs.com/package/@stencil/router |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
module.exports = { | ||
"roots": [ | ||
"<rootDir>/src" | ||
], | ||
testMatch: [ | ||
"**/__tests__/**/*.+(ts|tsx|js)", | ||
"**/?(*.)+(spec|test).+(ts|tsx|js)" | ||
], | ||
"transform": { | ||
"^.+\\.(ts|tsx)$": "ts-jest" | ||
}, | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.