diff options
Diffstat (limited to 'packages/markdown/remark/src')
-rw-r--r-- | packages/markdown/remark/src/index.ts | 18 | ||||
-rw-r--r-- | packages/markdown/remark/src/remark-prism.ts | 20 | ||||
-rw-r--r-- | packages/markdown/remark/src/remark-scoped-styles.ts | 18 | ||||
-rw-r--r-- | packages/markdown/remark/src/remark-shiki.ts | 46 | ||||
-rw-r--r-- | packages/markdown/remark/src/types.ts | 4 |
5 files changed, 33 insertions, 73 deletions
diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index 43ab885b6..c54826bdc 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -9,9 +9,8 @@ import { toRemarkInitializeAstroData } from './frontmatter-injection.js'; import { loadPlugins } from './load-plugins.js'; import { rehypeHeadingIds } from './rehype-collect-headings.js'; import { remarkCollectImages } from './remark-collect-images.js'; -import remarkPrism from './remark-prism.js'; -import scopedStyles from './remark-scoped-styles.js'; -import remarkShiki from './remark-shiki.js'; +import { remarkPrism } from './remark-prism.js'; +import { remarkShiki } from './remark-shiki.js'; import rehypeRaw from 'rehype-raw'; import rehypeStringify from 'rehype-stringify'; @@ -25,6 +24,8 @@ import { rehypeImages } from './rehype-images.js'; export { rehypeHeadingIds } from './rehype-collect-headings.js'; export { remarkCollectImages } from './remark-collect-images.js'; +export { remarkPrism } from './remark-prism.js'; +export { remarkShiki } from './remark-shiki.js'; export * from './types.js'; export const markdownConfigDefaults: Omit<Required<AstroMarkdownOptions>, 'drafts'> = { @@ -61,7 +62,6 @@ export async function renderMarkdown( frontmatter: userFrontmatter = {}, } = opts; const input = new VFile({ value: content, path: fileURL }); - const scopedClassName = opts.$?.scopedClassName; let parser = unified() .use(markdown) @@ -85,18 +85,14 @@ export async function renderMarkdown( }); if (!isPerformanceBenchmark) { - if (scopedClassName) { - parser.use([scopedStyles(scopedClassName)]); - } - if (syntaxHighlight === 'shiki') { - parser.use([await remarkShiki(shikiConfig, scopedClassName)]); + parser.use(remarkShiki, shikiConfig); } else if (syntaxHighlight === 'prism') { - parser.use([remarkPrism(scopedClassName)]); + parser.use(remarkPrism); } // Apply later in case user plugins resolve relative image paths - parser.use([remarkCollectImages]); + parser.use(remarkCollectImages); } parser.use([ diff --git a/packages/markdown/remark/src/remark-prism.ts b/packages/markdown/remark/src/remark-prism.ts index 6147d9ee9..a3f476d6e 100644 --- a/packages/markdown/remark/src/remark-prism.ts +++ b/packages/markdown/remark/src/remark-prism.ts @@ -1,31 +1,19 @@ import { runHighlighterWithAstro } from '@astrojs/prism/dist/highlighter'; import { visit } from 'unist-util-visit'; +import type { RemarkPlugin } from './types.js'; -type MaybeString = string | null | undefined; - -/** */ -function transformer(className: MaybeString) { +export function remarkPrism(): ReturnType<RemarkPlugin> { return function (tree: any) { - const visitor = (node: any) => { + visit(tree, 'code', (node) => { let { lang, value } = node; node.type = 'html'; let { html, classLanguage } = runHighlighterWithAstro(lang, value); let classes = [classLanguage]; - if (className) { - classes.push(className); - } node.value = `<pre class="${classes.join( ' ' )}"><code is:raw class="${classLanguage}">${html}</code></pre>`; return node; - }; - return visit(tree, 'code', visitor); + }); }; } - -function plugin(className: MaybeString) { - return transformer.bind(null, className); -} - -export default plugin; diff --git a/packages/markdown/remark/src/remark-scoped-styles.ts b/packages/markdown/remark/src/remark-scoped-styles.ts deleted file mode 100644 index ba8780bb7..000000000 --- a/packages/markdown/remark/src/remark-scoped-styles.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { visit } from 'unist-util-visit'; -const noVisit = new Set(['root', 'html', 'text']); - -/** */ -export default function scopedStyles(className: string) { - const visitor = (node: any) => { - if (noVisit.has(node.type)) return; - - const { data } = node; - let currentClassName = data?.hProperties?.class ?? ''; - node.data = node.data || {}; - node.data.hProperties = node.data.hProperties || {}; - node.data.hProperties.class = `${className} ${currentClassName}`.trim(); - - return node; - }; - return () => (tree: any) => visit(tree, visitor); -} diff --git a/packages/markdown/remark/src/remark-shiki.ts b/packages/markdown/remark/src/remark-shiki.ts index 77cbf16c6..6cd3861e5 100644 --- a/packages/markdown/remark/src/remark-shiki.ts +++ b/packages/markdown/remark/src/remark-shiki.ts @@ -1,7 +1,7 @@ import type * as shiki from 'shiki'; import { getHighlighter } from 'shiki'; import { visit } from 'unist-util-visit'; -import type { ShikiConfig } from './types.js'; +import type { RemarkPlugin, ShikiConfig } from './types.js'; /** * getHighlighter() is the most expensive step of Shiki. Instead of calling it on every page, @@ -10,10 +10,11 @@ import type { ShikiConfig } from './types.js'; */ const highlighterCacheAsync = new Map<string, Promise<shiki.Highlighter>>(); -const remarkShiki = async ( - { langs = [], theme = 'github-dark', wrap = false }: ShikiConfig, - scopedClassName?: string | null -) => { +export function remarkShiki({ + langs = [], + theme = 'github-dark', + wrap = false, +}: ShikiConfig = {}): ReturnType<RemarkPlugin> { const cacheID: string = typeof theme === 'string' ? theme : theme.name; let highlighterAsync = highlighterCacheAsync.get(cacheID); if (!highlighterAsync) { @@ -35,15 +36,22 @@ const remarkShiki = async ( }); highlighterCacheAsync.set(cacheID, highlighterAsync); } - const highlighter = await highlighterAsync; - // NOTE: There may be a performance issue here for large sites that use `lang`. - // Since this will be called on every page load. Unclear how to fix this. - for (const lang of langs) { - await highlighter.loadLanguage(lang); - } + let highlighter: shiki.Highlighter; + + return async (tree: any) => { + // Lazily assign the highlighter as async can only happen within this function, + // and not on `remarkShiki` directly. + if (!highlighter) { + highlighter = await highlighterAsync!; + + // NOTE: There may be a performance issue here for large sites that use `lang`. + // Since this will be called on every page load. Unclear how to fix this. + for (const lang of langs) { + await highlighter.loadLanguage(lang); + } + } - return () => (tree: any) => { visit(tree, 'code', (node) => { let lang: string; @@ -69,10 +77,7 @@ const remarkShiki = async ( // <span class="line" // Replace "shiki" class naming with "astro" and add "is:raw". - html = html.replace( - /<pre class="(.*?)shiki(.*?)"/, - `<pre is:raw class="$1astro-code$2${scopedClassName ? ' ' + scopedClassName : ''}"` - ); + html = html.replace(/<pre class="(.*?)shiki(.*?)"/, `<pre is:raw class="$1astro-code$2"`); // Add "user-select: none;" for "+"/"-" diff symbols if (node.lang === 'diff') { html = html.replace( @@ -91,16 +96,9 @@ const remarkShiki = async ( ); } - // Apply scopedClassName to all nested lines - if (scopedClassName) { - html = html.replace(/\<span class="line"\>/g, `<span class="line ${scopedClassName}"`); - } - node.type = 'html'; node.value = html; node.children = []; }); }; -}; - -export default remarkShiki; +} diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts index 6d8ecf8f2..caeebec93 100644 --- a/packages/markdown/remark/src/types.ts +++ b/packages/markdown/remark/src/types.ts @@ -61,10 +61,6 @@ export interface ImageMetadata { export interface MarkdownRenderingOptions extends AstroMarkdownOptions { /** @internal */ fileURL?: URL; - /** @internal */ - $?: { - scopedClassName: string | null; - }; /** Used for frontmatter injection plugins */ frontmatter?: Record<string, any>; } |