diff --git a/assets/.well-known/traffic-advice b/assets/.well-known/traffic-advice index 8cd8df9..54e23d9 100644 --- a/assets/.well-known/traffic-advice +++ b/assets/.well-known/traffic-advice @@ -1,6 +1,6 @@ { "user_agent": "prefetch-proxy", "google_prefetch_proxy_eap": { - "fraction": 1.0 + "fraction": 0.7 } } \ No newline at end of file diff --git a/src/layout/helpers/htmxConfig.tsx b/src/layout/helpers/htmxConfig.tsx new file mode 100644 index 0000000..a566ac9 --- /dev/null +++ b/src/layout/helpers/htmxConfig.tsx @@ -0,0 +1,28 @@ +import { raw } from "hono/html"; +import type { LooseObj, NoncePropType } from "../../types"; + +export function getHTMXConfigStr(nonce: string | undefined) { + const HTMXConfigObj: LooseObj = { + responseHandling: [ + { code: "204", swap: false }, + { code: "400", swap: false, error: true }, + { code: "404", swap: true, error: true }, + { code: "[234]..", swap: true, error: false }, + { code: "500", swap: true, error: true }, + { code: "[5]..", swap: false, error: true }, + { code: "...", swap: true }, + ], + }; + if (nonce !== undefined) { + HTMXConfigObj.allowEval = false; + HTMXConfigObj.inlineScriptNonce = + HTMXConfigObj.inlineStyleNonce = nonce; + } + + return ``; +} + +export function HTMXConfig({ nonce }: NoncePropType) { + return raw(getHTMXConfigStr(nonce)); +} + diff --git a/src/layout/helpers/includesTags.tsx b/src/layout/helpers/includesTags.tsx index 89794a5..83720d4 100644 --- a/src/layout/helpers/includesTags.tsx +++ b/src/layout/helpers/includesTags.tsx @@ -1,9 +1,4 @@ -import { raw } from "hono/html"; -import type { LooseObj, PreloadRules } from "../../types"; - -interface NoncePropType { - nonce?: string; -} +import type { NoncePropType, PreloadRules } from "../../types"; type DepTagsType = NoncePropType & { scripts?: PreloadRules[] @@ -54,27 +49,3 @@ export function PreloadDependencyTags({ scripts }: DepTagsType) { }); return <>{html}; } - -export function getHTMXConfigStr(nonce: string | undefined) { - const HTMXConfigObj: LooseObj = { - responseHandling: [ - { code: "204", swap: false }, - { code: "400", swap: false, error: true }, - { code: "404", swap: true, error: true }, - { code: "[234]..", swap: true, error: false }, - { code: "500", swap: true, error: true }, - { code: "[5]..", swap: false, error: true }, - { code: "...", swap: true }, - ], - }; - if (nonce !== undefined) { - HTMXConfigObj.allowEval = false; - HTMXConfigObj.inlineScriptNonce = HTMXConfigObj.inlineStyleNonce = nonce; - } - - return ``; -} - -export function HTMXNonceTag({ nonce }: NoncePropType) { - return raw(getHTMXConfigStr(nonce)); -} diff --git a/src/layout/helpers/speculation.tsx b/src/layout/helpers/speculation.tsx new file mode 100644 index 0000000..aabcfb3 --- /dev/null +++ b/src/layout/helpers/speculation.tsx @@ -0,0 +1,28 @@ +// this file handles injecting speculation rules. +import { raw } from "hono/html"; +import { ALLOW_SPECULATION_RULES } from "../../limits"; + +export function SpeculationRulesTag() { + if (!ALLOW_SPECULATION_RULES) + return (<>); + + const speculationDefines = { + prerender: [ + { + where: { + and: [ + { href_matches: "/*" }, + // sensitive pages + { not: { href_matches: "/(dashboard|reset)" } }, + // redirects + { not: { href_matches: "/(reset|tip|contact|bsky|source)" } }, + ] + }, + eagerness: "moderate", + }, + ], + // fetch everything that's not outside the main site + prefetch: [{ where: { not: { href_matches: "/*" } }, eagerness: "moderate" }], + }; + return ; +} diff --git a/src/layout/main.tsx b/src/layout/main.tsx index 0d4927c..4fc5d22 100644 --- a/src/layout/main.tsx +++ b/src/layout/main.tsx @@ -3,9 +3,11 @@ import type { Child } from "hono/jsx"; import { APP_NAME } from "../appInfo"; import { ScriptInclusionLevel } from "../enums"; import type { BaseElementProps, PreloadRules } from "../types"; +import { HTMXConfig } from "./helpers/htmxConfig"; import { getScriptsForInteractivity } from "./helpers/includesList"; -import { HTMXNonceTag, IncludeDependencyTags, PreloadDependencyTags } from "./helpers/includesTags"; +import { IncludeDependencyTags, PreloadDependencyTags } from "./helpers/includesTags"; import { MetaTags, PersonaTags } from "./helpers/metaTags"; +import { SpeculationRulesTag } from "./helpers/speculation"; type BaseLayoutProps = BaseElementProps & { children: Child; @@ -41,7 +43,8 @@ export const BaseLayout = (props: BaseLayoutProps) => { - + + {props.interactivity === ScriptInclusionLevel.NonInteractive ? : null} diff --git a/src/limits.ts b/src/limits.ts index f1aacd8..fd137b3 100644 --- a/src/limits.ts +++ b/src/limits.ts @@ -111,6 +111,9 @@ export const USE_DEPRECATED_SIZE_PARSE: boolean = true; // if we should try to use SSG rendering for pages vs dynamic rendering export const USE_STATIC_HTML: boolean = true; +// if we should enable chrome speculation rules to speed up the site +export const ALLOW_SPECULATION_RULES: boolean = false; + /*********************************************************/ /**** APPLICATION INTERVAL SETTINGS ****/ /*********************************************************/ diff --git a/src/middleware/ssg.ts b/src/middleware/ssg.ts index 4afe6c5..e4f28bf 100644 --- a/src/middleware/ssg.ts +++ b/src/middleware/ssg.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/dot-notation */ +import { readFile } from "fs/promises"; import { createMiddleware } from "hono/factory"; import { isSSGContext } from "hono/ssg"; -import { readFile } from "fs/promises"; -import { getHTMXConfigStr } from "../layout/helpers/includesTags"; +import { getHTMXConfigStr } from "../layout/helpers/htmxConfig"; import { USE_GRANULAR_CSP_SETTINGS, USE_STATIC_HTML } from "../limits"; import type { BaseContext, NextMiddleware } from "../types"; import { has } from "../utils/helpers"; @@ -27,7 +27,8 @@ class NonceInject { if (scriptType !== null && scriptType !== "text/javascript" && scriptType !== "application/javascript" && - scriptType !== "module") { + scriptType !== "module") + { return; } } diff --git a/src/types.ts b/src/types.ts index eaae0fc..6d3669b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -264,6 +264,10 @@ export type ContextVariables = SecureHeadersVariables & { ssg: boolean; }; +export interface NoncePropType { + nonce?: string; +} + export interface HonoBase { Bindings: Bindings; Variables: ContextVariables;