{"id":20495328,"url":"https://github.com/kevinast/feature-router","last_synced_at":"2026-04-09T07:56:41.511Z","repository":{"id":29142298,"uuid":"120330153","full_name":"KevinAst/feature-router","owner":"KevinAst","description":"Feature Based Navigation (using redux state)","archived":false,"fork":false,"pushed_at":"2022-12-07T20:37:24.000Z","size":1332,"stargazers_count":1,"open_issues_count":13,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-28T21:43:54.504Z","etag":null,"topics":["feature","feature-u","features","navigation","navigator","react","redux","router","routing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KevinAst.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-05T16:23:28.000Z","updated_at":"2023-01-16T10:19:03.000Z","dependencies_parsed_at":"2023-01-14T14:14:03.166Z","dependency_job_id":null,"html_url":"https://github.com/KevinAst/feature-router","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinAst%2Ffeature-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinAst%2Ffeature-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinAst%2Ffeature-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KevinAst%2Ffeature-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KevinAst","download_url":"https://codeload.github.com/KevinAst/feature-router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242077466,"owners_count":20068364,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["feature","feature-u","features","navigation","navigator","react","redux","router","routing"],"created_at":"2024-11-15T17:45:27.369Z","updated_at":"2025-12-31T00:54:38.197Z","avatar_url":"https://github.com/KevinAst.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# feature-router - *Feature Based Navigation (using redux state)*\n\n**feature-router** is your [feature-u] integration point to **Feature\nRoutes**!  It promotes the [`routeAspect`] _(a [feature-u] plugin)_\nthat integrates **Feature Routes** into your features.\n\n\n**Backdrop:**\n\n\u003cul\u003e\u003c!--- indentation hack for github - other attempts with style is stripped (be careful with number bullets) ---\u003e \n\n[feature-u] is a utility that facilitates feature-based project\norganization for your [react] project. It helps organize your\nproject by individual features.  [feature-u] is extendable. It\noperates under an open plugin architecture where [`Aspect`]s integrate\n**feature-u** to other framework/utilities that match your specific\nrun-time stack.\n\n\u003c/ul\u003e\n\n\n\u003c!--- Badges for CI Builds ---\u003e \n[![Build Status](https://travis-ci.org/KevinAst/feature-router.svg?branch=master)](https://travis-ci.org/KevinAst/feature-router)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/3fefa1344c8c49ebaca605525760d88a)](https://www.codacy.com/app/KevinAst/feature-router?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=KevinAst/feature-router\u0026amp;utm_campaign=Badge_Grade)\n[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/3fefa1344c8c49ebaca605525760d88a)](https://www.codacy.com/app/KevinAst/feature-router?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=KevinAst/feature-router\u0026utm_campaign=Badge_Coverage)\n[![Known Vulnerabilities](https://snyk.io/test/github/kevinast/feature-router/badge.svg?targetFile=package.json)](https://snyk.io/test/github/kevinast/feature-router?targetFile=package.json)\n[![NPM Version Badge](https://img.shields.io/npm/v/feature-router.svg)](https://www.npmjs.com/package/feature-router)\n\n\n**Overview:**\n\n\u003cul\u003e\u003c!--- indentation hack for github - other attempts with style is stripped (be careful with number bullets) ---\u003e \n\n\n**feature-router** configures **Feature Routes** through the\n[`routeAspect`] (_which is supplied to_ **feature-u**'s\n[`launchApp()`]).  This extends **feature-u**'s [`Feature`] object by\nadding support for the `Feature.route` property, referencing the\n[`routeCB()`] hook specified through the [`featureRoute()`] function.\n\n**Feature Routes** is _based on a very simple concept_: **allow the\n[redux] application state to drive the routes!** It operates through a series\nof registered functional callback hooks, which determine the active\nscreen based on an analysis of the the overall appState.  \n\nThis is particularly useful in feature-based routing, because each\nfeature can promote their own UI components in an encapsulated and\nautonomous way!\n\nBecause of this, **feature-router** is a preferred routing solution\nfor [feature-u].\n\n\u003c/ul\u003e\n\n## At a Glance\n\n- [Install](#install)\n- [Usage]\n- [A Closer Look]\n  * [Why Feature Routes?](#why-feature-routes)\n  * [How Feature Routes Work](#how-feature-routes-work)\n  * [Route Priorities]\n  * [Feature Order and Routes](#feature-order-and-routes)\n  * [Routing Precedence](#routing-precedence)\n- [Interface Points](#interface-points)\n  * [Input](#input)\n  * [Exposure](#exposure)\n  * [Error Conditions](#error-conditions)\n- [API](#api)\n  - [`routeAspect: Aspect`](#routeaspect-aspect)\n  - [`featureRoute({content, [priority]}): routeCB`](#featureroute)\n    - [`routeCB({fassets, appState}): reactElm || null`](#routecb)\n  - [`PRIORITY`]\n- [Potential Need for Polyfills](#potential-need-for-polyfills)\n\n\n\n## Install\n\n- **peerDependencies** ... you should already have these, **because\n  this is our integration point** _(but just in case)_:\n\n  ```shell\n  npm install --save feature-u\n  npm install --save react\n  npm install --save redux\n  npm install --save react-redux\n  ```\n  \u003c!--- WITH REVEAL of USAGE:\n  npm install --save feature-u    # VER: \u003e=1.0.0    USAGE: createAspect() (v1 replaces App with Fassets obj -AND- publicFace with fassets aspect)\n  npm install --save react        # VER: \u003e=0.14.0   USAGE: \u003cStateRouter\u003e component definition and it's injection into the DOM with JSX\n  npm install --save redux        # VER: \u003e=3.1.0    USAGE: indirect under-the-covers (because of the react-redux connect() usage) ... found in unit testing\n  npm install --save react-redux  # VER: \u003e=3.0.0    USAGE: connect() within \u003cStateRouter\u003e\n  NOTE: the **StateRouter** dependency is self contained\n  ---\u003e \n\n- **the main event**:\n\n  ```shell\n  npm install --save feature-router\n  ```\n\n**SideBar**: Depending on how current your target browser is\n_(i.e. it's JavaScript engine)_, you may need to polyfill your app\n_(please refer to [Potential Need for\nPolyfills](#potential-need-for-polyfills))_.\n\n\n## Usage\n\n1. Within your mainline, register the **feature-router**\n   [`routeAspect`] _(see: `**1**`)_ to **feature-u**'s\n   [`launchApp()`].\n\n   **Please note** that [`routeAspect`] has a required `fallbackElm`\n   parameter _(see: `**2**`)_ that specifies a reactElm to use when no\n   routes are in effect _(a SplashScreen of sorts)_.\n\n   **Also note** that [redux] must be present in your run-time stack,\n   because the routes ultimately analyze state managed by [redux] _(see:\n   `**3**`)_.\n\n   **src/app.js**\n   ```js\n   import {launchApp}            from 'feature-u';\n   import {createRouteAspect}    from 'feature-router'; // **1**\n   import {createReducerAspect}  from 'feature-redux';  // **3**\n   import SplashScreen           from '~/util/comp/SplashScreen';\n   import features               from './feature';\n\n   export default launchApp({\n\n     aspects: [\n\n       createRouteAspect({     // **1** and **2**\n         fallbackElm: \u003cSplashScreen msg=\"I'm trying to think but it hurts!\"/\u003e\n       }),\n\n       createReducerAspect(),  // **3**\n\n       ... other Aspects here\n     ],\n\n     features,\n\n     registerRootAppElm(rootAppElm) {\n       ReactDOM.render(rootAppElm,\n                       getElementById('myAppRoot'));\n     }\n   });\n   ```\n\n2. Within each feature that promotes UI Screens, simply register the\n   feature's route through the `Feature.route` property _(using\n   **feature-u**'s [`createFeature()`])_.\n\n   Here is a route for a `startup` feature that simply promotes a\n   SplashScreen until the system is ready.  It's route references a\n   [`routeCB()`] _(see `**4**`)_ defined through the\n   [`featureRoute()`] function _(see `**5**`)_:\n\n   **Note** that this example has a **HIGH** [route\n   priority](#route-priorities), giving it precedence over other\n   routes at a lower priority _(see: `**6**`)_.\n\n   **src/feature/startup/index.js**\n   ```js\n   import React            from 'react';\n   import {createFeature}  from 'feature-u';\n   import {featureRoute, \n           PRIORITY}       from 'feature-router';\n   import * as selector    from './state';\n   import SplashScreen     from '~/util/comp/SplashScreen';\n   \n   export default createFeature({\n\n     name:  'startup',\n\n     route: featureRoute({              // **5** \n       priority: PRIORITY.HIGH,         // **6**\n       content({fassets, appState}) {   // **4**\n         if (!selector.isDeviceReady(appState)) {\n           return \u003cSplashScreen msg={selector.getDeviceStatusMsg(appState)}/\u003e;\n         }\n         return null;  // system IS ready ... allow downstream routes to activate\n       },\n     }),\n\n     ... snip snip\n   });\n   ```\n\n   The `Feature.route` property can either reference a single\n   [`featureRoute()`] or multiple _(an array)_ with varying\n   priorities.\n\n\nThis should give you the **basic idea** of how **Feature Routes**\noperate.  The following sections _**develop a more thorough\nunderstanding**_ of **Feature Route** concepts.  _Go forth and\ncompute!_\n\n\n## A Closer Look\n\nYou may be surprised to discover that [feature-u] recommends it's own\nflavor of route management. There are so many!  Why introduce yet\nanother?\n\nAs it turns out, [feature-u] does not dictate any one\nnavigation/router solution.  You are free to use whatever\nroute/navigation solution that meets your requirements.\n - You can use the recommended **Feature Routes** _(i.e. this package)_\n - You can use XYZ navigation (_fill in the blank with your chosen solution_)\n - You can even use a combination of **Feature Routes** routes and XYZ routes\n\nLet's take a closer look at **Feature Routes**.\n\n\n### Why Feature Routes?\n\nThe **big benefit** of **Feature Routes** (_should you choose to use\nthem_) is that **it allows a feature to promote it's screens in an\nencapsulated and autonomous way**!\n\n**Feature Routes** are _based on a very simple concept_: **allow the\n[redux] application state to drive the routes!**\n\nIn feature based routing, you will not find the typical \"route path to\ncomponent\" mapping catalog, where (_for example_) some pseudo\n`route('signIn')` directive causes the SignIn screen to display, which\nin turn causes the system to accommodate the request by adjusting it's\nstate appropriately.  Rather, the appState is analyzed, and if the\nuser is NOT authenticated, the SignIn screen is automatically\ndisplayed ... **Easy Peasy!**\n\nDepending on your perspective, this approach can be **more natural**,\nbut _more importantly_ (once again), **it allows features to promote\ntheir own screens in an encapsulated and autonomous way**!\n\n\n### How Feature Routes Work\n\nEach feature _(that maintains UI screens)_ promotes it's top-level\nscreens through a `Feature.route` property _(within **feature-u**'s\n[`createFeature()`])_.\n\nA `route` is simply a function that reasons about the [redux]\nappState, and either returns a rendered component, or null to allow\ndownstream routes the same opportunity.  Basically **the first\nnon-null return wins**.\n\nIf no component is established _(after analyzing the routes from all\nfeatures)_, the router will revert to a [configured\nfallback](#fallbackelm) - **a Splash Screen of sorts** _(not typical\nbut may occur in some startup transitions)_.\n\nThe `route` directive contains one or more function callbacks\n([`routeCB()`]), as defined by the `content` parameter of\n[`featureRoute()`].  This callback has the following signature:\n\n**API:** `routeCB({fassets, appState}): reactElm || null`\n\n\n### Route Priorities\n\nA `Feature.route` may reference a single [`routeCB()`] or an array of\nmultiple [`routeCB()`]s with varying priorities.  Priorities are integer\nvalues that are used to minimize a routes registration order.  Higher\npriority routes are given precedence (i.e. executed before lower\npriority routes).  Routes with the same priority are executed in their\nregistration order.\n\nWhile priorities can be used to minimize (or even eliminate) the\nregistration order, typically an application does in fact rely on\nregistration order and can operate using a small number of priorities.\nA set of [`PRIORITY`] constants are available for your convenience\n(_should you choose to use them_).\n\nPriorities are particularly useful within [feature-u], where a given\nfeature is provided one registration slot, but requires it's route\nlogic to execute in different priorities.  In that case, the feature\ncan promote multiple routes (an array) each with their own priority.\n\nHere is a route for an `Eateries` feature (_displaying a list of\nrestaurants_) that employs two separate [`routeCB()`]s with varying\npriorities:\n\n**`src/feature/eateries/route.js`**\n```js\nimport React               from 'react';\nimport {createFeature}     from 'feature-u';\nimport {featureRoute,\n        PRIORITY}          from 'feature-router';\nimport * as sel            from './state';\nimport featureName         from './featureName';\nimport EateriesListScreen  from './comp/EateriesListScreen';\nimport EateryDetailScreen  from './comp/EateryDetailScreen';\nimport EateryFilterScreen  from './comp/EateryFilterScreen';\nimport SplashScreen        from '~/util/comp/SplashScreen';\n\nexport default createFeature({\n\n  name: featureName,\n\n  route: [\n    featureRoute({\n      priority: PRIORITY.HIGH,\n      content({fassets, appState}) {\n        // display EateryFilterScreen, when form is active (accomplished by our logic)\n        // NOTE: this is done as a priority route, because this screen can be used to\n        //       actually change the view - so we display it regardless of the state of\n        //       the active view\n        if (sel.isFormFilterActive(appState)) {\n          return \u003cEateryFilterScreen/\u003e;\n        }\n      }\n    }),\n\n    featureRoute({\n      content({fassets, appState}) {\n\n        // allow other down-stream features to route, when the active view is NOT ours\n        if (fassets.sel.getView(appState) !== featureName) {\n          return null;\n        }\n        \n        // ***\n        // *** at this point we know the active view is ours\n        // ***\n        \n        // display annotated SplashScreen, when the spin operation is active\n        const spinMsg = sel.getSpinMsg(appState);\n        if (spinMsg) {\n          return \u003cSplashScreen msg={spinMsg}/\u003e;\n        }\n        \n        // display an eatery detail, when one is selected\n        const selectedEatery = sel.getSelectedEatery(appState);\n        if (selectedEatery) {\n          return \u003cEateryDetailScreen eatery={selectedEatery}/\u003e;\n        }\n        \n        // fallback: display our EateriesListScreen\n        return \u003cEateriesListScreen/\u003e;\n      }\n    }),\n\n  ],\n\n  ... snip snip\n});\n```\n\n\n### Feature Order and Routes\n\nThe `Feature.route` aspect **may be one _rare_ characteristic that\ndictates the order of your feature registration**.  It really depends\non the specifics of your app, and how much it relies on [Route\nPriorities].\n\nWith that said, _it is not uncommon for your route logic to naturally\noperate independent of your feature registration order_.\n\n\n### Routing Precedence\n\nA **fundamental principle** to understand is that **feature based\nrouting establishes a Routing Precedence _as defined by your\napplication state_**!\n\nAs an example, an `'auth'` feature can take **routing precedence**\nover an `'xyz'` feature, by simply resolving to an appropriate screen\nuntil the user is authenticated _(say a SignIn screen or an\nauthorization splash screen during auth processing)_.\n\nThis means the the `'xyz'` feature can be assured the user is\nauthenticated!  You will never see logic in the `'xyz'` feature that\nredirects to a login screen if the user is not authenticated.  **Very\nnatural and goof-proof!!!**\n\n\n## Interface Points\n\n**feature-router** accumulates all the routes from the various\nfeatures of your app, and registers them to it's `\u003cStateRouter\u003e`\ncomponent.  The **Aspect Interface** to this process (_i.e. the inputs\nand outputs_) are documented here.\n\n### Input\n\n- The input to **feature-router** is the set of routing callback\n  hooks.  This is specified by each of your features (_that maintain\n  UI Screens_) through the `Feature.route` property, referencing\n  functions defined by the [`featureRoute()`] utility.\n\n### Exposure\n\n- **feature-router** promotes the app's active screen by injecting\n  it's `\u003cStateRouter\u003e` component at the root of your application DOM.\n  This allows your `Feature.route` hooks to specify the active screen,\n  based on your application state.\n\n- As a convenience, **feature-router** auto injects the **feature-u**\n  [`Fassets object`] as a named parameter in the\n  [`routeCB()`](#routecb) API.  This promotes full [Cross Feature\n  Communication].\n\n### Error Conditions\n\n- **routeAspect Placement** _(Aspect Order)_\n\n  The `routeAspect` must be ordered before other aspects that inject\n  content in the rootAppElm (i.e. the Aspects passed to\n  [`launchApp()`]).  The reason for this is that `\u003cStateRouter\u003e` _(the\n  underlying utility component)_ does NOT support children (by design).\n\n  When **feature-router** detects this scenario _(requiring action by\n  you)_, it will throw the following exception:\n\n  ```\n  ***ERROR*** Please register routeAspect (from feature-router) \n              before other Aspects that inject content in the rootAppElm\n              ... \u003cStateRouter\u003e does NOT support children.\n  ```\n\n- **NO Routes in Features**\n\n  When **feature-router** detects that no routes have been specified by\n  any of your features, it will (by default) throw the following\n  exception:\n\n  ```\n  ***ERROR*** feature-router found NO routes within your features\n              ... did you forget to register Feature.route aspects in your features?\n              (please refer to the feature-router docs to see how to override this behavior).\n  ```\n\n  Most likely this should in fact be considered an error _(for example\n  you neglected to specify the routes within your features)_.  **The\n  reasoning is**: _why would you not specify any routes if your using\n  **feature-router**?_\n\n  You can change this behavior by specifying the `allowNoRoutes` constructor\n  parameter _(see: [`routeAspect: Aspect`](#routeaspect-aspect))_:\n\n  ```js\n  createRouteAspect({allowNoRoutes:true})\n  ```\n\n  With this option enabled, when no routes are found, **feature-router**\n  will simply NOT be configured (accompanied with a WARNING logging\n  probe).\n\n  You can also specify your own array of routes in place of the `true`\n  value, which will be used ONLY in the scenario where no routes were\n  specified by your features.\n\n\n\n## API\n\n### routeAspect: Aspect\n\n\u003cul\u003e\u003c!--- indentation hack for github - other attempts with style is stripped (be careful with number bullets) ---\u003e \n\n```\nAPI: createRouteAspect({name:'route',\n                        fallbackElm,\n                        componentDidUpdateHook,\n                        allowNoRoutes:false}): routeAspect\n```\n\nThe `routeAspect` is the [feature-u] plugin that facilitates\n**Feature Route** integration to your features.\n\n**PARAMS**: _(**Please Note**: only named parameters are used)_\n\n- **name**: The name of this Aspect Plugin (defaults to 'route')\n\n- **fallbackElm**: The required reactElm to render when no routes\n  are in effect _(a SplashScreen of sorts)_.\n\n  This is **required**, because it would be problematic for\n  **feature-router** to devise a default.  For one thing, it doesn't\n  know your app layout. But more importantly, it doesn't know the\n  [react] platform in use _(ex: [react-web], [react-native], [expo],\n  etc.)_.\n\n- **componentDidUpdateHook**: an optional `\u003cStateRouter\u003e`\n  componentDidUpdate life-cycle hook.  When defined, it is a function\n  that is invoked during the componentDidUpdate react life-cycle\n  phase.  _This was initially introduced in support of [react-native]\n  animation ... **for example**:_\n\n  ```js\n  import {createRouteAspect} from 'feature-router';\n  import {LayoutAnimation}   from 'react-native';\n  \n  createRouteAspect({\n    ... other params (snip snip)\n    componentDidUpdateHook: () =\u003e LayoutAnimation.configureNext(LayoutAnimation.Presets.spring)\n  });\n  ```\n\n- **allowNoRoutes**: an optional boolean expression that determines\n  how to handle the situation where **NO Routes** were found in the\n  active feature set ... please refer to the **NO Routes in Features**\n  discussion in [Error Conditions](#error-conditions).\n\n\n**USAGE**:\n\n- Within your mainline, register the **feature-router**\n  `routeAspect` to **feature-u**'s [`launchApp()`].\n\n  The `fallbackElm` constructor parameter is required, and represents\n  a SplashScreen (of sorts) when no routes are in effect.\n\n- Within each feature that maintains UI Components, simply register\n  the feature's route through the `Feature.route` property _(using\n  **feature-u**'s [`createFeature()`])_.  This `Feature.route`\n  references a function defined through the [`featureRoute()`]\n  utility.\n\nPlease refer to the [Usage] section for examples of this process.\n\n\u003c/ul\u003e\n\n### featureRoute()\n\n\u003cul\u003e\u003c!--- indentation hack for github - other attempts with style is stripped (be careful with number bullets) ---\u003e \n\n**API:** `featureRoute({content, [priority]}): routeCB`\n\nEmbellish the supplied `content` function _(a [`routeCB()`])_ with a\n`routePriority` property _(a specification interpreted by **Feature\nRouter**)_ as to the order in which the set of registered routes are\nto be executed.\n\nA [`routeCB()`] reasons about the supplied [redux] appState, and\neither returns a rendered component screen, or null to allow\ndownstream routes the same opportunity.  Basically the first non-null\nreturn wins _(within all registered routes)_.\n\nPriorities are integer values that are used to minimize a routes\nregistration order.  Higher priority routes are given precedence\n(i.e. executed before lower priority routes).  Routes with the same\npriority are executed in their registration order.  While a\npriority can be any integer number, for your convenience, a small\nnumber of [`PRIORITY`] constants are provided.\n\nFor more details, please refer to [A Closer Look].\n\n**Please Note**: `featureRoute()` accepts named parameters.\n\n**Parameters**:\n\n- **content**: [`routeCB()`]\n\n  The the [`routeCB()`] to embellish.\n\n- **[priority]**: integer\n\n  The optional priority to use (DEFAULT: `PRIORITY.STANDARD` or 50).\n\n\n**Return**: [`routeCB()`]\n\n\u003cul style=\"margin-left: 2em;\"\u003e\n\nthe supplied `content` function, embellished with the specified\n`routePriority` property.\n\n\u003c/ul\u003e\n\n\u003c/ul\u003e\n\n\n### routeCB()\n\n\u003cul\u003e\u003c!--- indentation hack for github - other attempts with style is stripped (be careful with number bullets) ---\u003e \n\n**API:** `routeCB({fassets, appState}): reactElm || null`\n\nA functional callback hook (specified by [`featureRoute()`]) that\nprovides a generalized run-time API to abstractly expose component\nrendering, based on appState. \n\nA **routeCB** reasons about the supplied [redux] appState, and either\nreturns a rendered component screen, or null to allow downstream\nroutes the same opportunity.  Basically the first non-null return\n(within all registered routes) wins.\n\nThe **routeCB** also has a routePriority associated with it.  Priority\nroutes are given precedence in their execution order.  In other\nwords, the order in which a set of routes are executed\nare 1: routePriority, 2: registration order.  This is useful in\nminimizing the registration order.\n\nFor more details, please refer to [A Closer Look].\n\n**Please Note**: `routeCB()` accepts named parameters.\n\n**Parameters**:\n\n- **fassets**: [`Fassets object`]\n\n  The [`Fassets object`] used in feature cross-communication.\n\n  **SideBar**: `fassets` is actually injected by the [`routeAspect`] using\n  `\u003cStateRouter\u003e`'s namedDependencies.  However, since\n  **feature-router** is currently the only interface to\n  `\u003cStateRouter\u003e`, we document it as part of this **routeCB** API.\n\n- **appState**: Any\n\n  The top-level [redux] application state to reason about.\n\n**Return**: reactElm || null\n\n\u003cul style=\"margin-left: 2em;\"\u003e\n\na rendered component (i.e. [react] element) representing the screen to\ndisplay, or null for none (allowing downstream routes an opportunity).\n\n\u003c/ul\u003e\n\n\u003c/ul\u003e\n\n\n### PRIORITY\n\n\u003cul\u003e\u003c!--- indentation hack for github - other attempts with style is stripped (be careful with number bullets) ---\u003e \n\nThe **PRIORITY** container promotes a small number of defined\nconstants.  This is strictly a convenience, as any integer can be\nused.\n\nPriorities are integer values that are used to minimize a routes\nregistration order.  Higher priority routes are given precedence\n(i.e. executed before lower priority routes).  Routes with the same\npriority are executed in their registration order.  While a priority\ncan be any integer number, for your convenience, a small number of\n**PRIORITY** constants are provided:\n\n```js\nimport {PRIORITY} from 'feature-router';\n\n// usage:\nPRIORITY.HIGH     // ... 100\nPRIORITY.STANDARD // ...  50 ... the default (when NOT specified)\nPRIORITY.LOW      // ...  10\n```\n\nFor more information, please refer to [Route Priorities].\n\n\u003c/ul\u003e\n\n\n## Potential Need for Polyfills\n\nThe implementation of this library employs modern es2015+ JavaScript\nconstructs.  Even though the library distribution is transpiled to\n[es5](https://en.wikipedia.org/wiki/ECMAScript#5th_Edition) _(the\nleast common denominator)_, **polyfills may be required** if you are\nusing an antiquated JavaScript engine _(such as the IE browser)_.\n\nWe take the approach that **polyfills are the responsibility of the\nclient app**.  This is a legitimate approach, as specified by the [W3C\nPolyfill Findings](https://www.w3.org/2001/tag/doc/polyfills/)\n_(specifically [Advice for library\nauthors](https://www.w3.org/2001/tag/doc/polyfills/#advice-for-library-and-framework-authors))_.\n\n- polyfills should only be introduced one time _(during code expansion\n  of the app)_\n- a library should not pollute the global name space _(by including\n  polyfills at the library level)_\n- a library should not needlessly increase it's bundle size _(by\n  including polyfills that are unneeded in a majority of target\n  environments)_\n\nAs it turns out, **app-level polyfills are not hard to implement**,\nwith the advent of third-party utilities, such as babel:\n\n- simply import [babel-polyfill](https://babeljs.io/docs/en/babel-polyfill.html)\n- or use babel's\n  [babel-preset-env](https://babeljs.io/docs/en/babel-preset-env.html)\n  in conjunction with babel 7's `\"useBuiltins\": \"usage\"` option\n\n**If your target JavaScript engine is inadequate, it will generate\nnative run-time errors, and you will need to address the polyfills.**\nUnfortunately, in many cases these errors can be very obscure _(even\nto seasoned developers)_.  The following [Babel Feature\nRequest](https://github.com/babel/babel/issues/8089) _(if/when\nimplemented)_ is intended to address this issue.\n\n\n\u003c!--- *** REFERENCE LINKS *** ---\u003e \n\n\u003c!--- **feature-router** ---\u003e \n[Usage]:            #usage\n[A Closer Look]:    #a-closer-look\n[Route Priorities]: #route-priorities\n[`routeAspect`]:    #routeaspect-aspect\n[`featureRoute()`]: #featureroute\n[`routeCB()`]:      #routecb\n[`PRIORITY`]:       #priority\n\n\n\u003c!--- feature-u ---\u003e \n[feature-u]:              https://feature-u.js.org/\n[`launchApp()`]:          https://feature-u.js.org/cur/api.html#launchApp\n[`createFeature()`]:      https://feature-u.js.org/cur/api.html#createFeature\n[`expandWithFassets()`]:  https://feature-u.js.org/cur/api.html#expandWithFassets\n[`Feature`]:              https://feature-u.js.org/cur/api.html#Feature\n[`Fassets object`]:       https://feature-u.js.org/cur/api.html#Fassets\n[`Aspect`]:               https://feature-u.js.org/cur/api.html#Aspect\n[Managed Code Expansion]: https://feature-u.js.org/cur/crossCommunication.html#managed-code-expansion\n[Cross Feature Communication]: https://feature-u.js.org/cur/crossCommunication.html\n\n\u003c!--- react ---\u003e \n[react]:            https://reactjs.org/\n[react-web]:        https://reactjs.org/\n[react-native]:     https://facebook.github.io/react-native/\n[expo]:             https://expo.io/\n\n\n\u003c!--- redux ---\u003e \n[redux]:            https://redux.js.org/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevinast%2Ffeature-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkevinast%2Ffeature-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevinast%2Ffeature-router/lists"}