diff --git a/quartz.config.ts b/quartz.config.ts
index ab7e990..d1fe184 100644
--- a/quartz.config.ts
+++ b/quartz.config.ts
@@ -56,9 +56,9 @@ const config: QuartzConfig = {
     ],
     emitters: [
       Plugin.ContentPage({
-        head: Component.Head,
-        header: [Component.PageTitle, Component.Spacer, Component.Darkmode],
-        body: [Component.ArticleTitle, Component.ReadingTime, Component.TableOfContents, Component.Content]
+        head: Component.Head(),
+        header: [Component.PageTitle(), Component.Spacer(), Component.Darkmode()],
+        body: [Component.ArticleTitle(), Component.ReadingTime(), Component.TableOfContents(), Component.Content()]
       })
     ]
   },
diff --git a/quartz/components/ArticleTitle.tsx b/quartz/components/ArticleTitle.tsx
index 02725c6..37950c4 100644
--- a/quartz/components/ArticleTitle.tsx
+++ b/quartz/components/ArticleTitle.tsx
@@ -1,6 +1,6 @@
-import { QuartzComponentProps } from "./types"
+import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
 
-export default function ArticleTitle({ fileData }: QuartzComponentProps) {
+function ArticleTitle({ fileData }: QuartzComponentProps) {
   const title = fileData.frontmatter?.title
   const displayTitle = fileData.slug === "index" ? undefined : title
   if (displayTitle) {
@@ -9,3 +9,5 @@ export default function ArticleTitle({ fileData }: QuartzComponentProps) {
     return null
   }
 }
+
+export default (() => ArticleTitle) satisfies QuartzComponentConstructor
diff --git a/quartz/components/Body.tsx b/quartz/components/Body.tsx
index b8ad34b..0130828 100644
--- a/quartz/components/Body.tsx
+++ b/quartz/components/Body.tsx
@@ -1,8 +1,8 @@
 import clipboardScript from './scripts/clipboard.inline'
 import clipboardStyle from './styles/clipboard.scss'
-import { QuartzComponentProps } from "./types"
+import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
 
-export default function Body({ children }: QuartzComponentProps) {
+function Body({ children }: QuartzComponentProps) {
   return <article>
     {children}
   </article>
@@ -10,3 +10,6 @@ export default function Body({ children }: QuartzComponentProps) {
 
 Body.afterDOMLoaded = clipboardScript
 Body.css = clipboardStyle
+
+export default (() => Body) satisfies QuartzComponentConstructor
+
diff --git a/quartz/components/Content.tsx b/quartz/components/Content.tsx
index c010f2a..71d0f35 100644
--- a/quartz/components/Content.tsx
+++ b/quartz/components/Content.tsx
@@ -1,9 +1,11 @@
-import { QuartzComponentProps } from "./types"
+import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
 import { Fragment, jsx, jsxs } from 'preact/jsx-runtime'
 import { toJsxRuntime } from "hast-util-to-jsx-runtime"
 
-export default function Content({ tree }: QuartzComponentProps) {
+function Content({ tree }: QuartzComponentProps) {
   // @ts-ignore (preact makes it angry)
   const content = toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: 'html' })
   return content
 }
+
+export default (() => Content) satisfies QuartzComponentConstructor
diff --git a/quartz/components/Darkmode.tsx b/quartz/components/Darkmode.tsx
index 2170253..49f61c7 100644
--- a/quartz/components/Darkmode.tsx
+++ b/quartz/components/Darkmode.tsx
@@ -3,8 +3,9 @@
 // see: https://v8.dev/features/modules#defer
 import darkmodeScript from "./scripts/darkmode.inline"
 import styles from './styles/darkmode.scss'
+import { QuartzComponentConstructor } from "./types"
 
-export default function Darkmode() {
+function Darkmode() {
   return <div class="darkmode">
     <input class="toggle" id="darkmode-toggle" type="checkbox" tabIndex={-1} />
     <label id="toggle-label-light" for="darkmode-toggle" tabIndex={-1}>
@@ -48,3 +49,5 @@ export default function Darkmode() {
 
 Darkmode.beforeDOMLoaded = darkmodeScript
 Darkmode.css = styles
+
+export default (() => Darkmode) satisfies QuartzComponentConstructor
diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx
index 37c0aba..16125da 100644
--- a/quartz/components/Head.tsx
+++ b/quartz/components/Head.tsx
@@ -1,7 +1,7 @@
 import { resolveToRoot } from "../path"
-import { QuartzComponentProps } from "./types"
+import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
 
-export default function Head({ fileData, externalResources }: QuartzComponentProps) {
+function Head({ fileData, externalResources }: QuartzComponentProps) {
   const slug = fileData.slug!
   const title = fileData.frontmatter?.title ?? "Untitled"
   const description = fileData.description ?? "No description provided"
@@ -9,7 +9,7 @@ export default function Head({ fileData, externalResources }: QuartzComponentPro
   const baseDir = resolveToRoot(slug)
   const iconPath = baseDir + "/static/icon.png"
   const ogImagePath = baseDir + "/static/og-image.png"
-  
+
   return <head>
     <title>{title}</title>
     <meta charSet="utf-8" />
@@ -28,3 +28,5 @@ export default function Head({ fileData, externalResources }: QuartzComponentPro
     {js.filter(resource => resource.loadTime === "beforeDOMReady").map(resource => <script key={resource.src} {...resource} spa-preserve />)}
   </head>
 }
+
+export default (() => Head) satisfies QuartzComponentConstructor
diff --git a/quartz/components/Header.tsx b/quartz/components/Header.tsx
index 8b06863..197c4e5 100644
--- a/quartz/components/Header.tsx
+++ b/quartz/components/Header.tsx
@@ -1,6 +1,6 @@
-import { QuartzComponentProps } from "./types"
+import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
 
-export default function Header({ children }: QuartzComponentProps) {
+function Header({ children }: QuartzComponentProps) {
   return <header>
     {children}
   </header>
@@ -21,3 +21,5 @@ header > h1 {
   flex: auto;
 }
 `
+
+export default (() => Header) satisfies QuartzComponentConstructor
diff --git a/quartz/components/PageTitle.tsx b/quartz/components/PageTitle.tsx
index 080b74d..fe6ec3d 100644
--- a/quartz/components/PageTitle.tsx
+++ b/quartz/components/PageTitle.tsx
@@ -1,9 +1,11 @@
 import { resolveToRoot } from "../path"
-import { QuartzComponentProps } from "./types"
+import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
 
-export default function({ cfg, fileData }: QuartzComponentProps) {
+function PageTitle({ cfg, fileData }: QuartzComponentProps) {
   const title = cfg.siteTitle
   const slug = fileData.slug!
   const baseDir = resolveToRoot(slug)
   return <h1><a href={baseDir}>{title}</a></h1>
 }
+
+export default (() => PageTitle) satisfies QuartzComponentConstructor
diff --git a/quartz/components/ReadingTime.tsx b/quartz/components/ReadingTime.tsx
index 39110f9..cac8711 100644
--- a/quartz/components/ReadingTime.tsx
+++ b/quartz/components/ReadingTime.tsx
@@ -1,7 +1,7 @@
-import { QuartzComponentProps } from "./types"
+import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
 import readingTime from "reading-time"
 
-export default function ReadingTime({ fileData }: QuartzComponentProps) {
+function ReadingTime({ fileData }: QuartzComponentProps) {
   const text = fileData.text
   const isHomePage = fileData.slug === "index"
   if (text && !isHomePage) {
@@ -18,3 +18,5 @@ ReadingTime.css = `
   opacity: 0.5;
 }
 `
+
+export default (() => ReadingTime) satisfies QuartzComponentConstructor
diff --git a/quartz/components/Spacer.tsx b/quartz/components/Spacer.tsx
index 02b1093..34ea084 100644
--- a/quartz/components/Spacer.tsx
+++ b/quartz/components/Spacer.tsx
@@ -1,3 +1,7 @@
-export default function() {
+import { QuartzComponentConstructor } from "./types"
+
+function Spacer() {
   return <div class="spacer"></div>
 }
+
+export default (() => Spacer) satisfies QuartzComponentConstructor
diff --git a/quartz/components/TableOfContents.tsx b/quartz/components/TableOfContents.tsx
index 1f331ed..531c61d 100644
--- a/quartz/components/TableOfContents.tsx
+++ b/quartz/components/TableOfContents.tsx
@@ -1,7 +1,7 @@
-import { QuartzComponentProps } from "./types"
+import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
 import style from "./styles/toc.scss"
 
-export default function TableOfContents({ fileData }: QuartzComponentProps) {
+function TableOfContents({ fileData }: QuartzComponentProps) {
   if (!fileData.toc) {
     return null
   }
@@ -17,3 +17,5 @@ export default function TableOfContents({ fileData }: QuartzComponentProps) {
 }
 
 TableOfContents.css = style
+
+export default (() => TableOfContents) satisfies QuartzComponentConstructor
diff --git a/quartz/components/types.ts b/quartz/components/types.ts
index cb84edc..0b9b0eb 100644
--- a/quartz/components/types.ts
+++ b/quartz/components/types.ts
@@ -18,4 +18,4 @@ export type QuartzComponent = ComponentType<QuartzComponentProps> & {
   afterDOMLoaded?: string,
 }
 
-export type QuartzComponentConstructor<Options extends object> = (opts: Options) => QuartzComponent
+export type QuartzComponentConstructor<Options extends object | undefined = undefined> = (opts: Options) => QuartzComponent
diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx
index b7059f8..9b789ef 100644
--- a/quartz/plugins/emitters/contentPage.tsx
+++ b/quartz/plugins/emitters/contentPage.tsx
@@ -5,9 +5,9 @@ import { render } from "preact-render-to-string"
 import { GlobalConfiguration } from "../../cfg"
 import { QuartzComponent } from "../../components/types"
 import { resolveToRoot } from "../../path"
-import Header from "../../components/Header"
+import HeaderConstructor from "../../components/Header"
 import { QuartzComponentProps } from "../../components/types"
-import Body from "../../components/Body"
+import BodyConstructor from "../../components/Body"
 
 interface Options {
   head: QuartzComponent
@@ -20,6 +20,10 @@ export const ContentPage: QuartzEmitterPlugin<Options> = (opts) => {
     throw new Error("ContentPage must be initialized with options specifiying the components to use")
   }
 
+  const { head: Head, header, body } = opts
+  const Header = HeaderConstructor()
+  const Body = BodyConstructor()
+
   return {
     name: "ContentPage",
     getQuartzComponents() {
@@ -28,7 +32,6 @@ export const ContentPage: QuartzEmitterPlugin<Options> = (opts) => {
     async emit(cfg: GlobalConfiguration, content: ProcessedContent[], resources: StaticResources, emit: EmitCallback): Promise<string[]> {
       const fps: string[] = []
 
-      const { head: Head, header, body } = opts
       for (const [tree, file] of content) {
         const baseDir = resolveToRoot(file.data.slug!)
         const pageResources: StaticResources = {