Releases: pshrmn/curi
Release list
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
matchAPI.
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
Thedetailsprop passed to the various link components never felt right. These properties (hash,queryandstate) 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 hashes).
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
cacheoption tocreateConfig. The cache allows you to re-use responses to the same location. Implementations can vary, but the cache must havegetandsetmethods.getreceives the current location and returns the cached response for the location (if one exists).setreceives a response object, which the cache should store (usingresponse.locationto 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 useprefetchwithout theprefetchaddon) - Added
<Link onClick> - Default pathname to
/if<Link>is not given aname - Prefetch addon returns
Promise.rejectis attempting togetan 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.