Fresh 1.5: Partials, client side navigation and more

By admin

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 https://fresh.deno.dev

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

deno run -Ar https://fresh.deno.dev/update .

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={props.page} /> + <Partial

name="docs
ORG

-main"> + <Content page={props.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 https://esbuild.github.io/analyze/ 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

.