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
相关产品推荐
相关产品推荐

