mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-03-21 21:45:42 -05:00
fix: only call scripts one per page
This commit is contained in:
parent
912642590c
commit
34480c686d
@ -18,6 +18,7 @@ export interface RegisteredComponent {
|
|||||||
|
|
||||||
class ComponentRegistry {
|
class ComponentRegistry {
|
||||||
private components = new Map<string, RegisteredComponent>()
|
private components = new Map<string, RegisteredComponent>()
|
||||||
|
private instanceCache = new Map<string, QuartzComponent>()
|
||||||
|
|
||||||
register(
|
register(
|
||||||
name: string,
|
name: string,
|
||||||
@ -40,6 +41,30 @@ class ComponentRegistry {
|
|||||||
return new Map(this.components)
|
return new Map(this.components)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a component constructor with options, returning a cached instance
|
||||||
|
* if the same constructor was already called with equivalent options.
|
||||||
|
* This prevents duplicate afterDOMLoaded scripts when the same component
|
||||||
|
* appears in multiple page-type layouts.
|
||||||
|
*/
|
||||||
|
instantiate(constructor: QuartzComponentConstructor, options?: unknown): QuartzComponent {
|
||||||
|
const optsKey = options !== undefined ? JSON.stringify(options) : ""
|
||||||
|
// Use constructor identity + serialized options as cache key
|
||||||
|
// We store constructor name as a hint but rely on a unique id for identity
|
||||||
|
const ctorId =
|
||||||
|
(constructor as unknown as { __cacheId?: string }).__cacheId ??
|
||||||
|
((constructor as unknown as { __cacheId: string }).__cacheId =
|
||||||
|
`ctor_${this.instanceCache.size}`)
|
||||||
|
const cacheKey = `${ctorId}:${optsKey}`
|
||||||
|
|
||||||
|
const cached = this.instanceCache.get(cacheKey)
|
||||||
|
if (cached) return cached
|
||||||
|
|
||||||
|
const instance = constructor(options)
|
||||||
|
this.instanceCache.set(cacheKey, instance)
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
getAllComponents(): QuartzComponent[] {
|
getAllComponents(): QuartzComponent[] {
|
||||||
// Deduplicate by component reference (same constructor may be registered under multiple keys)
|
// Deduplicate by component reference (same constructor may be registered under multiple keys)
|
||||||
const seen = new Set<QuartzComponent | QuartzComponentConstructor>()
|
const seen = new Set<QuartzComponent | QuartzComponentConstructor>()
|
||||||
@ -50,7 +75,7 @@ class ComponentRegistry {
|
|||||||
try {
|
try {
|
||||||
let instance: QuartzComponent
|
let instance: QuartzComponent
|
||||||
if (typeof r.component === "function") {
|
if (typeof r.component === "function") {
|
||||||
instance = (r.component as QuartzComponentConstructor)(undefined)
|
instance = this.instantiate(r.component as QuartzComponentConstructor, undefined)
|
||||||
} else {
|
} else {
|
||||||
instance = r.component as QuartzComponent
|
instance = r.component as QuartzComponent
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import path from "path"
|
|||||||
import YAML from "yaml"
|
import YAML from "yaml"
|
||||||
import { styleText } from "util"
|
import { styleText } from "util"
|
||||||
import { QuartzConfig, GlobalConfiguration, FullPageLayout } from "../../cfg"
|
import { QuartzConfig, GlobalConfiguration, FullPageLayout } from "../../cfg"
|
||||||
import { QuartzComponent } from "../../components/types"
|
import { QuartzComponent, QuartzComponentConstructor } from "../../components/types"
|
||||||
import { PluginTypes } from "../types"
|
import { PluginTypes } from "../types"
|
||||||
import {
|
import {
|
||||||
PluginManifest,
|
PluginManifest,
|
||||||
@ -561,11 +561,12 @@ export async function loadQuartzLayout(layoutOverrides?: {
|
|||||||
const footerReg = componentRegistry.get("footer") ?? componentRegistry.get("Footer")
|
const footerReg = componentRegistry.get("footer") ?? componentRegistry.get("Footer")
|
||||||
if (footerReg) {
|
if (footerReg) {
|
||||||
if (typeof footerReg.component === "function" && !("displayName" in footerReg.component)) {
|
if (typeof footerReg.component === "function" && !("displayName" in footerReg.component)) {
|
||||||
// It's a constructor, instantiate with options
|
// It's a constructor — use registry cache for consistent instances
|
||||||
const opts = { ...footerEntry.options }
|
const opts = { ...footerEntry.options }
|
||||||
footer = (footerReg.component as Function)(
|
footer = componentRegistry.instantiate(
|
||||||
|
footerReg.component as QuartzComponentConstructor,
|
||||||
Object.keys(opts).length > 0 ? opts : undefined,
|
Object.keys(opts).length > 0 ? opts : undefined,
|
||||||
) as QuartzComponent
|
)
|
||||||
} else {
|
} else {
|
||||||
footer = footerReg.component as QuartzComponent
|
footer = footerReg.component as QuartzComponent
|
||||||
}
|
}
|
||||||
@ -648,11 +649,14 @@ function buildLayoutForEntries(
|
|||||||
|
|
||||||
let component: QuartzComponent
|
let component: QuartzComponent
|
||||||
if (typeof reg.component === "function" && !("displayName" in reg.component)) {
|
if (typeof reg.component === "function" && !("displayName" in reg.component)) {
|
||||||
// It's a constructor, instantiate with options
|
// It's a constructor — use registry cache to avoid duplicate instances
|
||||||
|
// (and duplicate afterDOMLoaded scripts) across page-type layouts
|
||||||
const opts = { ...entry.options }
|
const opts = { ...entry.options }
|
||||||
component = (reg.component as Function)(
|
const optsArg = Object.keys(opts).length > 0 ? opts : undefined
|
||||||
Object.keys(opts).length > 0 ? opts : undefined,
|
component = componentRegistry.instantiate(
|
||||||
) as QuartzComponent
|
reg.component as QuartzComponentConstructor,
|
||||||
|
optsArg,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
component = reg.component as QuartzComponent
|
component = reg.component as QuartzComponent
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user