Fresh 1.5: Partials, client side navigation and more

Created on November 12, 2023 at 10:56 am

Today DATE , we’re happy to announce the 1.5 CARDINAL release of Fresh, the fast, Deno ORG -native framework for building full stack web applications.

This release contains a brand new approach to client-side navigation that we’re calling Partials PERSON . Using HTML attributes, you can configure your Fresh apps to replace HTML in an already-loaded page using server-rendered markup, without a page reload. This style of navigation makes your app feel much more responsive, and prevents losing state in your client-side island components across page turns.

In addition to Partials, Fresh 1.5 ORG contains a number of improvements and bug fixes aimed at supporting complex UI ORG development patterns.

Ready to try it out? You can start a new Fresh project by running this command:

deno run -Ar

You can also update an existing project by running the following command in your project folder:

deno run -Ar .

Here’s an overview of what’s new in 1.5 CARDINAL . Read on for all the details, plus what to expect in the next iteration of Fresh.

Client side navigation with partials

Traditionally, client side navigation is a tricky thing to get right in web development. It usually requires lots of boilerplate and a new data loading strategy. For Fresh we wanted to solve this in a way that doesn’t require developers to change how they build websites and applications.

With Fresh 1.5 we’re releasing a new concept called Partials PERSON that makes Fresh apps feel more app-like by blending client and server-side navigation. The idea behind Partials PERSON is that you can mark areas in your page that change on navigation and Fresh will only update those. And the best part: Island LOC state is kept intact.

Notice how the search bar island on the Fresh documentation page doesn’t flicker anymore when navigating between pages.

To make this work, we only needed to change two CARDINAL things in our code:

Add the f-client-nav attribute to a container element to make any links below that node opt into client side navigation and partials Wrap the main content area with a <Partial name="content">…</Partial> component

And boom! We now have full client side navigation in our documentation! The full changes can be seen in this PR.

– import { asset, Head } from "$fresh/runtime.ts"; + import { asset, Head, Partial } from "$fresh/runtime.ts"; // …snip export default function DocsPage(props: PageProps ORG <Data>) { return ( – <div class="flex flex-col min-h TIME -screen"> + <div class="flex flex-col min-h TIME -screen" f-client-nav> – <Content page={} /> + <Partial name="docs ORG -main"> + <Content page={} /> + </Partial> </div> ) }

Behind the scenes, Fresh fetches the new page and only pulls out the relevant content out of the HTML response.

Granular partial modifications

We can optimise this pattern even further by opting into more granular partial modifications with the f-partial attribute.

– <a href="/docs/routes">Routes</a> + <a href="/docs/routes" f-partial="/partials/docs/routes">Routes</a>

When the link is clicked, we’ll navigate to /docs/routes as expected, but fetch the new content from /partials/docs/routes instead. In our case this can be a slimmed down HTML page that only returns the main content and bypasses rendering the outer document directly on the server.

export default function DocRoute ORG ( ) { return ( < Partial name = " content " > { } </ Partial > ) ; }

Applying multiple Partials in one CARDINAL single HTTP response

A neat aspect of partials in Fresh is that a response can return as many partials as desired. That way you can update multiple unrelated areas on your page in one CARDINAL single HTTP response. A scenario where this is useful are online shops for example.

export default function AddToCart ORG ( ) { return ( < > < Partial name = " cart-items " mode = " append " > { } </ Partial > < Partial name = " total-price " > < p > Total: { totalPrice } € </ p > </ Partial > </ > ) ; }

Specifying the replacement mode

You may have noticed in the previous example that we used a new mode="append" prop on the <Partial> component. The default mode is to always replace the contents of a partial, but with the mode prop you can specify how you’d like the content to be integrated into the active page. We’ve added three CARDINAL distinct merge modes:

replace – Swap out the content of the existing partial (default)

– Swap out the content of the existing partial (default) prepend – Insert the new content before the existing content

– Insert the new content before the existing content append – Insert the new content after the existing content

Personally, we’ve found that the append mode is really useful when you have an UI ORG which displays log messages or similar list-like data. Head on over to our documentation to learn more about Partials.

Easier active link styling

One CARDINAL thing we always wanted to make easier is to style active links. Most code bases we have seen so far forward the current url through a lot of components to be able to check if the href attribute of an <a> -element should be styled in a way to show that it’s the current page.

The thing is that Fresh already knows what the current URL is and can do this automatically for you. No need to manually pass along the current url. With Fresh 1.5 we’ll add the following two CARDINAL attribute to links:

data-current – Added to links with an exact path match

– Added to links with an exact path match data-ancestor – Added to links which partially match the current URL

Here is an example of how these can be styled with CSS:

a [ data-current ] { color : green ; } a [ data-ancestor ] { color : peachpuff ORG ; }

…and with twind:

< a href = " /foo " class = " [data-current]:text-green-600 " > … </ a > < a href = " /foo " class = " [data-ancestor]:font-bold " > … </ a >

Custom build targets

Internally, Fresh passes the generation of optimized frontend assets to esbuild ORG , which has a pretty cool “target” feature which allows you to specify the minimum browser versions you want to support. esbuild PERSON takes that and tries to convert newer JavaScript PRODUCT construct not supported in the specified range to something these older engines support. Since every project has different requirements, it was long overdue to expose that in our configuration.

export default defineConfig ( { build : { target : [ "chrome99" , "firefox99" , " safari15 WORK_OF_ART " ] , } , } ) ;

Head over to the esbuild documentation for a full list of possible target values.

Analyzing bundle files

With Fresh 1.5 we expose esbuild GPE ’s metafile.json file which can be used to analyze and inspect what modules are actually shipped to the browser. This file can be generated by running the build task of your project.

After the build is finished, you can inspect the meta file on which is provided by the esbuild project itself.

Thanks to Tiago Gimenes PERSON for adding this to Fresh!

Error overlay

We’ve spent a bit of time improving the developer experience as well. Fresh 1.5 CARDINAL will now render a proper error overlay and try its best to show you where the error originated from. Rest assured, this is only visible in when you run dev.ts .

Errors shown in the terminal will show you a visual indicator of where the error happened as well:

It’s a minor thing, but is has proven already useful for myself working on Fresh directly.

Other noteworthy features

Inline scripts automatically get a nonce value, which makes using Content-Security ORG Policy headers nicer

value, which makes using Content-Security ORG Policy headers nicer The Deno ORG KV OAuth plugin was moved into the Fresh repository as it’s a first ORDINAL class supported plugin – Thanks to Asher Gomez PERSON and Michael Herzner PERSON for adding this!

plugin was moved into the Fresh repository as it’s a first ORDINAL class supported plugin – Thanks to Asher Gomez PERSON and Michael Herzner PERSON for adding this! The plugin API ORG received a buildStart and buildEnd hook that is called when building respectively. We consider these two CARDINAL experimental as we’ll start exposing more things in the plugin API in the very near future and these might change.

What’s on the horizon?

With support for partials, we’re very close to shipping the View Transitions API as well. We’re also eager to make partials even more awesome! Other areas we’re thinking is new additions to our plugin API and much more.

Like in the past cycles you can follow the next iteration plan on GitHub ORG .

Connecting to Connected... Page load complete