UNPKG

@nolebase/vitepress-plugin-meta

Version:

A vitepress plugin to add <meta> (excerpts, author, authors, etc.) to your rendered pages to maximize SEO and social media sharing capabilities.

87 lines (84 loc) 3.34 kB
import { defu } from 'defu'; import { select, selectAll } from 'hast-util-select'; import { toText } from 'hast-util-to-text'; import RehypeParse from 'rehype-parse'; import RetextStringify from 'retext-stringify'; import { unified } from 'unified'; import { remove } from 'unist-util-remove'; import { removePosition } from 'unist-util-remove-position'; function RehypeRetext(option) { return (nodes) => { const vpDocElement = select(option.selector, nodes); if (!vpDocElement) return; if (vpDocElement.children.length === 0) return; for (const selector of option.removeSelectors) { const elements = selectAll(selector, vpDocElement); if (elements) remove(vpDocElement, elements); } removePosition(vpDocElement); if (nodes.type !== "root" && nodes.type !== "element") return; const text = toText(vpDocElement).replaceAll(/(\n){2,}/g, " "); nodes.children = [{ type: "text", value: text }]; }; } function getMeta(head, fromKey, withValue) { return head.find(([key, attrs]) => key === "meta" && attrs[fromKey] === withValue); } function updateMetaOrCreateMeta(head, fromKey, withValue, asContent) { const meta = head.find(([key, attrs]) => key === "meta" && attrs[fromKey] === withValue); if (meta) { meta[1].content = asContent; return head; } head.push(["meta", { [fromKey]: withValue, content: asContent }]); return head; } function transformHeadMeta(options) { const opts = defu(options, { length: 200, contentSelector: "#VPContent div.content main .vp-doc div", removeContentSelector: [ "h1", "h2", "h3", "h4", "h5", "h6", ".vp-nolebase-page-properties-container", ".vp-nolebase-git-changelog-history-container", ".vp-nolebase-git-changelog-contributors-container" ], useTaglineForHomeLayout: true }); return async (head, context) => { const result = (await unified().data({ settings: { fragment: true } }).use(RehypeParse).use(RehypeRetext, { selector: opts.contentSelector, removeSelectors: opts.removeContentSelector }).use(RetextStringify).process(context.content)).toString(); let excerpt = result.slice(0, opts.length).trim(); if (result.length > opts.length) excerpt += "..."; if (context.pageData.frontmatter?.layout === "home" && opts.useTaglineForHomeLayout) excerpt = context.pageData.frontmatter?.hero?.tagline ?? context.siteConfig.site.description; if (opts.handleExcerpt && typeof opts.handleExcerpt === "function") { const handledResult = opts.handleExcerpt(excerpt, context); if (handledResult && typeof handledResult === "string") excerpt = handledResult; else if (handledResult instanceof Promise) excerpt = await handledResult; } const ogTitle = getMeta(head, "property", "og:title"); if (!ogTitle && context.pageData.title) head = updateMetaOrCreateMeta(head, "property", "og:title", context.pageData.title); head = updateMetaOrCreateMeta(head, "name", "description", excerpt); head = updateMetaOrCreateMeta(head, "property", "og:description", excerpt); head = updateMetaOrCreateMeta(head, "property", "twitter:description", excerpt); return head; }; } export { transformHeadMeta }; //# sourceMappingURL=index.mjs.map