by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
@imrahulpatel there are migration instructions in change log, JFYI: https://github.com/kriasoft/universal-router/releases/tag/v5.0.0
Vince Bello
@vincentbello
When following a client side route that resolves asynchronously, is there any way to hook into the UI (display some kind of spinner) to indicate that the data for the route is loading?
Vladimir Kutepov
@frenzzy
@vincentbello yes, show loader before router.resolve() and hide after route is resolved and rendered, for example:
async function navigate(pathname) {
  console.log('show loader')
  const result = await router.resolve(pathname)
  document.body.innerHTML = result
  console.log('hide loader')
}
Vince Bello
@vincentbello
ty @frenzzy !
Liz Mitchell
@asyncLiz

Hey all! I'm having a weird problem, I've got some middleware and it throws TypeError: Cannot read property 'route' of undefined instead of Error: Route not found for unknown routes:

    const router = new UniversalRouter({
      path: '/',
      async action({ next }) {
        console.log('middleware: start');
        const child = await next();
        console.log('middleware: end');
        return child;
      },
      children: [
        {
          path: '/hello',
          action() {
            console.log('route: return a result');
            return 'Hello, world!';
          }
        }
      ]
    });


    router.resolve('/hello/404');

I can't find an existing issue for this, is it a known problem?
https://jsbin.com/buzeloligu/2/edit?html,output

Vladimir Kutepov
@frenzzy
It contains the fix for the issue above
quanganhtran
@quanganhtran
@frenzzy hi, when is certain query param an array of strings?
I want to adopt TS typing but the union string | string[] is breaking existing codes
Vladimir Kutepov
@frenzzy

@quanganhtran for example for path: '/:segment+'

router.resolve('/a/b/c') // => params: { segment: ['a', 'b', 'c'] }
router.resolve('/foo')   // => params: { segment: ['foo'] }

more info here: https://github.com/pillarjs/path-to-regexp#parameter-modifiers

quanganhtran
@quanganhtran

I saw that section but it seems like the match is returned as string

const regexp = pathToRegexp('/:foo+')
regexp.exec('/bar/baz')
//=> [ '/bar/baz', 'bar/baz', index: 0, input: '/bar/baz', groups: undefined ]

Does universal-router split them by delimiter afterwards?

it is useful since param may contain encoded slashes itself like /foo%2Fbar
Vladimir Kutepov
@frenzzy
router.resolve('/1%2F2/3%2F4') // => params: { segment: ['1/2', '3/4'] }
Logan Powell
@loganpowell
Real quick question from a newb here: does universal-router's async resolution enable proper search engine crawling for SEO?
Vladimir Kutepov
@frenzzy
@loganpowell universal router support both sync and async resolution and itโ€™s not directly related to SEO. You should care about SEO separately whether you use a router or not.
Logan Powell
@loganpowell
@frenzzy thank you for the clarification. I was specifically referring to the pages ability to be crawled
LucaGabi
@LucaGabi
this code dose not trigger the router action by link click, what am I doing wrong ? please help me ..
<!DOCTYPE html>
<html lang="zxx">

<head>
   <script src="https://unpkg.com/universal-router/universal-router.min.js"></script>
</head>

<body>

   <a href="/page">page link</a>

   <script>
      const routes = {
         path: '/page',            // string or regexp or array of them, optional
         name: 'page',             // unique string, optional
         parent: null,             // route object or null, automatically filled by the router
         children: [],             // array of route objects or null, optional
         action(context, params) { // function, optional

            // action method should return anything except `null` or `undefined` to be resolved by router
            // otherwise router will throw `Page not found` error if all matched routes returned nothing
            return '<h1>The Page</h1>'
         },
         // ...
      }

      const options = {
         context: { user: null },
         baseUrl: '',
         resolveRoute(context, params) {
            debugger
            if (typeof context.route.action === 'function') {
               return context.route.action(context, params)
            }
            return undefined
         },
         errorHandler(error, context) {
            console.error(error)
            console.info(context)
            return error.status === 404
               ? '<h1>Page Not Found</h1>'
               : '<h1>Oops! Something went wrong</h1>'
         }
      }

      const router = new UniversalRouter(routes, options);
      const result = router.resolve({ pathname: '/page' })

      result.then(v=>console.log(v)) // => Page One

   </script>
</body>

</html>
Vladimir Kutepov
@frenzzy
@LucaGabi the answer is here: kriasoft/universal-router#184
Rui Carneiro
@carneiror_gitlab

Hi all! Did anyone here had "circular dependencies" issues when using universal-router and react?

// routes.ts
import React from "React";
import AdminPage from "./admin";
import HomePage from "./homepage";

