Refactor cache control settings and improve robots.txt handling; update definition retrieval to synchronous method

This commit is contained in:
Ben
2026-05-17 21:45:59 -07:00
parent 4a4b759a37
commit 6b028fdbda
8 changed files with 45 additions and 27 deletions
+4 -1
View File
@@ -12,7 +12,8 @@ const MIME_TYPES: Record<string, string> = {
'.otf': 'font/otf' '.otf': 'font/otf'
}; };
const HTML_CACHE_CONTROL = 'public, max-age=0, s-maxage=3600, stale-while-revalidate=86400'; const HTML_CACHE_CONTROL = 'no-cache, max-age=0, must-revalidate, no-transform';
const EDGE_HTML_CACHE_CONTROL = 'max-age=300, stale-while-revalidate=86400';
const IMMUTABLE_ASSET_CACHE_CONTROL = 'public, max-age=31536000, immutable'; const IMMUTABLE_ASSET_CACHE_CONTROL = 'public, max-age=31536000, immutable';
const ASSET_404_CACHE_CONTROL = 'no-store'; const ASSET_404_CACHE_CONTROL = 'no-store';
const LONG_CACHE_EXTENSIONS = new Set([ const LONG_CACHE_EXTENSIONS = new Set([
@@ -71,6 +72,8 @@ export const handle: Handle = async ({ event, resolve }) => {
// bundle hashes after each deployment. // bundle hashes after each deployment.
if (contentType.includes('text/html')) { if (contentType.includes('text/html')) {
response.headers.set('cache-control', HTML_CACHE_CONTROL); response.headers.set('cache-control', HTML_CACHE_CONTROL);
response.headers.set('cdn-cache-control', EDGE_HTML_CACHE_CONTROL);
response.headers.set('cloudflare-cdn-cache-control', EDGE_HTML_CACHE_CONTROL);
} }
return response; return response;
@@ -39,14 +39,10 @@
{#if supportsExample && result} {#if supportsExample && result}
<section class="example-card"> <section class="example-card">
<h3>How to convert {config.labels.in1} to {config.labels.in2}</h3> <h3>How to convert {config.labels.in1} to {config.labels.in2}</h3>
{#if hasOffset} <p class="example-note">
<p class="example-note"> 1 {config.labels.in1} = {formattedFactorValue}{hasOffset ? ` + ${formattedOffsetValue}` : ''} {config.labels.in2}
Formula: {config.labels.in2} = ({config.labels.in1} x {formattedFactorValue}) {offset > 0 ? '+' : '-'} {formatConversionValue(Math.abs(offset))} </p>
</p> {#if !hasOffset}
{:else}
<p class="example-note">
1 {config.labels.in1} = {formattedFactorValue} {config.labels.in2}
</p>
<p class="example-note"> <p class="example-note">
1 {config.labels.in2} = {formattedReverseValue} {config.labels.in1} 1 {config.labels.in2} = {formattedReverseValue} {config.labels.in1}
</p> </p>
@@ -1,20 +1,18 @@
<script lang="ts"> <script lang="ts">
import { getDefinition } from '$lib/data/unitDefinitions'; import { getDefinitionSync } from '$lib/data/unitDefinitions';
import type { CalculatorDef } from '$lib/data/calculatorLoader'; import type { CalculatorDef } from '$lib/data/calculators';
export let config: CalculatorDef; export let config: CalculatorDef;
let label1 = 'Unit 1'; let label1 = 'Unit 1';
let label2 = 'Unit 2'; let label2 = 'Unit 2';
let def1: string | undefined; let def1 = '';
let def2: string | undefined; let def2 = '';
$: label1 = config.labels.in1 || 'Unit 1'; $: label1 = config.labels.in1 || 'Unit 1';
$: label2 = config.labels.in2 || 'Unit 2'; $: label2 = config.labels.in2 || 'Unit 2';
$: { $: def1 = getDefinitionSync(label1, config.category) ?? '';
getDefinition(label1, config.category).then(d => { def1 = d; }); $: def2 = getDefinitionSync(label2, config.category) ?? '';
getDefinition(label2, config.category).then(d => { def2 = d; });
}
</script> </script>
<section class="definition-card"> <section class="definition-card">
@@ -22,11 +20,11 @@
<div class="definition-grid"> <div class="definition-grid">
<article> <article>
<strong>{label1}</strong> <strong>{label1}</strong>
<p>{def1 ?? `Definition pending for ${label1}.`}</p> <p>{def1}</p>
</article> </article>
<article> <article>
<strong>{label2}</strong> <strong>{label2}</strong>
<p>{def2 ?? `Definition pending for ${label2}.`}</p> <p>{def2}</p>
</article> </article>
</div> </div>
</section> </section>
@@ -100,6 +100,9 @@ const normalizeLabel = (label?: string): string | undefined => {
const categoryPriority = [...Object.keys(domainDefinitions)]; const categoryPriority = [...Object.keys(domainDefinitions)];
const specificDefinitions: Array<[RegExp, string]> = [ const specificDefinitions: Array<[RegExp, string]> = [
[/\btons? of tnt\b/i, 'measures explosive energy release. One ton of TNT is conventionally defined as 4.184 gigajoules of energy.'],
[/\batomic time units?\b/i, 'measures time on an atomic scale. One atomic unit of time is about 2.418884326505e-17 seconds.'],
[/\bastronomical units?\b/i, 'measures large distances in astronomy. One astronomical unit is the average Earth-Sun distance, exactly 149,597,870,700 meters.'],
[/\bwatts?\b|\bkilowatts?\b|\bmegawatts?\b|\bhorsepower\b/i, 'measures the rate at which energy is transferred or converted. It is used for engines, appliances, electrical loads, and heat-transfer rates.'], [/\bwatts?\b|\bkilowatts?\b|\bmegawatts?\b|\bhorsepower\b/i, 'measures the rate at which energy is transferred or converted. It is used for engines, appliances, electrical loads, and heat-transfer rates.'],
[/\bcalories?\b|\bjoules?\b|\bbtu\b|\bkilocalories?\b|\btherms?\b|\bwatt hours?\b|\bkilowatt hours?\b/i, 'measures energy, heat, or work. These units are used for food energy, physics calculations, heating systems, and stored electricity.'], [/\bcalories?\b|\bjoules?\b|\bbtu\b|\bkilocalories?\b|\btherms?\b|\bwatt hours?\b|\bkilowatt hours?\b/i, 'measures energy, heat, or work. These units are used for food energy, physics calculations, heating systems, and stored electricity.'],
[/\bvolts?\b/i, 'measures electric potential difference. Voltage describes the electrical pressure that pushes current through a circuit.'], [/\bvolts?\b/i, 'measures electric potential difference. Voltage describes the electrical pressure that pushes current through a circuit.'],
@@ -177,3 +180,9 @@ export async function getDefinition(label: string, category?: string): Promise<s
const entries = defs[normalized]; const entries = defs[normalized];
return findByPriority(entries, category); return findByPriority(entries, category);
} }
export function getDefinitionSync(label: string, category?: string): string | undefined {
const normalized = normalizeLabel(label);
if (!normalized) return undefined;
return buildDefinition(normalized, category || 'other');
}
+1 -3
View File
@@ -1,3 +1 @@
// Prerender the homepage as static HTML at build time. export const prerender = false;
// adapter-node will serve this as a static file — no SSR round-trip.
export const prerender = true;
@@ -0,0 +1,16 @@
import type { RequestHandler } from './$types';
const robots = `User-agent: *
Disallow:
Sitemap: https://howdoyouconvert.com/sitemap.xml
`;
export const GET: RequestHandler = () =>
new Response(robots, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
'Cache-Control': 'no-cache, max-age=0, must-revalidate, no-transform',
'CDN-Cache-Control': 'max-age=300, stale-while-revalidate=86400',
'Cloudflare-CDN-Cache-Control': 'max-age=300, stale-while-revalidate=86400'
}
});
@@ -33,7 +33,9 @@ ${calculatorUrls.join('\n')}
return new Response(sitemap, { return new Response(sitemap, {
headers: { headers: {
'Content-Type': 'application/xml', 'Content-Type': 'application/xml',
'Cache-Control': 'max-age=0, s-maxage=3600' 'Cache-Control': 'no-cache, max-age=0, must-revalidate, no-transform',
'CDN-Cache-Control': 'max-age=300, stale-while-revalidate=86400',
'Cloudflare-CDN-Cache-Control': 'max-age=300, stale-while-revalidate=86400'
} }
}); });
}; };
-4
View File
@@ -1,4 +0,0 @@
# allow crawling everything by default
User-agent: *
Disallow:
Sitemap: https://howdoyouconvert.com/sitemap.xml