summaryrefslogtreecommitdiff
path: root/packages/integrations/mdx/src
diff options
context:
space:
mode:
authorGravatar Bjorn Lu <bjornlu.dev@gmail.com> 2023-09-07 22:28:02 +0800
committerGravatar GitHub <noreply@github.com> 2023-09-07 22:28:02 +0800
commitf3f62a5a20f4881bb04f65f192df8e1ccf7fb601 (patch)
treebcbae285c9ef23257c480861aa14622032a954d7 /packages/integrations/mdx/src
parent0fa483283e54c94f173838cd558dc0dbdd11e699 (diff)
downloadastro-f3f62a5a20f4881bb04f65f192df8e1ccf7fb601.tar.gz
astro-f3f62a5a20f4881bb04f65f192df8e1ccf7fb601.tar.zst
astro-f3f62a5a20f4881bb04f65f192df8e1ccf7fb601.zip
Refactor mdx remark plugins (#8430)
Diffstat (limited to 'packages/integrations/mdx/src')
-rw-r--r--packages/integrations/mdx/src/plugins.ts11
-rw-r--r--packages/integrations/mdx/src/remark-prism.ts18
-rw-r--r--packages/integrations/mdx/src/remark-shiki.ts94
3 files changed, 7 insertions, 116 deletions
diff --git a/packages/integrations/mdx/src/plugins.ts b/packages/integrations/mdx/src/plugins.ts
index 5d7b9b58c..a3d9e4ff3 100644
--- a/packages/integrations/mdx/src/plugins.ts
+++ b/packages/integrations/mdx/src/plugins.ts
@@ -1,4 +1,9 @@
-import { rehypeHeadingIds, remarkCollectImages } from '@astrojs/markdown-remark';
+import {
+ rehypeHeadingIds,
+ remarkCollectImages,
+ remarkPrism,
+ remarkShiki,
+} from '@astrojs/markdown-remark';
import {
InvalidAstroDataError,
safelyGetAstroData,
@@ -16,8 +21,6 @@ import { rehypeInjectHeadingsExport } from './rehype-collect-headings.js';
import rehypeMetaString from './rehype-meta-string.js';
import { rehypeOptimizeStatic } from './rehype-optimize-static.js';
import { remarkImageToComponent } from './remark-images-to-component.js';
-import remarkPrism from './remark-prism.js';
-import remarkShiki from './remark-shiki.js';
import { jsToTreeNode } from './utils.js';
// Skip nonessential plugins during performance benchmark runs
@@ -112,7 +115,7 @@ export async function getRemarkPlugins(mdxOptions: MdxOptions): Promise<Pluggabl
if (!isPerformanceBenchmark) {
// Apply syntax highlighters after user plugins to match `markdown/remark` behavior
if (mdxOptions.syntaxHighlight === 'shiki') {
- remarkPlugins.push([await remarkShiki(mdxOptions.shikiConfig)]);
+ remarkPlugins.push([remarkShiki, mdxOptions.shikiConfig]);
}
if (mdxOptions.syntaxHighlight === 'prism') {
remarkPlugins.push(remarkPrism);
diff --git a/packages/integrations/mdx/src/remark-prism.ts b/packages/integrations/mdx/src/remark-prism.ts
deleted file mode 100644
index 7dc05f358..000000000
--- a/packages/integrations/mdx/src/remark-prism.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { runHighlighterWithAstro } from '@astrojs/prism/dist/highlighter';
-import { visit } from 'unist-util-visit';
-
-/** */
-export default function remarkPrism() {
- return (tree: any) =>
- visit(tree, 'code', (node: any) => {
- let { lang, value } = node;
- node.type = 'html';
-
- let { html, classLanguage } = runHighlighterWithAstro(lang, value);
- let classes = [classLanguage];
- node.value = `<pre class="${classes.join(
- ' '
- )}"><code class="${classLanguage}">${html}</code></pre>`;
- return node;
- });
-}
diff --git a/packages/integrations/mdx/src/remark-shiki.ts b/packages/integrations/mdx/src/remark-shiki.ts
deleted file mode 100644
index a241aaa4e..000000000
--- a/packages/integrations/mdx/src/remark-shiki.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import type { ShikiConfig } from 'astro';
-import type * as shiki from 'shiki';
-import { getHighlighter } from 'shiki';
-import { visit } from 'unist-util-visit';
-
-/**
- * getHighlighter() is the most expensive step of Shiki. Instead of calling it on every page,
- * cache it here as much as possible. Make sure that your highlighters can be cached, state-free.
- * We make this async, so that multiple calls to parse markdown still share the same highlighter.
- */
-const highlighterCacheAsync = new Map<string, Promise<shiki.Highlighter>>();
-
-const remarkShiki = async ({ langs = [], theme = 'github-dark', wrap = false }: ShikiConfig) => {
- const cacheID: string = typeof theme === 'string' ? theme : theme.name;
- let highlighterAsync = highlighterCacheAsync.get(cacheID);
- if (!highlighterAsync) {
- highlighterAsync = getHighlighter({ theme }).then((hl) => {
- hl.setColorReplacements({
- '#000001': 'var(--astro-code-color-text)',
- '#000002': 'var(--astro-code-color-background)',
- '#000004': 'var(--astro-code-token-constant)',
- '#000005': 'var(--astro-code-token-string)',
- '#000006': 'var(--astro-code-token-comment)',
- '#000007': 'var(--astro-code-token-keyword)',
- '#000008': 'var(--astro-code-token-parameter)',
- '#000009': 'var(--astro-code-token-function)',
- '#000010': 'var(--astro-code-token-string-expression)',
- '#000011': 'var(--astro-code-token-punctuation)',
- '#000012': 'var(--astro-code-token-link)',
- });
- return hl;
- });
- 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);
- }
-
- return () => (tree: any) => {
- visit(tree, 'code', (node) => {
- let lang: string;
-
- if (typeof node.lang === 'string') {
- const langExists = highlighter.getLoadedLanguages().includes(node.lang);
- if (langExists) {
- lang = node.lang;
- } else {
- console.warn(`The language "${node.lang}" doesn't exist, falling back to plaintext.`);
- lang = 'plaintext';
- }
- } else {
- lang = 'plaintext';
- }
-
- let html = highlighter.codeToHtml(node.value, { lang });
-
- // Q: Couldn't these regexes match on a user's inputted code blocks?
- // A: Nope! All rendered HTML is properly escaped.
- // Ex. If a user typed `<span class="line"` into a code block,
- // It would become this before hitting our regexes:
- // &lt;span class=&quot;line&quot;
-
- // Replace "shiki" class naming with "astro".
- html = html.replace(/<pre class="(.*?)shiki(.*?)"/, `<pre class="$1astro-code$2"`);
- // Add "user-select: none;" for "+"/"-" diff symbols
- if (node.lang === 'diff') {
- html = html.replace(
- /<span class="line"><span style="(.*?)">([\+|\-])/g,
- '<span class="line"><span style="$1"><span style="user-select: none;">$2</span>'
- );
- }
- // Handle code wrapping
- // if wrap=null, do nothing.
- if (wrap === false) {
- html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto;"');
- } else if (wrap === true) {
- html = html.replace(
- /style="(.*?)"/,
- 'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'
- );
- }
-
- node.type = 'html';
- node.value = html;
- node.children = [];
- });
- };
-};
-
-export default remarkShiki;