You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Deno Fresh框架如何自定义HTML模板 向head添加title与CSS引用

Fresh框架自定义Head内容与模板修改方案

你看到的源码里opts.headComponents就是官方预留的自定义head内容注入入口,不需要修改框架源码,通过官方暴露的API就能实现所有需求,具体方法如下:

  • 不需要改内置模板的场景:直接用内置的<Head>组件,所有传入组件的内容都会自动注入到opts.headComponents对应的渲染位置。
  • 需要完全自定义HTML模板的场景:通过入口文件的render配置替换默认模板即可。

基础需求实现:添加title与自定义CSS

首先把你要引入的CSS文件放到项目根目录的static/文件夹下,框架会自动托管该目录下的静态资源,引用时直接使用/开头的根路径即可,不需要加static前缀。
在需要自定义head内容的路由文件中,从$fresh/runtime.ts导入Head组件,直接在页面组件内写入需要追加的head标签即可:

// routes/index.tsx 示例
import { Head } from "$fresh/runtime.ts";

export default function HomePage() {
  return (
    <>
      <Head>
        {/* 添加页面title */}
        <title>我的Fresh站点首页</title>
        {/* 引入static目录下的自定义CSS,对应路径为static/css/main.css */}
        <link rel="stylesheet" href="/css/main.css" />
        {/* 其他任意meta标签、资源引用都可以在这里写,比如og标签、favicon等 */}
        <link rel="icon" href="/favicon.ico" />
      </Head>

      {/* 原有页面主体内容 */}
      <main>
        <h1>首页内容</h1>
      </main>
    </>
  );
}

全局统一Head内容配置

如果需要给所有页面添加全局生效的CSS、统一的meta规则,不需要在每个路由重复写,直接在全局布局文件routes/_app.tsx中配置即可:

// routes/_app.tsx 示例
import { AppProps } from "$fresh/server.ts";
import { Head } from "$fresh/runtime.ts";

export default function GlobalApp({ Component }: AppProps) {
  return (
    <>
      <Head>
        {/* 全局CSS,所有页面自动加载 */}
        <link rel="stylesheet" href="/global.css" />
        {/* 全局meta标签 */}
        <meta name="author" content="我的名字" />
      </Head>
      <Component />
    </>
  );
}

单路由内写入的Head内容会和全局配置自动合并,不会出现覆盖冲突。

完全自定义HTML模板

如果你需要修改默认模板的结构(比如调整默认meta标签顺序、给html/body添加全局属性、在body末尾追加全局脚本等),可以直接在项目入口文件main.ts中替换默认模板,官方已经暴露了对应的配置入口,不需要修改框架源码:

// main.ts 示例
import { start, createRenderer } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";
import { renderToString } from "preact-render-to-string";
import type { ComponentChildren } from "preact";

// 自定义模板,结构和你在源码中看到的默认模板完全一致,可以按需修改
interface CustomTemplateOptions {
  bodyHtml: string;
  headComponents: ComponentChildren[];
  imports: (readonly [string, string])[];
  styles: string[];
  preloads: string[];
  lang: string;
}

function myCustomTemplate(opts: CustomTemplateOptions): string {
  const page = (
    <html lang={opts.lang} class="light">
      <head>
        <meta charSet="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        {/* 你可以在这里添加固定的全局head内容 */}
        {opts.preloads.map((src) => <link rel="modulepreload" href={src} />)}
        {opts.imports.map(([src, nonce]) => (
          <script src={src} nonce={nonce} type="module"></script>
        ))}
        <style
          id="__FRSH_STYLE"
          dangerouslySetInnerHTML={{ __html: opts.styles.join("\n") }}
        />
        {opts.headComponents}
      </head>
      <body>
        <div dangerouslySetInnerHTML={{ __html: opts.bodyHtml }} />
        {/* 比如可以在这里追加全局统计脚本、固定的页脚结构等 */}
      </body>
    </html>
  );
  return "<!DOCTYPE html>" + renderToString(page);
}

// 启动时传入自定义render配置,替换默认模板
await start(manifest, {
  render: createRenderer({
    template: myCustomTemplate
  })
});

注意:如果使用的是1.0之前的早期Fresh版本,createRendererAPI尚未暴露,此时可以通过中间件拦截响应内容替换HTML字符串实现自定义模板,升级到最新稳定版即可直接使用上述配置方式。

内容的提问来源于stack exchange,提问作者Harrel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 16:18:21