惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

M
MIT News - Artificial intelligence
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
J
Java Code Geeks
G
Google Developers Blog
美团技术团队
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
腾讯CDC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
The Blog of Author Tim Ferriss
月光博客
月光博客
B
Blog
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
博客园_首页
人人都是产品经理
人人都是产品经理
aimingoo的专栏
aimingoo的专栏
Y
Y Combinator Blog
Jina AI
Jina AI
S
SegmentFault 最新的问题
H
Help Net Security
博客园 - 聂微东
Microsoft Azure Blog
Microsoft Azure Blog
Google DeepMind News
Google DeepMind News

Deno

Deno 2.8 | Deno Claw Patrol: an open-source security firewall for agents | Deno Fresh 2.3: Zero JS by default, View Transitions, and Temporal support | Deno Deno 2.7: Temporal API, Windows ARM, and npm overrides | Deno Build a dinosaur runner game with Deno, pt. 6 | Deno Build a dinosaur runner game with Deno, pt. 5 | Deno Deno Deploy is Generally Available | Deno Introducing Deno Sandbox | Deno Build a dinosaur runner game with Deno, pt. 4 | Deno Build a dinosaur runner game with Deno, pt. 3 | Deno Build a dinosaur runner game with Deno, pt. 2 | Deno React / Next.js Denial-of-Service Vulnerability: Deno Deploy users protected | Deno Deno 2.6: dx is the new npx | Deno Build a dinosaur runner game with Deno, pt. 1 | Deno React Server Functions / Next.js Vulnerability: Deno Deploy users protected | Deno My highlights from the new Deno Deploy | Deno Deno's Other Open Source Projects | Deno How Deno protects against npm exploits | Deno Help Us Raise $200k to Free JavaScript from Oracle | Deno Deno 2.5: Permissions in the config file | Deno Fresh 2.0 Graduates to Beta, Adds Vite Support | Deno Deno 2.4: deno bundle is back | Deno JavaScript™ Trademark Update | Deno What's coming to JavaScript | Deno A brief history of JavaScript | Deno Reports of Deno's Demise Have Been Greatly Exaggerated | Deno An Update on Fresh | Deno How Plaid migrated 100 services to a new database platform 5x faster with Deno | Deno Deno 2.3: Improved deno compile, local npm packages, and more | Deno Add JSR packages with pnpm and Yarn | Deno
Fresh 1.4 – Faster Page Loads, Layouts and More | Deno
Marvin Hagem · 2023-08-16 · via Deno

In this cycle we’ve focused on the overall developer experience of making it easier to use shared layouts, route-specific islands and more in Fresh.

Remember: you can start a new Fresh project by running deno run -A -r https://fresh.deno.dev or update an existing project by running deno run -A -r https://fresh.deno.dev/update . in your project folder.

  • Faster page loads with ahead-of-time compilation
  • Custom html, head and body tags
  • Layouts
  • Async layouts and async app wrapper
  • Quicker typing with define functions
  • Organise your code with Route Groups
    • Colocated islands, components and more
  • What’s on the horizon?

Faster page loads with ahead-of-time compilation

So far, Fresh has always compiled assets on the fly. This has served us well so far, as it enables lightning fast deployments with no build step, but we realised just-in-time (=JIT) rendering with large islands was noticeably slower. We arrived at a pre-compile solution that results in assets being served ~45-60x faster for a cold start of a serverless function, with minimal impact on deployment times. The savings depend on the size of the island, but even for small ones the improvements are very visible.

Here is a demonstration of the different techniques on the Fresh documentation site. The search box is a small island which weights around ~30kB.

The search box island revives nearly instantaneously with ahead of time compiled assets whereas it took 4.28s with JIT compilation.

Locally, when running the development server, Fresh will always use JIT compilation so that your sever can respond to API as soon as possible and doesn’t have to wait for asset compilation to finish.

You can opt into AOT compilation for deployments by following the ahead-of-time builds guide. Running deno task build will create a _fresh folder which holds all the generated assets.

Custom html, head and body tags

A tricky aspect in previous versions was setting the lang attribute on the <html>-tag. Up until now Fresh created the outer HTML structure up to the <body>-tag internally and you’d need to apply workarounds like creating a custom render function to modify the lang attribute.

await start(manifest, {
  
  
  render: (ctx, render) => {
    ctx.lang = "de";
    render();
  },
});

After thinking about this for a while we realised that we could simplify Fresh quite a bit by allowing you to render the HTML document yourself. So we did exactly that. With Fresh 1.4 you can set the <html> , <head> and <body>-tag directly on the server.


import { AppProps } from "$fresh/server.ts";

export default function App({ Component }: AppProps) {
  return (
    <html lang="de">
      <head>
        <title>My Fresh App</title>
      </head>
      <body>
        <Component />
      </body>
    </html>
  );
}

