https://deno.com/blog/fresh-1.1
Deno
CLIBlogDeploy
Deno dinosaur flying with a lemon balloon
Fresh 1.1 - automatic JSX, plugins, DevTools, and more
September 8, 2022
Luca Casonato
---------------------------------------------------------------------
Fresh is a new full stack web framework for Deno. By default, web
pages built with Fresh send zero JavaScript to the client. The
framework has no build step which allows for an order of
magnitude improvement in development experience and deployment
times.
Today we are releasing the next significant version of Fresh. Version
1.1 brings a lot of important improvements that make Fresh easier to
use, faster, and generally more useful. Some highlights of this
release:
* Automatic JSX
* Plugins
+ Official twind plugin
* Preact Signals support
* Preact DevTools support
* Explicit rendering of 404 pages
* Stacked middleware
* Experimental Deno.serve support
* Showcase & "Made with Fresh" badges
To create a new Fresh project, you can run:
$ deno run -A -r https://fresh.deno.dev my-app
To update your project to the latest version of Fresh run the update
script from the root of your project:
$ deno run -A -r https://fresh.deno.dev/update .
In addition to updating Fresh and it's dependencies, this script can
also apply codemods to your codebase to keep it up to date with the
latest recommendations for Fresh projects. Also view the Concepts:
Updating documentation page.
Automatic JSX
New projects are now set up to use automatic mode JSX by default.
This means that you do not need the /** @jsx h */ pragma and import {
h } from "preact"; at the top of all of your files anymore. This is a
major improvement in developer experience and removes a common source
of errors for new users.
- /** @jsx h */
- import { h } from "preact";
export default function AboutPage() {
return (
About
This is the about page.
);
}
Existing projects can be updated to use automatic mode using the
codemod in the Fresh update script. Alternatively it can be manually
enabled by adding the following lines to the deno.json file in the
root of your project:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}
After doing this, you must remove all /** @jsx h */ pragmas and
import { h } from "preact"; imports from your JSX/TSX files.
Automatic and non automatic mode can not be mixed in the same
project.
Plugins
Plugins are a new way to extend Fresh's functionality without
requiring intrusive changes in Fresh itself. Right now plugins can
only be used to orchestrate rendering and inject styles and scripts
into the rendered HTML. This is useful for styling frameworks like
twind. This could also be used to do things like inject a Google
Analytics script into the page, or globally load a web component.
Plugins are defined through the plugins property in the options bag
passed to the start function in your main.ts file.
This is just the first iteration of plugins. Future versions will add
more hooks that plugins can use to extend Fresh's functionality.
Plugins will be able to add new routes, middleware, and islands to a
project in the future.
Documentation for plugins is available in the Concepts: Plugins
documentation page.
As of now only a single official plugin is available. More plugins
will be added in the future as the capabilities of the plugin system
expand.
Official twind plugin
Twind is a small Tailwind-in-JS implementation that can generate CSS
just-in-time based on the classes used in your JSX. Previous versions
of Fresh had a option to automatically configure Twind for you during
project initialization, but this resulted in significant amounts of
boilerplate.
With the new plugin system, we are now providing a first-party Fresh
plugin for Twind. This plugin automatically configures Twind for you
to minimize boilerplate in your project. Using it is as simple as:
// main.ts
import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";
+ import twindPlugin from "$fresh/plugins/twind.ts";
+ import twindConfig from "./twind.config.js";
await start(manifest, {
+ plugins: [
+ twindPlugin(twindConfig),
+ ],
});
With this new plugin, using Twind classes in your project becomes
even simpler. Previously you had to import the tw function from the
twind module and wrap all your class names in it. Now you can just
specify the class names directly in the JSX component, and the plugin
will take care of the rest.
// pages/index.tsx
- import { tw } from "@twind";
export default function IndexPage() {
return (
-
Hello, world!
+
Hello, world!
);
}
With the new plugin, Twind also works more reliably during client
side renders and is able to better resolve conflicts between server
and client rendered style sheets.
The project initialization script has been updated to use the new
Twind plugin, and now also generates all required files to be able to
use the Twind VSCode extension.
The update script can be used to update your project to use the new
Twind plugin via a codemod.
Preact Signals support
New Fresh projects are now automatically set up to use the new Preact
Signals. Signals are a new reactive state management primitive for
Preact. They are designed to be much faster than hooks and context,
while simultaneously being much more ergonomic.
Here is an example of the basic "counter" component using signals
instead of hooks.
import { useSignal } from "@preact/signals";
import { Button } from "../components/Button.tsx";
interface CounterProps {
start: number;
}
export default function Counter(props: CounterProps) {
const count = useSignal(props.start);
return (
{count}
);
}
Signals also provide an excellent way to manage shared state across
multiple islands in your Fresh project. Check out the Fresh with
Signals demo to see how this works.
For existing projects the updater script will automatically add the
@preact/signals dependency to your import map. You can also manually
add the dependency to your import map - just make sure to also update
preact-render-to-string to >=5.2.3.
Preact DevTools support
You can now use the Preact DevTools extension available for Chrome,
Firefox, and Edge to inspect the component tree of your Fresh
project.
This is a great way to debug issues with your islands and understand
how Preact is rendering your components.
To make use of this feature no additional configuration is required.
Just update to the latest version of Fresh and install the Preact
DevTools extension for your browser.
This feature is only available during development. In production the
Preact DevTools integration is not available. This is done to reduce
the amount of JavaScript that is shipped to clients.
Thank you to Marvin Hagemeister for contributing this feature, and
improving the Preact DevTools support for island based hydration.
Explicit rendering of 404 pages
It is now possible to explicitly render the 404 page from a route
handler. This can be useful if you want to render the 404 page
depending on the result of a database query, or if you do more
complex routing in your route handler.
To render a 404 page, just call ctx.renderNotFound() from your route
handler instead of calling ctx.render() or returning a custom
Response object. Just like with ctx.render() you can modify the
returned Response object before it is sent to the client.
// routes/index.ts
export const handler: Handlers = {
GET(req, ctx) {
const url = new URL(req.url);
const id = url.searchParams.get("id");
if (!id) return ctx.renderNotFound(); // return a 404 page if no id is provided
return ctx.render({ id });
},
};
// ... page component here ...
Thank you to Steven Yung for contributing this feature.
Stacked middleware
It is now possible to have multiple middleware functions for a single
middleware route. This is useful if you have multiple different
middleware functions that should all be applied for a given matcher.
This is achieved by exporting an array from the middleware file
instead of a single function.
Here is an example of a middleware module that contains two
middleware functions: one to do logging and one to add timing headers
to the response.
// routes/_middleware.ts
export const handler = [
timing,
logging,
];
async function timing(
_req: Request,
ctx: MiddlewareHandlerContext,
): Promise {
const start = performance.now();
const res = await ctx.next();
const end = performance.now();
const dur = (end - start).toFixed(1);
res.headers.set("Server-Timing", `handler;dur=${dur}`);
return res;
}
async function logging(
req: Request,
ctx: MiddlewareHandlerContext,
): Promise {
const res = await ctx.next();
console.log(`${req.method} ${req.url} ${res.status}`);
return res;
}
Thank you to @ahuigo for contributing this feature.
Experimental Deno.serve support
Deno v1.25 added a new very high performance HTTP server to Deno. You
can read more about it in the Deno 1.25 release notes. It is only
available in Deno v1.25 and later when running with the --unstable
flag.
This version of Fresh adds experimental support for using the new
Deno.serve API instead of the existing std/http server. Deno.serve is
not yet stable, so you should not use it in production. Deno.serve is
also not available on Deno Deploy, because it is still experimental.
To enable the new server you must specify experimentalDenoServe: true
in the options bag passed to the start() method in your main.ts file.
Showcase & "Made with Fresh" badges
The Fresh homepage now has a showcase section where you can find a
list of projects that are using Fresh. If you have a project using
Fresh, please add it to the list!
In addition to the showcase, we are now also providing a "Made with
Fresh" badge that you can add to your website or project README. The
badge is also available in a dark variant.
Made with Fresh
Made with Fresh(dark)
Follow these instructions to add the badge to your project: https://
github.com/denoland/fresh#badges
Deno
DeploySubhostingManualStandard LibraryThird Party ModulesBlogCompany
Jobs at DenoDeno NewsSystem StatusPrivacy Policy