mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-03-22 05:55:42 -05:00
fix: include virtual pages in content index for explorer visibility
This commit is contained in:
parent
360dfca18e
commit
673f51c13d
@ -50,6 +50,7 @@ async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) {
|
|||||||
allSlugs: [],
|
allSlugs: [],
|
||||||
allFiles: [],
|
allFiles: [],
|
||||||
incremental: false,
|
incremental: false,
|
||||||
|
virtualPages: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
const perf = new PerfTimer()
|
const perf = new PerfTimer()
|
||||||
@ -264,10 +265,40 @@ async function rebuild(changes: ChangeEvent[], clientRefresh: () => void, buildD
|
|||||||
)
|
)
|
||||||
|
|
||||||
let emittedFiles = 0
|
let emittedFiles = 0
|
||||||
|
|
||||||
|
// Phase 1: Run PageTypeDispatcher first so it populates ctx.virtualPages
|
||||||
|
const dispatcher = cfg.plugins.emitters.find((e) => e.name === "PageTypeDispatcher")
|
||||||
|
if (dispatcher) {
|
||||||
|
ctx.virtualPages = []
|
||||||
|
const emitFn = dispatcher.partialEmit ?? dispatcher.emit
|
||||||
|
const emitted = await emitFn(ctx, processedFiles, staticResources, changeEvents)
|
||||||
|
if (emitted !== null) {
|
||||||
|
if (Symbol.asyncIterator in emitted) {
|
||||||
|
for await (const file of emitted) {
|
||||||
|
emittedFiles++
|
||||||
|
if (ctx.argv.verbose) {
|
||||||
|
console.log(`[emit:${dispatcher.name}] ${file}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emittedFiles += emitted.length
|
||||||
|
if (ctx.argv.verbose) {
|
||||||
|
for (const file of emitted) {
|
||||||
|
console.log(`[emit:${dispatcher.name}] ${file}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 2: Run all other emitters with content extended by virtual pages
|
||||||
|
const contentWithVirtual =
|
||||||
|
ctx.virtualPages.length > 0 ? [...processedFiles, ...ctx.virtualPages] : processedFiles
|
||||||
for (const emitter of cfg.plugins.emitters) {
|
for (const emitter of cfg.plugins.emitters) {
|
||||||
|
if (emitter.name === "PageTypeDispatcher") continue
|
||||||
// Try to use partialEmit if available, otherwise assume the output is static
|
// Try to use partialEmit if available, otherwise assume the output is static
|
||||||
const emitFn = emitter.partialEmit ?? emitter.emit
|
const emitFn = emitter.partialEmit ?? emitter.emit
|
||||||
const emitted = await emitFn(ctx, processedFiles, staticResources, changeEvents)
|
const emitted = await emitFn(ctx, contentWithVirtual, staticResources, changeEvents)
|
||||||
if (emitted === null) {
|
if (emitted === null) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,6 +134,9 @@ export const PageTypeDispatcher: QuartzEmitterPlugin<Partial<DispatcherOptions>>
|
|||||||
...vp.data,
|
...vp.data,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Expose virtual pages on ctx so other emitters (e.g. ContentIndex) can include them
|
||||||
|
ctx.virtualPages.push([tree, vfile])
|
||||||
|
|
||||||
yield emitPage(ctx, vpSlug, tree, vfile.data, allFiles, layout, resources)
|
yield emitPage(ctx, vpSlug, tree, vfile.data, allFiles, layout, resources)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,6 +185,9 @@ export const PageTypeDispatcher: QuartzEmitterPlugin<Partial<DispatcherOptions>>
|
|||||||
...vp.data,
|
...vp.data,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Expose virtual pages on ctx so other emitters (e.g. ContentIndex) can include them
|
||||||
|
ctx.virtualPages.push([tree, vfile])
|
||||||
|
|
||||||
yield emitPage(ctx, vpSlug, tree, vfile.data, allFiles, layout, resources)
|
yield emitPage(ctx, vpSlug, tree, vfile.data, allFiles, layout, resources)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,50 @@
|
|||||||
import { PerfTimer } from "../util/perf"
|
import { PerfTimer } from "../util/perf"
|
||||||
import { getStaticResourcesFromPlugins } from "../plugins"
|
import { getStaticResourcesFromPlugins } from "../plugins"
|
||||||
import { ProcessedContent } from "../plugins/vfile"
|
import { ProcessedContent } from "../plugins/vfile"
|
||||||
|
import { QuartzEmitterPluginInstance } from "../plugins/types"
|
||||||
import { QuartzLogger } from "../util/log"
|
import { QuartzLogger } from "../util/log"
|
||||||
import { trace } from "../util/trace"
|
import { trace } from "../util/trace"
|
||||||
import { BuildCtx } from "../util/ctx"
|
import { BuildCtx } from "../util/ctx"
|
||||||
|
import { StaticResources } from "../util/resources"
|
||||||
import { styleText } from "util"
|
import { styleText } from "util"
|
||||||
|
|
||||||
|
async function runEmitter(
|
||||||
|
emitter: QuartzEmitterPluginInstance,
|
||||||
|
ctx: BuildCtx,
|
||||||
|
content: ProcessedContent[],
|
||||||
|
resources: StaticResources,
|
||||||
|
log: QuartzLogger,
|
||||||
|
): Promise<number> {
|
||||||
|
let count = 0
|
||||||
|
try {
|
||||||
|
const emitted = await emitter.emit(ctx, content, resources)
|
||||||
|
if (Symbol.asyncIterator in emitted) {
|
||||||
|
// Async generator case
|
||||||
|
for await (const file of emitted) {
|
||||||
|
count++
|
||||||
|
if (ctx.argv.verbose) {
|
||||||
|
console.log(`[emit:${emitter.name}] ${file}`)
|
||||||
|
} else {
|
||||||
|
log.updateText(`${emitter.name} -> ${styleText("gray", file)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Array case
|
||||||
|
count += emitted.length
|
||||||
|
for (const file of emitted) {
|
||||||
|
if (ctx.argv.verbose) {
|
||||||
|
console.log(`[emit:${emitter.name}] ${file}`)
|
||||||
|
} else {
|
||||||
|
log.updateText(`${emitter.name} -> ${styleText("gray", file)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
trace(`Failed to emit from plugin \`${emitter.name}\``, err as Error)
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
export async function emitContent(ctx: BuildCtx, content: ProcessedContent[]) {
|
export async function emitContent(ctx: BuildCtx, content: ProcessedContent[]) {
|
||||||
const { argv, cfg } = ctx
|
const { argv, cfg } = ctx
|
||||||
const perf = new PerfTimer()
|
const perf = new PerfTimer()
|
||||||
@ -15,36 +54,27 @@ export async function emitContent(ctx: BuildCtx, content: ProcessedContent[]) {
|
|||||||
|
|
||||||
let emittedFiles = 0
|
let emittedFiles = 0
|
||||||
const staticResources = getStaticResourcesFromPlugins(ctx)
|
const staticResources = getStaticResourcesFromPlugins(ctx)
|
||||||
await Promise.all(
|
|
||||||
cfg.plugins.emitters.map(async (emitter) => {
|
// Phase 1: Run PageTypeDispatcher first so it populates ctx.virtualPages
|
||||||
try {
|
// with pages generated by page type plugins (tag pages, folder pages, bases pages, etc.)
|
||||||
const emitted = await emitter.emit(ctx, content, staticResources)
|
const dispatcher = cfg.plugins.emitters.find((e) => e.name === "PageTypeDispatcher")
|
||||||
if (Symbol.asyncIterator in emitted) {
|
if (dispatcher) {
|
||||||
// Async generator case
|
ctx.virtualPages = []
|
||||||
for await (const file of emitted) {
|
emittedFiles += await runEmitter(dispatcher, ctx, content, staticResources, log)
|
||||||
emittedFiles++
|
}
|
||||||
if (ctx.argv.verbose) {
|
|
||||||
console.log(`[emit:${emitter.name}] ${file}`)
|
// Phase 2: Run all other emitters with content extended by virtual pages.
|
||||||
} else {
|
// This ensures emitters like ContentIndex include virtual pages in their output
|
||||||
log.updateText(`${emitter.name} -> ${styleText("gray", file)}`)
|
// (e.g. sitemap, RSS, contentIndex.json used by the explorer sidebar).
|
||||||
}
|
const contentWithVirtual =
|
||||||
}
|
ctx.virtualPages.length > 0 ? [...content, ...ctx.virtualPages] : content
|
||||||
} else {
|
const otherEmitters = cfg.plugins.emitters.filter((e) => e.name !== "PageTypeDispatcher")
|
||||||
// Array case
|
const counts = await Promise.all(
|
||||||
emittedFiles += emitted.length
|
otherEmitters.map((emitter) =>
|
||||||
for (const file of emitted) {
|
runEmitter(emitter, ctx, contentWithVirtual, staticResources, log),
|
||||||
if (ctx.argv.verbose) {
|
),
|
||||||
console.log(`[emit:${emitter.name}] ${file}`)
|
|
||||||
} else {
|
|
||||||
log.updateText(`${emitter.name} -> ${styleText("gray", file)}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
trace(`Failed to emit from plugin \`${emitter.name}\``, err as Error)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
emittedFiles += counts.reduce((sum, c) => sum + c, 0)
|
||||||
|
|
||||||
log.end(`Emitted ${emittedFiles} files to \`${argv.output}\` in ${perf.timeSince()}`)
|
log.end(`Emitted ${emittedFiles} files to \`${argv.output}\` in ${perf.timeSince()}`)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { QuartzConfig } from "../cfg"
|
import { QuartzConfig } from "../cfg"
|
||||||
import { QuartzPluginData } from "../plugins/vfile"
|
import { ProcessedContent, QuartzPluginData } from "../plugins/vfile"
|
||||||
import { FileTrieNode } from "./fileTrie"
|
import { FileTrieNode } from "./fileTrie"
|
||||||
import { FilePath, FullSlug } from "./path"
|
import { FilePath, FullSlug } from "./path"
|
||||||
|
|
||||||
@ -29,6 +29,8 @@ export interface BuildCtx {
|
|||||||
allFiles: FilePath[]
|
allFiles: FilePath[]
|
||||||
trie?: FileTrieNode<BuildTimeTrieData>
|
trie?: FileTrieNode<BuildTimeTrieData>
|
||||||
incremental: boolean
|
incremental: boolean
|
||||||
|
/** Virtual pages generated by page type plugins (e.g. tag pages, folder pages, bases pages) */
|
||||||
|
virtualPages: ProcessedContent[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function trieFromAllFiles(allFiles: QuartzPluginData[]): FileTrieNode<BuildTimeTrieData> {
|
export function trieFromAllFiles(allFiles: QuartzPluginData[]): FileTrieNode<BuildTimeTrieData> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user