To make upgrading from older Fresh versions easier, we added some logic to detect whether an <html>-tag was rendered or not. If none was rendered, we fall back to wrapping the html with the internal template like in past Fresh versions.

Layouts

A common aspect of building web applications is that many parts of the layouts are shared across routes. Think of the Header or Footer of a website which is the same component across routes. Previously, you could do that in routes/_app.tsx, but there was no way to go beyond that. Creating a shared layout for some sub routes in your app required extracting the code into a component and importing it into all routes manually.

In Fresh 1.4, we added support for _layout files, which can be described as a route local app wrapper. They can be put in any route folder and Fresh will detect all the layouts that match and stack them on top of each other.

routes/
  _app.tsx
  _layout.tsx
  page.tsx      

  sub-route/
    _layout.tsx 
    index.tsx   
    about.tsx   

A _layout file looks very similar to a route file or the app wrapper. It uses the Component prop to continue rendering further layouts or the final route file.


import { LayoutProps } from "$fresh/server.ts";

export default function MyLayout({ Component }: LayoutProps) {
  return (
    <div class="my-layout">
      <h2>This is rendered by a layout</h2>
      <Component />
    </div>
  );
}

But there are times where you don’t want to inherit layouts or even the app wrapper, so we also added a way for you to opt-out of that.

export const config: RouteConfig = {
  skipAppWrapper: true, 
  skipInheritedLayouts: true, 
};

Thanks to Michael Gearhardt for kicking off the work on this feature!

Async layouts and async app wrapper

Once we had landed support for layouts, we wondered what would happen if we made them the same as a route? Could we allow async layout components too? It would surely reduce mental load by making route components and layout components behave the same. After a bit of coding, it turned out we can. So this Fresh release brings you not just _layout components, but also async layouts!

export default async function Layout(req: Request, ctx: LayoutContext) {
  const person = await fetchSomeData();

  return (
    <div>
      <h1>Hello {person.name}</h1>
      <ctx.Component />
    </div>
  );
}

And while we’re at it, why not make the app wrapper async too? With Fresh 1.4, all layouts behave the same. The only special case are Routes because they’re at the end of the rendering chain and therefore don’t have a ctx.Component property.

Quicker typing with define functions

With the introduction of async route components we received some feedback that the function definition becomes a bit “wordy” with it needing so many keywords.

export default async function Page(req: Request, ctx: RouteContext) {
  
}

And looking at that we share those concerns. I noticed that it always took me a bit of time to type that out. Sure, one could add a custom snippet in your editor to create that boilerplate, but that seemed more of a workaround than a proper solution.

So we spent some time bouncing a few ideas back and forth until we came up with the concept of define* helper functions. They don’t contain any logic, but they provide autocompletion hints to editor out of the box, without having to define the types yourself.


export default defineRoute(async (req, ctx) => {
  
}

If you look at the two snippets, there doesn’t seem to be much of a difference. But when you type them out in your editor, you’ll notice that the latter is much quicker to type.

The following define helper functions are available:

  • defineRoute for creating routes
  • defineLayout for creating layouts
  • defineApp for creating the app wrapper.

Organise your code with Route Groups

Normally, nested folders inside the routes/ directory are mapped directly to URLs. However, with bigger projects there are often scenarios where you want to group files and not have that affect the structure of the URL.

Route groups make this possible. A route group is a folder inside routes/ whose name is surrounded by parenthesis like (my-group). This also allows you to have different _layout and _middleware files for routes on the same segment.

routes/
  (marketing)/
    _layout.tsx
    about.tsx  

  (blog)/
    _layout.tsx
    archive.tsx 

Colocated islands, components and more

When the name of a route group folder starts with an underscore, like (_components), Fresh will ignore that folder and it’s effectively treated as private. This means you can use these private route folders to store components related to a particular route. The one special name is (_islands) which tells Fresh to treat all files in that folder as an island.

routes/
  shop/
    (_components)/  
      Section.tsx

    (_islands)/     
      Cart.tsx

    index.tsx

Combined together, this gives you the ability to organise your code on a feature basis and put all related components, islands or anything else into a shared folder.

What’s on the horizon?

There were lots more features in the works, that didn’t make the cut because they need a bit more time to cook. In particular, we’re working on overhauling our plugin system to make it easier to understand and more powerful. The PR to add support for view transitions is coming along nicely and with that we’re exploring how to add spa-like client navigation to Fresh. Another area we’ve been looking at are styling solutions like UnoCSS, using tailwind directly and other solutions.

Like in the past month you can follow this months iteration plan on GitHub.

Did you know? Deno 1.36 was just released.

Be sure to check out the release notes for Deno 1.36, which comes with improved security controls, testing, benchmarking, and more.