Releases: pshrmn/curi
1.0.0!!!
Well, it certainly has taken a while, but I'm finally releasing Curi v1. No more breaking API changes!
This release includes @curi/router
, all of the React packages, all of the route interaction packages, and all of the side effect packages. The Vue and Svelte packages still need some love, so those will go to v1 at a later date.
Quality of Life Changes
Breaking Changes!
While Curi is in beta, I still don't love making breaking changes. However, as it gets closer to an "official" release, there are API fixes that I would rather make now than having to wait for v2, etc.
Apologies to anyone who has to do any large rewrites because of this, but I believe that these changes will make Curi much more approachable. I do not foresee any other large changes because this covers all of the nits I had. I am confident that Curi is in a better place because of these changes, and I hope that you agree.
- Breaking up the
match
API.
The response()
function is now moved to the top-level of a route and every()
and initial()
are grouped under the on
object. on
provides a better semantic grouping, especially for any future additions (on.unload()
?).
// before
{
match: {
initial() => {...},
every() => {...},
response() => {...}
}
}
// new
{
response() => {...},
on: {
initial() => {...},
every() => {...}
}
}
- No more "add-ons"
"Add-on" was always a bit of a strange name for functions to interact with routes because it didn't make their purpose obvious. From now on, these functions will just be called "route interactions".
Route intearctions are accessible through the router's route
property e.g. router.route.pathname("Home")
. Official route interactions are moved to @curi/route-
packages (@curi/route-active
, @curi/route-ancestors
, and @curi/route-prefetch
).
Route interactions are registered with the route
option array.
// old
import active from "@curi/addon-active";
const router = curi(history, routes, {
addons: [active()]
});
// new
import active from "@curi/route-active";
const router = curi(history, routes, {
route: [active()]
});
router.route.active("Home") // true?
route.response()
clean-up
Previously, route.response()
functions were passed a route
object with the matched route's name
, parsed params
, and the location
. These are now passed at the top-level. route
is now the object of route interactions functions (pathname()
and any you include).
{
response({ name, params, location, route }) {
const pathname = route.pathname(name, params);
}
}
The set
methods have also been removed. Instead, route.response()
should return an object. The valid properties will be merged onto the response that is emitted. Valid properties are body
, error
, status
, title
, data
, and redirectTo
. Most of these are copied verbatim, but redirectTo
uses the name
and params
it is given to form a location's pathname
.
{
response() {
return {
body: About,
title: "About Us"
};
}
}
// redirecting
{
name: "Old Route"
response({ params }) {
return {
redirectTo: {
name: "New Route",
params
}
}
}
- No more emitting misses
When no routes match a location, a response is not emitted. An application should always define its own catch-all route to handle these. The path string "(.*)"
will match everything, so it is the easiest way to make a catch-all.
const routes = [
// ...,
{
name: "Not Found",
path: "(.*)",
// ...
}
];
A console warning will be called when no routes match and describe the same fix, so any issues with this should be easy to catch.
- No more
details
Thedetails
prop passed to the various link components never felt right. These properties (hash
,query
andstate
) are now passed directly to the link components.
// before
<Link to="Yo" details={{ hash: "ahoy" }}>Howdy</Link>
// new
<Link to="Yo" hash="ahoy">Howdy</Link>
- Reworked the React
<Active>
component and dropped<Link active>
.
<Active>
now takes a render-invoked children
prop. That function will be given a boolean of whether or not it is "active". It will also receive the current response object as its second argument, which can be useful if you want to do additional active checks (e.g. compare query
objects or hash
es).
To style a <Link>
as active, it should now be rendered in an <Active>
's children
render-invoked prop.
<Active name="Home">
{active => (
<Link to="Home" className={active ? "active" : ""}>Home</Link>
)}
</Active>
A wrapper component can be used to handle lots of links that want to be styled the same way.
const ActiveLink = ({ to, params, partial = true, ...rest }) => (
<Active name={to} params={params} partial={partial}>
{active => (
<Link
to={to}
params={params}
{...rest}
className={active ? "active" : ""}
/>
)}
</Active>
Beta!
Curi is getting close to the point where its v1 API is finalized. Since the last release, it has switched to Hickory for its history implementation. Recently, it has also dropped middleware
in favor of sideEffects
(permanent subscribers). Automatic scrolling support has been added with the curi-side-effect-scroll
package and you can automatically set each route page's title using the curi-side-effect-title
package.
Revamped Addons
The 0.7.0
release of the curi
package has changed what route object is passed to addons. Previously, addons were passed the route object created by the user. Now, addons are passed the route object created internally by calling createRoute
. This allows addons to access any properties that are created for the internal route objects, such as the keys
array.
There is also a new addon package: curi-addon-active
. This compares a route to the current response object and returns true
when the comparison matches. The comparison is done by matching the route's name
against the response's name
(or sometimes the names in response.partials
). If the names match, then the param are compared.
To go along with curi-addon-active
, the <Link>
component now supports an active
prop. This allows you to style the <a>
rendered by the link when the <Link>
is "active".
The packaging
curi-react
, et al.
curi-react
has been split up into a number of smaller packages. If you want all of the React web components, you can install curi-react
. However, if you only want the <Navigator>
and <Link>
, you may just want to install curi-react-navigator
and curi-react-link
.
UMD
A UMD example has been added to the curi-experiments
package.
Also, UMD builds have been switched to Rollup. These builds are now slightly smaller. There is a little bit of work to do in optimizing these because there are some duplicate helpers, but the releases are still quite small. react-dom
makes up the vast majority (over two-thirds) of the script download size.
file | dependency of | size |
---|---|---|
curi.min.js | n/a | 7.99kB |
curi-react.min.js | n/a | 7.46kB |
15.45kB | ||
history.min.js | curi | 14.9kB |
prop-types.min.js | curi-react | 2.42kB |
32.77kB | ||
react.min.js | curi-react | 21.3kB |
react-dom.min.js | react | 129kB |
183.07kB |
Todo: Test Curi with Preact?
curi
The curi
package has had two changes:
-
Response objects now have a
key
. For browser/memory histories, this will be the same as thelocation
's key. For hash histories, it will be a randomly generated 6 character alphanumeric string. -
You can now provide a
cache
option tocreateConfig
. The cache allows you to re-use responses to the same location. Implementations can vary, but the cache must haveget
andset
methods.get
receives the current location and returns the cached response for the location (if one exists).set
receives a response object, which the cache should store (usingresponse.location
to identify the location).
Better createConfig
curi
This covers both the 0.5.0
and 0.6.0
releases of curi
.
Instead of exporting createConfig
as a named export, the createConfig
function is now the default export for curi
.
Additionally, createConfig
's third argument has changed. Instead of being an addons
array, it is now an options
object. This object currently has two valid properties: addons
and middleware
. The addons
property is the array that used to be the third argument to createConfig
. The middleware
property is an array of middleware functions.
Middleware functions are functions that get called once the response
object has been created, but prior to the subscriber functions being called. Middleware gives you the opportunity to modify the response that will be passed to the subscriber functions. A middleware function will receive the response
object as its argument and must return a response
object. The middleware functions will be called in the order they are provided in the middleware
array.
curi-middleware-query
The curi-middleware-query
package was created. It exports a middleware factory function, which assists in creating a middleware function that parses a response's location.search
to generate a query object.
No more path()
Instead of expecting you to call the path
(or parentPath
) function, the route path
property should now just be a (valid path-to-regexp
) string.
In order to pass options to path-to-regexp
, you can supply a pathOptions
property to a route.
{
name: 'Strict',
path: 'here/',
pathOptions: { strict: true }
}
If a route has a children
property, then its path will always be created with the { end: false }
option.
Little things
- Added
<Link prefetch>
(also, error if attempting to useprefetch
without theprefetch
addon) - Added
<Link onClick>
- Default pathname to
/
if<Link>
is not given aname
- Prefetch addon returns
Promise.reject
is attempting toget
an unregistered route.
An experiment
Curi is an experiment with route configurations.
I'm becoming more confident in the API, but it is still subject to change.