

























In this cycle we’ve worked on making first class Tailwind CSS support a reality and expanding our plugin API. Apart from that we spent time on various developer experience improvements.
Remember: you can start a new Fresh project by running
deno run -Ar https://fresh.deno.devor update an existing project by running
deno run -Ar https://fresh.deno.dev/updatein your project folder.
Here’s an overview of what’s new in 1.6. Read on for all the details, plus what to expect in the next iteration of Fresh.
_fresh/static.
<link>-elements and has a new configResolved hook.
It has been a long time coming and Fresh now ships with a proper Tailwind CSS plugin. It’s using the exact same npm package as you would do in Node. This means we’re putting our Twind plugin on life support and mark it as deprecated.
Tailwind CSS has many benefits over Twind, with the most important one being that Tailwind CSS is actively maintained and supports a much more polished editor experience. You’ll get some nice performance benefits too by switching over to Tailwind CSS as it only needs to generate CSS once on deployment, vs on the fly on every request with Twind.
To switch from Twind to Tailwind CSS, follow this guide in our documentation. Note that this plugin requires ahead of time builds to be set up for your project.
Thanks to Jason Gardner for prototyping the initial tailwindcss plugin integration!
We’ve expanded the capabilities for Partials to work with <form> -elements.
Similar to the existing Partials support for <a>-elements, Fresh will opt into
partials with forms when the parent element of the submitter has a “truthy”
f-client-nav attribute. This even works when the submit button is outside of
the enclosing form element.
<form id="foo"> <Partial name="slot-1"> <input type="text" value={value} name="name" /> </Partial> </form> <button type="submit" form="foo" formaction="/form" f-partial="/form" formmethod="POST" > submit </button>
With Fresh 1.6 you can now use Partials for error pages too. Previously, a partial navigation would error when the response status code was not ok. This limitation has been removed and we only check if the response content type is HTML.
While we were working on that part of the code, we also added support for following redirects automatically for partial navigations.
With Fresh 1.5 we added an error overlay during development that shows detailed
information about where the error occurred. Problem was that this overrode the
user’s _500.tsx error page. We fixed that and now the error overlay is a
proper error overlay that can be closed.
In the browser we noticed that we could improve the way we serve the JavaScript
code for islands. Previously, every island component would be moved into a
separate bundle, which would lead to many .js files being generated that are
less than <1kb. The new strategy adheres to the original files to give you much
more control on how best to bundle islands for your project. By respecting the
original files you can group related islands together and include them in the
same bundle.
Whilst we want to get rid of the manifest in the long term, we felt that we can
improve the current pain points of frequently running into merge conflicts when
adding new routes or renaming them. Previously, identifiers would be composed of
$<number> where the number part was merely incrementing. The new approach
converts the file name to a valid JavaScript identifier and only appends a
number if an existing identifier with the same name is found.
Thanks to Reed von Redwitz for bringing this over the finish line!

There are many scenarios where you’d want to generate asset files for
deployment. These could include file optimisations or generating CSS like for
the Tailwind CSS plugin. The way it works is that Fresh gives static files
residing in <project>/_fresh/static higher priority over the default
<project>/static directory.
The plugin API was an area we always wanted to improve but didn’t have the time for. With this release we set aside dedicated time to expand it with some new features users have been asking for.
Among the most exciting of them is the ability to add islands from plugins. By
specifying file paths to your island file, Fresh will treat them the same way as
if they had been placed inside the islands/ directory.
import { Plugin } from "$fresh/server.ts"; import * as path from "https://deno.land/std@0.208.0/path/mod.ts"; const __dirname = path.dirname(path.fromFileUrl(import.meta.url)); export default function myIslandPlugin(): Plugin { return { name: "my-island-plugin", islands: { baseLocation: import.meta.url, paths: [ "./plugin-islands/MyIsland.tsx", "./plugin-islands/OtherPluginIsland.tsx", ], }, }; }
Thanks to Reed von Redwitz for working out all the details.
Plugins can now add <link> -elements to add additional stylesheets or similar
things.
import { Plugin } from "$fresh/server.ts"; function MyPlugin(): Plugin { return { name: "link-inject", render(ctx) { ctx.render(); return { links: [{ rel: "stylesheet", href: "styles.css" }], }; }, }; }
Thanks to Adam Gregory for enabling this feature!
There are often scenarios where your plugin needs to apply different logic based
on the Fresh configuration. We already pass the config to onBuildStart(config)
but that is too late for other sections of the plugin API. Therefore we’ve added
a new configResolved hook similar to vite which allows you to grab the fully
resolved Fresh configuration.
import { Plugin, ResolvedFreshConfig } from "$fresh/server.ts"; function MyPlugin(): Plugin { let config: ResolvedFreshConfig; return { name: "my-cool-plugin", configResolved(resolvedConfig) { config = resolvedConfig; }, }; }
Another area we looked at to make Fresh faster, was our router. We’ve noticed some inefficiencies in the way we process and match routes, especially when a project has many static files. We added another optimisation that detects if the route has no dynamic parts and will fall back to a simple string comparisons.
Overall, with all optimisations applied we see a 4-10x speedup in route matching times on deno.com .
Not every project is served at the root domain address and a popular request
among users was to be able to serve Fresh from a sub path. Instead of hosted at
https://example.com/ it should be available under
https://example.com/foo/bar for example. This is now possible with the new
router.basePath config option.
import { defineConfig } from "$fresh/server.ts"; export default defineConfig({ router: { basePath: "/foo/bar", }, });
Thanks again to Reed von Redwitz for bringing this over the finish line!
One thing that I always felt we could do better has to do with how we type our API that users interface this. Take a look at the various middleware and route context types for example:
MiddlewareHandlerContextAppContextErrorHandlerContextHandlerContextLayoutContextUnknownHandlerContextThat’s quite a lot of types to be aware of. With recent code cleanups and simplifications of our internals we realised that they are mostly the same type. So we reduced the number of context types down to just two.
FreshContextRouteContext (for async routes/layouts/app wrapper)In the future we might be even able to reduce it further to just one. Note, that we’re still keeping the old types around as aliases to the new ones to not make this a breaking change.
In the midst of simplifying our core we noticed that our props typings were similarly complex, more than they should’ve been.
ErrorPagePropsAppPropsUnknownPagePropsLayoutPropsThose four types have been reduced to a single type:
PagePropsWe’re pretty happy with the simplifications so far as it eases the mental burden of working with Fresh.
Together with the type simplifications we made sure that the Fresh context
object is exposed everywhere. It’s now passed to middlewares and routes as well.
On top of we now pass the fully resolved Fresh config inside context, so that
you can apply different logic based on it.
As with every release there is more that I would’ve loved to be able to include in this release. The truth is that these features need a little more time to polish. Curious Deno readers might have noticed the new “precompile” JSX transform in recent Deno release notes. It’s something I spent quite a bit of time on during this cycle and something I want to bring to Fresh as soon as possible. It’s mostly a performance change in how JSX is transpiled that will speed up most Fresh sites by 2-4x.
Another thing that I’ve worked on with Bartek is HMR for Deno. The initial prototype landed in Deno 1.38 as well, but there is more work to be done to wire it up in Fresh and make it feel smooth.
And of course, there is more work to be done surrounding Partials! I really want to have a proper way to specify pending states, do error handling and expose the functionality so that you can call it from an event listener. I don’t know exactly how all of this will look like, but it’s something I really want to have a good answer for in Fresh.
The December cycle will be a bit shorter than usual due to vacations around Christmas. It’s likely that we’ll skip a feature release and only do another patch release at the end of the year. The current iteration plan can be seen in the December iteration plan
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。