mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-05-18 14:34:23 +02:00

For the current setup where people have to fork or at least clone quartz this changes nothing - but it allows you to install quartz as a devDependency via npm and have it actually work. One real change is switch from `.quartz-cache` to `node_modules/.cache/quartz` for transpilation results, this is an artifact from my previous attempts, I guess with this one I can change it back - but `node_modules/.cache` feels more better imo idk. edit: OTOH if you want to have quartz be a _completely_ separate binary (which this also enables I think), having it create a node_modules folder is weird, so I made a quick hack for that for now. Example: ```bash $ mkdir my-repo && cd my-repo $ npm i quartz@necauqua/quartz#untangled # quartz@ prefix is important $ cp node_modules/quartz/quartz.*.ts . # copy the default configs $ mkdir content && echo "# Hello World!" > content/index.md $ npx quartz build --serve # this just works! $ echo 'body { background: red !important; }' > styles.scss ``` Notice how I used my branch in the `npm i` line, ideally it'd be `npm i quartz@jackyzho0/quartz`, or maybe we can somehow get the quartz package on npm and it'll just be `npm i quartz`. In the latter case `npx quartz build` will literally just work without a local npm package at all?. Having some support for components and plugins being in separate npm packages instead of people copying code around is not out of the picture with this too btw. Closes #502 MOVE ME
143 lines
4.3 KiB
TypeScript
143 lines
4.3 KiB
TypeScript
import path from "path"
|
|
import { visit } from "unist-util-visit"
|
|
import { Root } from "hast"
|
|
import { VFile } from "vfile"
|
|
import { QuartzEmitterPlugin } from "../types"
|
|
import { QuartzComponentProps } from "../../components/types"
|
|
import HeaderConstructor from "../../components/Header"
|
|
import BodyConstructor from "../../components/Body"
|
|
import { pageResources, renderPage } from "../../components/renderPage"
|
|
import { FullPageLayout } from "../../cfg"
|
|
import { Argv } from "../../util/ctx"
|
|
import { FilePath, isRelativeURL, joinSegments, pathToRoot } from "../../util/path"
|
|
import { defaultContentPageLayout, sharedPageComponents } from "$layout"
|
|
import { Content } from "../../components"
|
|
import chalk from "chalk"
|
|
import { write } from "./helpers"
|
|
import DepGraph from "../../depgraph"
|
|
|
|
// get all the dependencies for the markdown file
|
|
// eg. images, scripts, stylesheets, transclusions
|
|
const parseDependencies = (argv: Argv, hast: Root, file: VFile): string[] => {
|
|
const dependencies: string[] = []
|
|
|
|
visit(hast, "element", (elem): void => {
|
|
let ref: string | null = null
|
|
|
|
if (
|
|
["script", "img", "audio", "video", "source", "iframe"].includes(elem.tagName) &&
|
|
elem?.properties?.src
|
|
) {
|
|
ref = elem.properties.src.toString()
|
|
} else if (["a", "link"].includes(elem.tagName) && elem?.properties?.href) {
|
|
// transclusions will create a tags with relative hrefs
|
|
ref = elem.properties.href.toString()
|
|
}
|
|
|
|
// if it is a relative url, its a local file and we need to add
|
|
// it to the dependency graph. otherwise, ignore
|
|
if (ref === null || !isRelativeURL(ref)) {
|
|
return
|
|
}
|
|
|
|
let fp = path.join(file.data.filePath!, path.relative(argv.directory, ref)).replace(/\\/g, "/")
|
|
// markdown files have the .md extension stripped in hrefs, add it back here
|
|
if (!fp.split("/").pop()?.includes(".")) {
|
|
fp += ".md"
|
|
}
|
|
dependencies.push(fp)
|
|
})
|
|
|
|
return dependencies
|
|
}
|
|
|
|
export const ContentPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (userOpts) => {
|
|
const opts: FullPageLayout = {
|
|
...sharedPageComponents,
|
|
...defaultContentPageLayout,
|
|
pageBody: Content(),
|
|
...userOpts,
|
|
}
|
|
|
|
const { head: Head, header, beforeBody, pageBody, afterBody, left, right, footer: Footer } = opts
|
|
const Header = HeaderConstructor()
|
|
const Body = BodyConstructor()
|
|
|
|
return {
|
|
name: "ContentPage",
|
|
getQuartzComponents() {
|
|
return [
|
|
Head,
|
|
Header,
|
|
Body,
|
|
...header,
|
|
...beforeBody,
|
|
pageBody,
|
|
...afterBody,
|
|
...left,
|
|
...right,
|
|
Footer,
|
|
]
|
|
},
|
|
async getDependencyGraph(ctx, content, _resources) {
|
|
const graph = new DepGraph<FilePath>()
|
|
|
|
for (const [tree, file] of content) {
|
|
const sourcePath = file.data.filePath!
|
|
const slug = file.data.slug!
|
|
graph.addEdge(sourcePath, joinSegments(ctx.argv.output, slug + ".html") as FilePath)
|
|
|
|
parseDependencies(ctx.argv, tree as Root, file).forEach((dep) => {
|
|
graph.addEdge(dep as FilePath, sourcePath)
|
|
})
|
|
}
|
|
|
|
return graph
|
|
},
|
|
async emit(ctx, content, resources): Promise<FilePath[]> {
|
|
const cfg = ctx.cfg.configuration
|
|
const fps: FilePath[] = []
|
|
const allFiles = content.map((c) => c[1].data)
|
|
|
|
let containsIndex = false
|
|
for (const [tree, file] of content) {
|
|
const slug = file.data.slug!
|
|
if (slug === "index") {
|
|
containsIndex = true
|
|
}
|
|
|
|
const externalResources = pageResources(pathToRoot(slug), file.data, resources)
|
|
const componentData: QuartzComponentProps = {
|
|
ctx,
|
|
fileData: file.data,
|
|
externalResources,
|
|
cfg,
|
|
children: [],
|
|
tree,
|
|
allFiles,
|
|
}
|
|
|
|
const content = renderPage(cfg, slug, componentData, opts, externalResources)
|
|
const fp = await write({
|
|
ctx,
|
|
content,
|
|
slug,
|
|
ext: ".html",
|
|
})
|
|
|
|
fps.push(fp)
|
|
}
|
|
|
|
if (!containsIndex && !ctx.argv.fastRebuild) {
|
|
console.log(
|
|
chalk.yellow(
|
|
`\nWarning: you seem to be missing an \`index.md\` home page file at the root of your \`${ctx.argv.directory}\` folder. This may cause errors when deploying.`,
|
|
),
|
|
)
|
|
}
|
|
|
|
return fps
|
|
},
|
|
}
|
|
}
|