mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-05-19 06:54:18 +02:00
Compare commits
No commits in common. "1bb6f09db1769bdb4cc64cc6afa3c272402765d3" and "7681a8681594ce2e4777bbb401bd7409cbed5915" have entirely different histories.
1bb6f09db1
...
7681a86815
@ -221,26 +221,12 @@ export type QuartzEmitterPlugin<Options extends OptionType = undefined> = (
|
|||||||
|
|
||||||
export type QuartzEmitterPluginInstance = {
|
export type QuartzEmitterPluginInstance = {
|
||||||
name: string
|
name: string
|
||||||
emit(
|
emit(ctx: BuildCtx, content: ProcessedContent[], resources: StaticResources): Promise<FilePath[]>
|
||||||
ctx: BuildCtx,
|
|
||||||
content: ProcessedContent[],
|
|
||||||
resources: StaticResources,
|
|
||||||
): Promise<FilePath[]> | AsyncGenerator<FilePath>
|
|
||||||
partialEmit?(
|
|
||||||
ctx: BuildCtx,
|
|
||||||
content: ProcessedContent[],
|
|
||||||
resources: StaticResources,
|
|
||||||
changeEvents: ChangeEvent[],
|
|
||||||
): Promise<FilePath[]> | AsyncGenerator<FilePath> | null
|
|
||||||
getQuartzComponents(ctx: BuildCtx): QuartzComponent[]
|
getQuartzComponents(ctx: BuildCtx): QuartzComponent[]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
An emitter plugin must define a `name` field, an `emit` function, and a `getQuartzComponents` function. It can optionally implement a `partialEmit` function for incremental builds.
|
An emitter plugin must define a `name` field, an `emit` function, and a `getQuartzComponents` function. `emit` is responsible for looking at all the parsed and filtered content and then appropriately creating files and returning a list of paths to files the plugin created.
|
||||||
|
|
||||||
- `emit` is responsible for looking at all the parsed and filtered content and then appropriately creating files and returning a list of paths to files the plugin created.
|
|
||||||
- `partialEmit` is an optional function that enables incremental builds. It receives information about which files have changed (`changeEvents`) and can selectively rebuild only the necessary files. This is useful for optimizing build times in development mode. If `partialEmit` is undefined, it will default to the `emit` function.
|
|
||||||
- `getQuartzComponents` declares which Quartz components the emitter uses to construct its pages.
|
|
||||||
|
|
||||||
Creating new files can be done via regular Node [fs module](https://nodejs.org/api/fs.html) (i.e. `fs.cp` or `fs.writeFile`) or via the `write` function in `quartz/plugins/emitters/helpers.ts` if you are creating files that contain text. `write` has the following signature:
|
Creating new files can be done via regular Node [fs module](https://nodejs.org/api/fs.html) (i.e. `fs.cp` or `fs.writeFile`) or via the `write` function in `quartz/plugins/emitters/helpers.ts` if you are creating files that contain text. `write` has the following signature:
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ If you prefer instructions in a video format you can try following Nicole van de
|
|||||||
## 🔧 Features
|
## 🔧 Features
|
||||||
|
|
||||||
- [[Obsidian compatibility]], [[full-text search]], [[graph view]], note transclusion, [[wikilinks]], [[backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]], [[comments]] and [many more](./features/) right out of the box
|
- [[Obsidian compatibility]], [[full-text search]], [[graph view]], note transclusion, [[wikilinks]], [[backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]], [[comments]] and [many more](./features/) right out of the box
|
||||||
- Hot-reload on configuration edits and incremental rebuilds for content edits
|
- Hot-reload for both configuration and content
|
||||||
- Simple JSX layouts and [[creating components|page components]]
|
- Simple JSX layouts and [[creating components|page components]]
|
||||||
- [[SPA Routing|Ridiculously fast page loads]] and tiny bundle sizes
|
- [[SPA Routing|Ridiculously fast page loads]] and tiny bundle sizes
|
||||||
- Fully-customizable parsing, filtering, and page generation through [[making plugins|plugins]]
|
- Fully-customizable parsing, filtering, and page generation through [[making plugins|plugins]]
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -35,7 +35,6 @@
|
|||||||
"mdast-util-to-hast": "^13.2.0",
|
"mdast-util-to-hast": "^13.2.0",
|
||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
"micromorph": "^0.4.5",
|
"micromorph": "^0.4.5",
|
||||||
"minimatch": "^10.0.1",
|
|
||||||
"pixi.js": "^8.8.1",
|
"pixi.js": "^8.8.1",
|
||||||
"preact": "^10.26.4",
|
"preact": "^10.26.4",
|
||||||
"preact-render-to-string": "^6.5.13",
|
"preact-render-to-string": "^6.5.13",
|
||||||
@ -5255,7 +5254,6 @@
|
|||||||
"version": "10.0.1",
|
"version": "10.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
|
||||||
"integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
|
"integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^2.0.1"
|
"brace-expansion": "^2.0.1"
|
||||||
},
|
},
|
||||||
|
@ -61,7 +61,6 @@
|
|||||||
"mdast-util-to-hast": "^13.2.0",
|
"mdast-util-to-hast": "^13.2.0",
|
||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
"micromorph": "^0.4.5",
|
"micromorph": "^0.4.5",
|
||||||
"minimatch": "^10.0.1",
|
|
||||||
"pixi.js": "^8.8.1",
|
"pixi.js": "^8.8.1",
|
||||||
"preact": "^10.26.4",
|
"preact": "^10.26.4",
|
||||||
"preact-render-to-string": "^6.5.13",
|
"preact-render-to-string": "^6.5.13",
|
||||||
|
@ -20,7 +20,6 @@ import { Mutex } from "async-mutex"
|
|||||||
import { getStaticResourcesFromPlugins } from "./plugins"
|
import { getStaticResourcesFromPlugins } from "./plugins"
|
||||||
import { randomIdNonSecure } from "./util/random"
|
import { randomIdNonSecure } from "./util/random"
|
||||||
import { ChangeEvent } from "./plugins/types"
|
import { ChangeEvent } from "./plugins/types"
|
||||||
import { minimatch } from "minimatch"
|
|
||||||
|
|
||||||
type ContentMap = Map<
|
type ContentMap = Map<
|
||||||
FilePath,
|
FilePath,
|
||||||
@ -118,23 +117,11 @@ async function startWatching(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const gitIgnoredMatcher = await isGitIgnored()
|
|
||||||
const buildData: BuildData = {
|
const buildData: BuildData = {
|
||||||
ctx,
|
ctx,
|
||||||
mut,
|
mut,
|
||||||
contentMap,
|
contentMap,
|
||||||
ignored: (path) => {
|
ignored: await isGitIgnored(),
|
||||||
if (gitIgnoredMatcher(path)) return true
|
|
||||||
const pathStr = path.toString()
|
|
||||||
for (const pattern of cfg.configuration.ignorePatterns) {
|
|
||||||
if (minimatch(pathStr, pattern)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
|
|
||||||
changesSinceLastBuild: {},
|
changesSinceLastBuild: {},
|
||||||
lastBuildMs: 0,
|
lastBuildMs: 0,
|
||||||
}
|
}
|
||||||
@ -150,17 +137,17 @@ async function startWatching(
|
|||||||
.on("add", (fp) => {
|
.on("add", (fp) => {
|
||||||
if (buildData.ignored(fp)) return
|
if (buildData.ignored(fp)) return
|
||||||
changes.push({ path: fp as FilePath, type: "add" })
|
changes.push({ path: fp as FilePath, type: "add" })
|
||||||
void rebuild(changes, clientRefresh, buildData)
|
rebuild(changes, clientRefresh, buildData)
|
||||||
})
|
})
|
||||||
.on("change", (fp) => {
|
.on("change", (fp) => {
|
||||||
if (buildData.ignored(fp)) return
|
if (buildData.ignored(fp)) return
|
||||||
changes.push({ path: fp as FilePath, type: "change" })
|
changes.push({ path: fp as FilePath, type: "change" })
|
||||||
void rebuild(changes, clientRefresh, buildData)
|
rebuild(changes, clientRefresh, buildData)
|
||||||
})
|
})
|
||||||
.on("unlink", (fp) => {
|
.on("unlink", (fp) => {
|
||||||
if (buildData.ignored(fp)) return
|
if (buildData.ignored(fp)) return
|
||||||
changes.push({ path: fp as FilePath, type: "delete" })
|
changes.push({ path: fp as FilePath, type: "delete" })
|
||||||
void rebuild(changes, clientRefresh, buildData)
|
rebuild(changes, clientRefresh, buildData)
|
||||||
})
|
})
|
||||||
|
|
||||||
return async () => {
|
return async () => {
|
||||||
@ -175,7 +162,6 @@ async function rebuild(changes: ChangeEvent[], clientRefresh: () => void, buildD
|
|||||||
const buildId = randomIdNonSecure()
|
const buildId = randomIdNonSecure()
|
||||||
ctx.buildId = buildId
|
ctx.buildId = buildId
|
||||||
buildData.lastBuildMs = new Date().getTime()
|
buildData.lastBuildMs = new Date().getTime()
|
||||||
const numChangesInBuild = changes.length
|
|
||||||
const release = await mut.acquire()
|
const release = await mut.acquire()
|
||||||
|
|
||||||
// if there's another build after us, release and let them do it
|
// if there's another build after us, release and let them do it
|
||||||
@ -194,19 +180,16 @@ async function rebuild(changes: ChangeEvent[], clientRefresh: () => void, buildD
|
|||||||
}
|
}
|
||||||
|
|
||||||
const staticResources = getStaticResourcesFromPlugins(ctx)
|
const staticResources = getStaticResourcesFromPlugins(ctx)
|
||||||
const pathsToParse: FilePath[] = []
|
|
||||||
for (const [fp, type] of Object.entries(changesSinceLastBuild)) {
|
for (const [fp, type] of Object.entries(changesSinceLastBuild)) {
|
||||||
if (type === "delete" || path.extname(fp) !== ".md") continue
|
if (type === "delete" || path.extname(fp) !== ".md") continue
|
||||||
const fullPath = joinSegments(argv.directory, toPosixPath(fp)) as FilePath
|
const fullPath = joinSegments(argv.directory, toPosixPath(fp)) as FilePath
|
||||||
pathsToParse.push(fullPath)
|
const parsed = await parseMarkdown(ctx, [fullPath])
|
||||||
}
|
for (const content of parsed) {
|
||||||
|
contentMap.set(content[1].data.relativePath!, {
|
||||||
const parsed = await parseMarkdown(ctx, pathsToParse)
|
type: "markdown",
|
||||||
for (const content of parsed) {
|
content,
|
||||||
contentMap.set(content[1].data.relativePath!, {
|
})
|
||||||
type: "markdown",
|
}
|
||||||
content,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update state using changesSinceLastBuild
|
// update state using changesSinceLastBuild
|
||||||
@ -282,7 +265,7 @@ async function rebuild(changes: ChangeEvent[], clientRefresh: () => void, buildD
|
|||||||
|
|
||||||
console.log(`Emitted ${emittedFiles} files to \`${argv.output}\` in ${perf.timeSince("rebuild")}`)
|
console.log(`Emitted ${emittedFiles} files to \`${argv.output}\` in ${perf.timeSince("rebuild")}`)
|
||||||
console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`))
|
console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`))
|
||||||
changes.splice(0, numChangesInBuild)
|
changes.length = 0
|
||||||
clientRefresh()
|
clientRefresh()
|
||||||
release()
|
release()
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,7 @@ export class QuartzLogger {
|
|||||||
private readonly spinnerChars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
private readonly spinnerChars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
||||||
|
|
||||||
constructor(verbose: boolean) {
|
constructor(verbose: boolean) {
|
||||||
const isInteractiveTerminal =
|
this.verbose = verbose
|
||||||
process.stdout.isTTY && process.env.TERM !== "dumb" && !process.env.CI
|
|
||||||
this.verbose = verbose || !isInteractiveTerminal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start(text: string) {
|
start(text: string) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user