Coder Social home page Coder Social logo

ultra-router's Introduction

npm i ultra

Add pushstate navigation to your component-based web app. Integrate seamlessly with React, Preact, and Vue.

download dependencies
4.6 kb none

Benefits

  • Embrace component paradigm, stay framework agnostic
    • Use conventions to map url string to component (sub)trees
    • Independent of rendering or view layer
      • Routing should be immune to complexity introduced by framework-level abstractions (context in React for e.g.)
  • Co-locate routes to support scalability
    • Routes are data. Similar types of information are best understood if they exist in the same space.
    • On the other end, as relationships between components get more complex, it is best to leave route matching logic out of the mix.
  • Extensible
    • Composable API provides clear separation between route configuration and runtime to avail maximum reuse and target different environments
  • Compact
    • Ideal for mobile/progressive web apps
      • No runtime dependencies
      • 4.6 kb > ultra (> preact)
      • Code splitting friendly

Trade-offs

  • For modern browsers with pushstate support
  • Does not render component or fetch data
  • Relies on use of path keys (strings) to derive result
    • More complex update process involves replacing path keys throughout the app
    • Path keys (non-minified) may contribute to bloated bundles
      • Concern for apps with multiple deeply nested routes, e.g. Amazon
  • For the Developer: Overcome the notion of changing your routing code again this season, and actually following through. No pun intended.

Resources

  • Quick start (build navigation for a news website tutorial)
  • React bindings: react-ultra
  • Code examples in /examples directory
    • Vehicle shop: jsfiddle
    • Tap (intercept routing): jsfiddle
    • Loading modules and routes dynamically

To-dos

  • Create automated cross-browser test suite
  • Add Preact and Vue.js examples
  • Implement Node.js container for ultra-router

License

MIT


Handle a route or two without breaking a sweat. โš”๏ธ ULTRA

ultra-router's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

ultra-router's Issues

add support to handle spec rejections

spec reject

  • gets called after something resolved (exact or partial)
  • spec that was resolved obviously should not be rejected
  • unless the resolving handler returns false => skip rejection processing completely

spec function should accept (next, err, fail)
container should run reject only after matchers are matched/resolved

add mismatch support

miss(action, '/x', '/x/xx')

pass mismatchers to container, execute after rejects

add pause feature to override transitions, save visited

  • record and save route id to history state
  • check if route has been visited to navigate back or forward
confirm(ok, cancel, msg) {
  return window.confirm('Are you sure you want to navigate away?') ? ok() : cancel()
}
render() {
  ultra.pause(this.confirm)
  return <>
}

optimize for fast tap

default style if tag == 'a' and no style prop provided
use: {cursor: 'pointer', touchAction: 'manipulation', msTouchAction: 'manipulation'}

ref

make checks more sophisticated

  • return flattened obj instead of array
  • rename to check

match: should accept single object instead of array

c1 = check(v1,v2,v3,rx) // => {v1: f1, v2: f2, v3: f3}
c2 = check(v4,rx2) // => {v4: f4}

let m1 = match(specs, Object.assign({}, c1, c2))

make api more functional

spec('/user/:id/details')(next)
spec('/user', '/user/:id', '/user/:id/show', '/user/:id/edit')(next, err)
spec('')(next)
let c1 = checks(':id', ':date')(/\d/)
let c2 = checks(':xxx')(/\w/)
let m1 = match(<<base>>, specs, [...c1, ...c2])

let ultra = container(m1, m2, ...)(<history>)
let {stop, push, replace} = utlra

/user/abc - :id not valid, stop matching in current spec, call error of current spec

/user/007/blah - :id valid, does not match any route in current spec EXACTLY, call error of current spec

/user/007/show - :id valid, matches some route exactly, call success

/user/abc/details - matches details but fails :id validation, call error of details spec

/zzz - none of the specs match, use default

add support for querystring params

additional parameters for key value pairs
user_path(Endpoint, :show, 17, admin: true, active: false)
"/users/17?admin=true&active=false"

refactor path normalization

  • create path normalize function
  • call before processing specs
  • move path fixing code from PrefixSpec class to normalize

simplify result shape

flatten values, add ids

/:year : {exact, match, passed}
/:year/:make : {exact, match, passed}
/:year/:make/:vid : {exact, match, passed}
ids: [':year',':make', ':model']
values: ['2017','bmw','m5']

provide api for pre-match mapper

  • match function accepts a mapper func
  • mapper func always returns a pathname
    • for e.g. mapper could return pathname.concat(query/hash)
  • matcher calls mapper fn to get new pathname

add path prefix

ability to add prefix per match(er)

let specs1 = [
 spec('/:id/details')(next),
 spec('/', '/:id', '/:id/show', '/:id/edit')(next, err)
]
let c1 = checks(':id', ':date')(/\d/)
let c2 = checks(':xxx')(/\w/)
let m1 = match(specs1, [...c1, ...c2], prefix = '/user')

let specs2 = [
 spec('/:id/details')(next),
 spec('/list')(next, err)
]
let c3 = checks(':id')(/\d/)
let m2 = match(specs2, c3, prefix = '/product')

let spec3 = [ spec('/error')(next), spec('')(next) ]
let m3 = match(specs3)

let ultra = container(m1, m2, m3)(<history>)

refactor to Path class

  • handle match and validation in Path object
  • make Path object and pathKey string semantics clearer

check should be able to accept multiple rx

let specB = spec('/')(routeB)
let level1Checks = check(':level1')(/^.{2}$/, /^[^\]]*$/)
match(specB, level1Checks, '/:level1')
// errors on href="b]" or href="bbbbb"

prevent possible deadlock in listeners

client code tries to delete a handler (element of the set) while proxy is iterating over the same handlers

this may leave the app in unexpected state

  • handle this by doing soft deletes
  • use weakset to hold "deleted" handlers
  • implement custom iterator that will filter out the deleted handlers, and actually remove them from the set

support dynamic anchor tags

  • late bind on ultra push in Anchor
createListener(ultra.push.bind(null, loc))
createListener(() => getUltra().push.bind(null, loc))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.