mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-19 10:54:06 -06:00
Merge c097dee535 into e6cc9ba368
This commit is contained in:
commit
08fa7e8ef3
@ -2,6 +2,10 @@
|
||||
title: AliasRedirects
|
||||
tags:
|
||||
- plugin/emitter
|
||||
permalink: "permalink"
|
||||
alias:
|
||||
- "alias"
|
||||
- "aliases"
|
||||
---
|
||||
|
||||
This plugin emits HTML redirect pages for aliases and permalinks defined in the frontmatter of content files.
|
||||
@ -11,14 +15,15 @@ For example, A `foo.md` has the following frontmatter
|
||||
```md title="foo.md"
|
||||
---
|
||||
title: "Foo"
|
||||
permalink: "bar"
|
||||
alias:
|
||||
- "bar"
|
||||
- "baz"
|
||||
---
|
||||
```
|
||||
|
||||
The target `host.me/bar` will be redirected to `host.me/foo`
|
||||
The target `host.me/bar` and `host.me/baz` will be redirected to `host.me/foo`
|
||||
|
||||
Note that these are permanent redirect.
|
||||
Note that these are permanent redirects.
|
||||
|
||||
The emitter supports the following aliases:
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { FullSlug, isRelativeURL, resolveRelative, simplifySlug } from "../../util/path"
|
||||
import { FullSlug, FilePath, joinSegments, isRelativeURL, resolveRelative, simplifySlug } from "../../util/path"
|
||||
import { QuartzEmitterPlugin } from "../types"
|
||||
import { write } from "./helpers"
|
||||
import { BuildCtx } from "../../util/ctx"
|
||||
@ -38,17 +38,45 @@ async function* processFile(ctx: BuildCtx, file: VFile) {
|
||||
|
||||
export const AliasRedirects: QuartzEmitterPlugin = () => ({
|
||||
name: "AliasRedirects",
|
||||
async *emit(ctx, content) {
|
||||
for (const [_tree, file] of content) {
|
||||
yield* processFile(ctx, file)
|
||||
}
|
||||
},
|
||||
async *partialEmit(ctx, _content, _resources, changeEvents) {
|
||||
for (const changeEvent of changeEvents) {
|
||||
if (!changeEvent.file) continue
|
||||
if (changeEvent.type === "add" || changeEvent.type === "change") {
|
||||
// add new ones if this file still exists
|
||||
yield* processFile(ctx, changeEvent.file)
|
||||
}
|
||||
},
|
||||
async emit(ctx, content, _resources): Promise<FilePath[]> {
|
||||
const { argv } = ctx
|
||||
const fps: FilePath[] = []
|
||||
|
||||
for (const [_tree, file] of content) {
|
||||
const ogSlug = simplifySlug(file.data.slug!)
|
||||
|
||||
const slugs = [file.data.frontmatter?.permalink || [], ...(file.data.aliases || [])]
|
||||
|
||||
for (const slug of slugs ?? []) {
|
||||
if (typeof slug !== "string") continue
|
||||
const redirUrl = file.data.slug!
|
||||
const fp = await write({
|
||||
ctx,
|
||||
content: `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>${ogSlug}</title>
|
||||
<link rel="canonical" href="${redirUrl}">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=${redirUrl}">
|
||||
</head>
|
||||
</html>
|
||||
`,
|
||||
slug: slug as FullSlug,
|
||||
ext: ".html",
|
||||
})
|
||||
|
||||
fps.push(fp)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -3,9 +3,12 @@ import remarkFrontmatter from "remark-frontmatter"
|
||||
import { QuartzTransformerPlugin } from "../types"
|
||||
import yaml from "js-yaml"
|
||||
import toml from "toml"
|
||||
import { FilePath, FullSlug, getFileExtension, slugifyFilePath, slugTag } from "../../util/path"
|
||||
import { FilePath, FullSlug, getFileExtension, joinSegments, slugifyFilePath, slugTag } from "../../util/path"
|
||||
import { QuartzPluginData } from "../vfile"
|
||||
import { i18n } from "../../i18n"
|
||||
import { Argv } from "../../util/ctx"
|
||||
import { VFile } from "vfile"
|
||||
|
||||
|
||||
export interface Options {
|
||||
delimiters: string | [string, string]
|
||||
@ -19,7 +22,10 @@ const defaultOptions: Options = {
|
||||
|
||||
function coalesceAliases(data: { [key: string]: any }, aliases: string[]) {
|
||||
for (const alias of aliases) {
|
||||
if (data[alias] !== undefined && data[alias] !== null) return data[alias]
|
||||
if (data[alias] !== undefined && data[alias] !== null) {
|
||||
if (typeof data[alias] === "string") return [data[alias]]
|
||||
return data[alias]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,13 +46,14 @@ function coerceToArray(input: string | string[]): string[] | undefined {
|
||||
.map((tag: string | number) => tag.toString())
|
||||
}
|
||||
|
||||
function getAliasSlugs(aliases: string[]): FullSlug[] {
|
||||
const res: FullSlug[] = []
|
||||
for (const alias of aliases) {
|
||||
const isMd = getFileExtension(alias) === "md"
|
||||
const mockFp = isMd ? alias : alias + ".md"
|
||||
const slug = slugifyFilePath(mockFp as FilePath)
|
||||
res.push(slug)
|
||||
export function getAliasSlugs(aliases: string[], _argv: Argv, file: VFile): FullSlug[] {
|
||||
const slugs: FullSlug[] = aliases.map(
|
||||
(alias) => (alias.startsWith("/") ? alias : `/${alias}`) as FullSlug,
|
||||
)
|
||||
const permalink = file.data.frontmatter?.permalink
|
||||
if (typeof permalink === "string") {
|
||||
const absolutePermalink = permalink.startsWith("/") ? permalink : `/${permalink}`
|
||||
slugs.push(absolutePermalink as FullSlug)
|
||||
}
|
||||
|
||||
return res
|
||||
@ -145,6 +152,7 @@ declare module "vfile" {
|
||||
published: string
|
||||
description: string
|
||||
socialDescription: string
|
||||
permalink: string
|
||||
publish: boolean | string
|
||||
draft: boolean | string
|
||||
lang: string
|
||||
|
||||
Loading…
Reference in New Issue
Block a user