神刀安全网

Universal Router, a middleware-style router for isomorphic JavaScript web apps

Universal Router

A simple middleware-style router for isomorphic JavaScript web apps

import Router from 'universal-router';  const router = new Router()   .route('/', () => '<h1>Welcome</h1>')   .route('/about', () => '<h1>About Us</h1>');  router.dispatch('/about').then(result => {   document.body.innerHTML = result; });

new Router() Router

Creates a new instance of the router

router.route(path, …actions) Router

Appends a new route to the internal collection

router.dispatch(path) Promise

Traverses the list of routes in the same order they were defined,  finds the first matching route, and executes its action method(s)

..where an  action is just a regular function that may, or may not, return any arbitrary data — a string, a React component, anything!

Named route parametersare captured and added to context.params

const router = new Router();  router.route('/:category/:title', (context) => {   console.log(context.params);   // => { category: 'programming', title: 'how-to-code' } });  router.dispatch('/programming/how-to-code');

URL Parameters

This functionality is powered by path-to-regexp npm module and works the same way as the routing solutions in many popular JavaScript frameworks such as Express and Koa

Context

router.dispatch({ path, …context })     Promise

In addition to the URL path string, any arbitrary data can be passed to the router’s .dispatch() method, that becomes available 

from inside the action methods

const router = new Router();  router.route('/hello', (context) => {   if (context.user) {      return `Welcome, ${context.user.name}!`;   } else {      return 'Welcome, Guest';   } });  router.dispatch({ path: '/hello', user: { name: 'John' } })   .then(result => {     console.log(result);     // => Welcome, John!   });

Async Routes

const router = new Router();  router.route('/people/:id', async ({ params: { id } }) => {   const resp = await fetch(`http://swapi.co/api/people/${id}`);   const data = await resp.json();   return `<h1>${data.name}</h1>`; });  router.dispatch({ path: '/people/1' }).then(result => {   document.body.innerHTML = result; });

The router works great with asynchronous functions out of the box!

Use Babel to transpile your code with async / await to normal JavaScript. Alternatively, stick to ES6 Promises:

router.route('/people/:id', ({ params: { id } }) => {   return fetch(`http://swapi.co/api/people/${id}`)     .then(resp => resp.json()).then(data => `<h1>${data.name}</h1>`); });

Middlewares

Any route action function may act as a middleware by calling context.next()

const router = new Router();  router.route('*', async ({ next }) => {   console.log('one');   await next();   console.log('three'); });  router.route('/hello', () => {   console.log('two');   return 'Hello, world!'; });  router.dispatch({ path: '/hello' }).then(result => {   document.body.innerText = result; });  // Prints: //   one //   two //   three

This is consistent with the middleware approaches used in Node.js, Express, Koa…

Use with React.js

Just create a middleware that’s responsible for rendering React components

const router = new Router(); const container = document.getElementById('root');  function render(context, component) {   return new Promise(resolve => {     ReactDOM.render(component, container, () => {       context.end();       resolve();     });   }); }  // Register React-specific middleware router.route('*', async (context) => {   context.render = render.bind(null, context); });  // Register route(s) router.route('/hello', ({ render }) => render(<div>Hello, world!</div>));  router.dispatch({ path: '/hello' });

Use with Node.js / Express

import express from 'express'; import Router from 'universal-router';  function render({ response, end }, component) {   const body = ReactDOM.renderToString(component);   const html = `<html><head>...</head><body>${body}</body></html>`;     response.send(html);     end();   }); }  const router = new Router();  router.route('*', async (context) => {   context.render = render.bind(null, context); }); router.route('/', ({ render }) => render(<h1>Hello, world!</h1>));   const app = express();  app.use((request, response, next) => {   router.dispatch({ path: request.path, response }).catch(err => next(err)); });  app.listen(3000);

Use with React / Relay

function render(context, props) {   return new Promise(resolve => {     ReactDOM.render(       React.createElement(RelayApp, props),       document.body, resolve);   }); }  const router = new Router();  router.route('*', async (context) => {   context.render = render.bind(null, context); });  router.route('/product/:id', ({ render, params }) => {   return render({     component: ProductPage, // <- Relay container     params,                 // <- query parameters     queries: {              // <- root queries       viewer: () => Relay.QL`query { viewer }`,       product: () => Relay.QL`query { product(id: $id) }`,     }   }); );  router.dispatch({ path: '/products/1' });

Code Splitting

This routing approach works great with code splitting

const router = new Router();  // Home page router.route('/', async ({ render }) => {   const component = await require.async('./Homepage');   render(component); });  // Profile page router.route('/:username', async ({ params, render }) => {   const [ component, data ] = await Promise.all([     require.async('./UserProfile'),     fetch(`/api/users/${params.username}`).then(x => x.json()),   ]);    if (data) {     render(component, data);   } });  router.dispatch({ path: '/john', render: /* renderer */ });

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Universal Router, a middleware-style router for isomorphic JavaScript web apps

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