Hwy is a fullstack web framework for driving a (p)react frontend with a Go backend. Includes end-to-end typesafety, file-based nested UI routing, and much more.
IMPORTANT – API Changes to Support Hono First-Class Async JSX Support (and experimental streaming)
Hono recently released their highly anticipated version 3.10.0 release, which includes first class support for async components using normal syntax (no more {await outlet()} hacks!) as well as experimental streaming and Suspense support. Incredible stuff!
Here's how to bring your app up to date:
Upgrade dependencies
Before making the changes described below, upgrade to the latest version of Hwy (all packages, >=0.7.0) and the latest version of Hono (>=3.10.0). If you're using the node server, also make sure to update @hono/node-server to at least >=1.2.3.
RootOutlet and renderRoot
Your rootOutlet no longer needs to be rendered like {await rootOutlet({ ...props })} and instead is now called RootOutlet (traditional JSX component capitalization) and can simply be used as <RootOutlet {...props} /> (no await needed).
renderRoot now takes a single object argument instead of three ordered arguments. Before, the three ordered arguments were (in order), c (Hono Context), next (Hono Next), and rootMarkup. Now it's an object with c, next, and root (same fundamental shape as before) as required properties, as well as an optional property experimentalStreaming property, which defaults to false.
Additionally, outlet components (returned in PageProps and used to render nested child routes) are similarly now capitalized and no longer need the weird async call syntax.
You can turn on experimental streaming support by flipping the experimentalStreaming property mentioned above to true (e.g., renderRoot({ ...props, experimentalStreaming: true})). This will let you add Suspense (experimental!) from Hono to your app. Streaming doesn't work well with HTMX or hx-boost at the moment, so we exported our own Suspense component from hwy core, which simply uses Hono's Suspense component for non-HTMX requests, and directly returns children for HTMX requests. Effectively, this means that you can use suspense for initial page loads, and any subsequent navigations (assuming you're using hx-boost) will be fully rendered before being swapped out by HTMX. If you want to try it, you can do this:
import { Suspense, type PageProps } from "hwy";
export default async function({ c }: PageProps) {
return (
<Suspense c={c} fallback={<div>Loading...</div>}>
<SomeAsyncChild />
</Suspense>
);
}
IMPORTANT – Other API changes
DataFunctionArgs type is now DataProps
Renames DataFunctionArgs type to DataProps. This name is more consistent with its sibling type PageProps.
As a reminder, DataProps (previously DataFunctionArgs) is the appropriate type for the single object parameter to both Hwy loaders and actions. It takes the same generics as before.
New stuff
@hwy-js/utils package
We added a new package called @hwy-js/utils that includes some new goodies. They should be considered experimental.
getFormStrings
We added a utility called getFormStrings to @hwy-js/utils. getFormStrings takes a generic of all the string literal types you expect in form data (essentially, the names of the inputs you submitted in a form) and returns them in an object. Very handy. An earlier version of this was included in templates as extractSimpleFormData. We made it a little more robust, renamed it, and tossed it in a utils package.
Usage:
const data = await getFormStrings<"email" | "password">({ c });
console.log(data);
// { email: "hi@example.com", password: "123" }
Client cookie events
We also added a brand new client cookie event helper system to the new @hwy-js/utils package. Very useful for triggering client-side toasts and stuff like that from server loaders or anywhere you have access to the Hono context object. This approach (cookie-based RPC) is a bit more robust than HX-Trigger because it will always persist across redirects (because it's cookie-based, not header-based). We'll document it eventually, but you can probably figure it out just by peaking into the source code. It's pretty cool!
More redirect options
Adds an option to the redirect helper to trigger a redirect using HX-Location instead of redirecting with Hono's c.redirect method. This will likely mostly be useful when you are calling an endpoint manually using fetch or htmx.ajax or similar. To opt in to that behavior, pass useHxRedirect: true to the redirect options arg.
Bug fixes
Fixes some bugs in the redirect helper, as well as some bugs in the data function handlers which resulted in thrown redirects not being sent. Now fixed.
Corrected some esbuild settings for browser-targeted files.
Fixes an issue where dev server exceptions weren't being appropriately handled. Practically speaking, this fixes an issue where you'd get EADDRINUSE when trying to restart your dev server. Very annoying, now fixed.
General
Removes some unused / unnecessary internal API surface.
Bumps dependencies.
Switch default dev port in newly bootstrapped projects back to 3000. The prior setting (5555) is the prisma studio default port, and it's not really necessary to try to use a unique one. The traditional 3000 is best, and users can change to whatever they want.
v0.7.0 release notes
IMPORTANT – API Changes to Support Hono First-Class Async JSX Support (and experimental streaming)
Hono recently released their highly anticipated version 3.10.0 release, which includes first class support for async components using normal syntax (no more
{await outlet()}
hacks!) as well as experimental streaming and Suspense support. Incredible stuff!Here's how to bring your app up to date:
Upgrade dependencies
Before making the changes described below, upgrade to the latest version of Hwy (all packages,
>=0.7.0
) and the latest version of Hono (>=3.10.0
). If you're using the node server, also make sure to update@hono/node-server
to at least>=1.2.3
.RootOutlet and renderRoot
rootOutlet
no longer needs to be rendered like{await rootOutlet({ ...props })}
and instead is now calledRootOutlet
(traditional JSX component capitalization) and can simply be used as<RootOutlet {...props} />
(no await needed).renderRoot
now takes a single object argument instead of three ordered arguments. Before, the three ordered arguments were (in order),c
(Hono Context),next
(Hono Next), androotMarkup
. Now it's an object withc
,next
, androot
(same fundamental shape as before) as required properties, as well as an optional propertyexperimentalStreaming
property, which defaults to false.OLD ❌
NEW ✅
Outlets
Additionally, outlet components (returned in
PageProps
and used to render nested child routes) are similarly now capitalized and no longer need the weird async call syntax.OLD ❌
NEW ✅
Much better! Thanks Hono!
Experimental Streaming and Suspense Support
experimentalStreaming
property mentioned above totrue
(e.g.,renderRoot({ ...props, experimentalStreaming: true})
). This will let you add Suspense (experimental!) from Hono to your app. Streaming doesn't work well with HTMX or hx-boost at the moment, so we exported our ownSuspense
component fromhwy
core, which simply uses Hono's Suspense component for non-HTMX requests, and directly returns children for HTMX requests. Effectively, this means that you can use suspense for initial page loads, and any subsequent navigations (assuming you're using hx-boost) will be fully rendered before being swapped out by HTMX. If you want to try it, you can do this:IMPORTANT – Other API changes
DataFunctionArgs type is now DataProps
Renames
DataFunctionArgs
type toDataProps
. This name is more consistent with its sibling typePageProps
.OLD ❌
NEW ✅
As a reminder,
DataProps
(previouslyDataFunctionArgs
) is the appropriate type for the single object parameter to both Hwy loaders and actions. It takes the same generics as before.New stuff
@hwy-js/utils package
We added a new package called
@hwy-js/utils
that includes some new goodies. They should be considered experimental.getFormStrings
We added a utility called
getFormStrings
to@hwy-js/utils
.getFormStrings
takes a generic of all the string literal types you expect in form data (essentially, the names of the inputs you submitted in a form) and returns them in an object. Very handy. An earlier version of this was included in templates asextractSimpleFormData
. We made it a little more robust, renamed it, and tossed it in a utils package.Usage:
Client cookie events
We also added a brand new client cookie event helper system to the new
@hwy-js/utils
package. Very useful for triggering client-side toasts and stuff like that from server loaders or anywhere you have access to the Hono context object. This approach (cookie-based RPC) is a bit more robust thanHX-Trigger
because it will always persist across redirects (because it's cookie-based, not header-based). We'll document it eventually, but you can probably figure it out just by peaking into the source code. It's pretty cool!More redirect options
Adds an option to the
redirect
helper to trigger a redirect usingHX-Location
instead of redirecting with Hono'sc.redirect
method. This will likely mostly be useful when you are calling an endpoint manually usingfetch
orhtmx.ajax
or similar. To opt in to that behavior, passuseHxRedirect: true
to theredirect
options arg.Bug fixes
redirect
helper, as well as some bugs in the data function handlers which resulted in thrown redirects not being sent. Now fixed.EADDRINUSE
when trying to restart your dev server. Very annoying, now fixed.General
3000
. The prior setting (5555
) is the prisma studio default port, and it's not really necessary to try to use a unique one. The traditional3000
is best, and users can change to whatever they want.