template-kit/size-renderer-bundle
The template-kit/size-renderer-bundle authoring rule — what it enforces, why, and how to fix it.
A section’s renderer bundle must be ≤ 50 KB gzip. The budget is not author-overridable.
Each section’s renderer is bundled with esbuild and minified, with React treated as external (it is a peer, shared by the whole page, and is not counted against any one section). The gzipped result must be 50 KB or less.
The budget is visible in template-kit check’s configuration and is not
author-overridable. A template workspace cannot raise it, and there is no per-section
exemption. If you go looking for the flag, this is the answer: there isn’t one.
Reason
Section titled “Reason”The output is a real page for a real buyer, standing in a driveway on a phone. Bytes are the one cost the section cannot delegate.
The number is set to be generous — roughly twice the largest section shipping today — so it does not fight ordinary authoring. You will not hit it by writing a rich section. You hit it when something runaway gets pulled in:
- a barrel import of an icon set, which drags every icon into the bundle so you can use three;
- a package that brings a font, a locale table, or a polyfill along with it, none of which you asked for.
That is the shape of essentially every violation: not a section that grew, but a single import that was more expensive than it looked.
Find the import that is not paying for itself.
- Import named symbols, never a namespace.
import { ArrowRight } from "…"is tree-shakeable;import * as Icons from "…"is not — a namespace object has to contain everything, so nothing can be dropped. - Prefer the package’s narrow entry if it offers one.
- Hand-write the residue. If you use one function out of a large utility package, copy the function.
Do not try to hoist code out of the section to dodge the budget. Each template owns its own presentation code; there is no shared library above a section to hoist it into, and the bytes would still land on the same page.
Before
Section titled “Before”import { Section, Slot, SlotItem } from "@homepages/template-kit";import * as Icons from "lucide-react"; // ← the whole set: every icon, in the bundle
import type { Props } from "./schema.js";
export function Renderer({ slots }: Props) { return ( <Section> <Slot id="amenities"> {slots.amenities.map((item, i) => ( <SlotItem key={typeof item.id === "string" ? item.id : i} index={i} as="li"> <Icons.Check aria-hidden /> <h3>{typeof item.label === "string" ? item.label : null}</h3> </SlotItem> ))} </Slot> </Section> );}import { Section, Slot, SlotItem } from "@homepages/template-kit";import { Check } from "lucide-react"; // ← one icon, and the bundler can drop the rest
import type { Props } from "./schema.js";
export function Renderer({ slots }: Props) { return ( <Section> <Slot id="amenities"> {slots.amenities.map((item, i) => ( <SlotItem key={typeof item.id === "string" ? item.id : i} index={i} as="li"> <Check aria-hidden /> <h3>{typeof item.label === "string" ? item.label : null}</h3> </SlotItem> ))} </Slot> </Section> );}See also
Section titled “See also”size-section-css— the same budget on the other half of what the section ships.license-denied— the other reason to look hard at a dependency before you take it.