export const router = new UniversalRouter([
  {
    name: "homepage",
    path: "/",
    action: () => <Homepage/>
  },
  {
    name: "admin",
    path: "/:admin",
    action: () => <AdminPage/>
  }
], {});

export const urls = generateUrls(router);

// admin.tsx
import React from "React";
import { urls } from "./routes";

const AdminPage: FunctionComponent = () => {
  const url = urls("homepage");

  return (
    <div>
      <a href={url}>Homepage</a>
      <br/>
      <h1>Hello World</h1>
    </div>
  )
};
export default AdminPage;

In this example I can't use generateUrls without a circular dependencies. Routes need Pages , Pages need Urls, Urls need Routes.

Vladimir Kutepov
@frenzzy
@carneiror_gitlab probably you can give url generator to your pages through router context without the need to import routes inside route. For example:
const routes = [ // or import routes from 'routes.js'
  { name: 'home', path: '', action: ({ url }) => <a href={url('admin')}>Go to admin page</a> },
  { name: 'admin', path: '/admin', action: () => <h1>Admin Page</h1> }
]

const router = new UniversalRouter(routes)
const url = generateUrls(router)
const { pathname } = window.location

router.resolve({ pathname, url })
Rui Carneiro
@carneiror_gitlab
It's an option. Will try! Thx @frenzzy
quanganhtran
@quanganhtran

I'm trying out version 9, but it seems that

export interface RouteParams {
    [paramName: string]: string | string[];
}

does not reflect the path params correctly. e.g. optional path can be undefined

and not sure when it is a string[]
Vladimir Kutepov
@frenzzy
@quanganhtran they are an array when there are * or + modifiers https://github.com/pillarjs/path-to-regexp#modifiers
like /:foo* or /:bar+
Vladimir Kutepov
@frenzzy
btw, there are no key for optional path at all, value can't be undefined
quanganhtran
@quanganhtran
but the indexed type does not prevent you from accessing non-existing key. it assumes all string key
gkn06
@gkn06
How to import universal router in typescript?
Vladimir Kutepov
@frenzzy
@gkn06 the same as in javascript:
import UniversalRouter from 'universal-router';

const routes = [{ path: '/demo', action: () => 'Hello!' }];
const router = new UniversalRouter(routes);
router.resolve('/demo').then(console.log);
gkn06
@gkn06
No luck ๐Ÿ˜’ am getting this error
Cannot find module 'universal-router'.ts(2307)
gkn06
@gkn06
@frenzzy its fixed. I need to set moduleResolution to node is tsconfig
thanks a lot @frenzzy
Vladimir Kutepov
@frenzzy
:tada:
genderev
@genderev
hey all
I have an app that generates divs from Javascript. After the page loads, I want each div to have its own permalink. Is this the right solution?
Right now I have an anchorlink for each div in the page, but I don't know how to make it a permalink. When I paste the url with the hash/fragment/anchor link in a new tab, its like the anchor link isn't there.
Vladimir Kutepov
@frenzzy
<div id="foo"></div> and /index.html#foo should just work
genderev
@genderev
thanks @frenzzy

I think I need this

{
        path: '/:id',
        action: (context) => `<h1>Post #${context.params.id}</h1>`
      }

I want to generate user profiles for each user based on the url query. Is that what /:id does? (if :id was a username for example)

genderev
@genderev
{
          path: '/:username',          // www.example.com/admin/users/john
          action: () => 'User Profile'
        }
I think I answered my own question
What does action: () => 'User Profile' mean?
Vladimir Kutepov
@frenzzy

@genderev the router executes action method of a route and returns its result:

import UniversalRouter from 'universal-router'

const routes = [
  { path: '/:username', action: (ctx) => `<h1>User Profile: ${ctx.params.username}</h1>` },
]

const router = new UniversalRouter(routes)

router.resolve({ pathname: '/genderev' }).then(result => {
  document.body.innerHTML = result
  // renders: <h1>User Profile: genderev</h1>
})

https://github.com/kriasoft/universal-router/blob/master/docs/getting-started.md

genderev
@genderev
Awesome. How do you render more complex things? For example, if you want to add CSS.
Vladimir Kutepov
@frenzzy
@genderev check out https://github.com/kriasoft/react-starter-kit and https://github.com/kriasoft/react-firebase-starter
they both use universal-router and shows how you can use it
genderev
@genderev
Do you think they're useful if you're using neither Firebase nor React?
Vladimir Kutepov
@frenzzy
If you are looking for more complex examples, then yes, why not
dpyzo0o
@dpyzo0o
Does anyone has a working demo using create-react-app with universal-router?
Vladimir Kutepov
@frenzzy
@dpyzo0o as far as I know https://github.com/kriasoft/react-firebase-starter uses both CRA and UR
dpyzo0o
@dpyzo0o
@frenzzy Thanks