npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@fleur/froute

v1.0.9

Published

Type safe and flexible router for React

Downloads

99

Readme

CI latest BundleSize License npm

Froute

CHANGELOG

Framework independent Router for React.
Can use with both Fleur / Redux (redux-thunk).

With provides Next.js subset useRouter

yarn add @fleur/froute

Features

See all examples in this spec or examples

  • Library independent
    • Works with Redux and Fleur
  • Next.js's Router subset compatiblity (useRouter, withRouter)
  • Supports dynamic import without any code transformer
  • Supports Sever Side Rendering
    • Supports preload
    • ResponseCode and Redirect component
  • Custom route resolution (for i18n support)
  • URL Builder

API Overview

Hooks

  • useRouter - Next.js subset compat hooks
    • withRouter available
  • useFrouteRouter - useRouter superset (not compatible to Next.js's useRouter)
  • useRouteComponent
  • useBeforeRouteChange(listener: () => Promise<boolean | void> | boolean | void)
    • It can prevent routing returns Promise<false> | false

The following hooks are deprecated. These features are available from useFrouteRouter.

  • useParams
  • useLocation
  • useNavigation
  • useUrlBuilder

Components

  • <Link href={string} />
  • <FrouteLink to={routeDef} params={object} query={object} /> - Type-safe routing
  • <ResponseCode status={number} />
  • <Redirect url={string} status={number = 302}

Getting started

Route definition:

export const routes = {
  index: routeOf('/').action({
    component: () => import('./pages/index'),
  }),
  user: routeOf('/users/:userId').action({
    component: () => import('./pages/user'),
    preload: (store: Store, params /* => inferred to { userId: string } */) =>
      Promise.all([ store.dispatch(fetchUser(param.userId)) ]),
  })
}

App:

import { useRouteComponent, ResponseCode } from '@fleur/froute'

export const App = () => {
  const { PageComponent } = useRouteComponent()

  return (
    <div>
      {PageComponent ? (
        <PageComponent /> 
      ) : (
        <ResponseCode status={404}>
          <NotFound />
        </ResponseCode>
      )}
    </div>
  )
}

User.tsx:

import { useRouter, buildPath } from '@fleur/froute'
import { routes, ResponseCode, Redirect } from './routes'

export default () => {
  const { query: { userId } } = useRouter()
  const user = useSelector(getUser(userId))

  if (!user) {
    return (
      <ResponseCode status={404}>
        <NotFound />
      </ResponseCode>
    )
  }

  if (user.suspended) {
    return (
      <Redirect status={301} url='/'>
        This account is suspended.
      </Redirect>
    )
  }
  
  return (
    <div>
      Hello, {user.name}!
      <br />
      <Link href={buildPath(routes.user, { userId: '2' })}>
        Show latest update friend
      </Link>
    </div>
  )
}

Server side:

import { createRouter } from '@fleur/froute'
import { routes } from './routes'

server.get("*", async (req, res, next) => {
  const router = createRouter(routes, {
    preloadContext: store
  })

  await router.navigate(req.url)
  await context.preloadCurrent();

  const content = ReactDOM.renderToString(
    <FrouteContext router={router}>
      <App />
    </FrouteContext>
  )

  // Handling redirect
  if (router.redirectTo) {
    res.redirect(router.statusCode, router.redirectTo)
  } else{
    res.status(router.statusCode)
  }
  
  const stream = ReactDOM.renderToNodeStream(
    <Html>
      {content}
    </Html>
  ).pipe(res)

  router.dispose()
})

Client side:

import { createRouter, FrouteContext } from '@fleur/froute'

domready(async () => {
  const router = createRouter(routes, {
    preloadContext: store,
  });

  await router.navigate(location.href)
  await router.preloadCurrent({ onlyComponentPreload: true })

  ReactDOM.render((
      <FrouteContext router={router}>
        <App />
      </FrouteContext>
    ),
    document.getElementById('root')
  )
})

Next.js compat status

  • Compat API via useRouter or withRouter
    • Compatible features
      • query, push(), replace(), prefetch(), back(), reload()
      • pathname is provided, but Froute's pathname is not adjust to file system route.
    • Any type check not provided from Next.js (Froute is provided, it's compat breaking)
  • Next.js specific functions not supported likes asPath, isFallback, basePath, locale, locales and defaultLocale
    • <Link /> only href props compatible but behaviour in-compatible.
      • Froute's Link has <a /> element. Next.js is not.
      • as, passHref, prefetch, replace, scroll, shallow is not supported currently.
    • pathname is return current location.pathname, not adjust to component file path base pathname.
    • router.push(), router.replace()
      • URL Object is does not support currentry
      • as argument is not supported
    • router.beforePopState is not supported
      • Use useBeforeRouteChange() hooks instead
    • router.events
      • Partially supported: routeChangeStart, routeChangeComplete, routeChangeError

        • Only url or err arguments.
        • Not implemented: err.cancelled and { shallow } flag.
      • Not implemented: beforeHistoryChange, hashChangeStart, hashChangeComplete

Why froute provides Next.js compat hooks?

It aims to migrate to Next.js from react-router or another router.

Froute's useRouter aims to provide a useRouter that is partially compatible with the Next.js useRouter, thereby guaranteeing an intermediate step in the migration of existing React Router-based applications to Next.js.

How to type-safe useRoute

Use this snippet in your app. (It's breaking to Type-level API compatibility from Next.js)

// Copy it in-your-app/useRouter.ts
import { useRouter as useNextCompatRouter } from '@fleur/froute'
export const useRouter: UseRouter = useNextCompatRouter

Usage:

// Route definition
const routes = {
  users: routeOf('/users/:id'),
}

// Typeing to `Routes`, it's free from circular dependency
export type Routes = typeof routes

// Component
import { useRouter } from './useRouter'
import { Routes } from './your-routes'

const Users = () => {
  const router = useRouter<typeof Routes['users']>()
  router.query.id // It infering to `string`.
}