Skip to content

Commit 4bc3636

Browse files
committed
chore(shiki): only send required langs to client
1 parent da768d0 commit 4bc3636

8 files changed

Lines changed: 119 additions & 117 deletions

File tree

apps/site/components/Downloads/Release/ReleaseCodeBox.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { highlightToHtml } from '@node-core/rehype-shiki';
3+
import { highlightToHtml } from '@node-core/rehype-shiki/minimal';
44
import AlertBox from '@node-core/ui-components/Common/AlertBox';
55
import Skeleton from '@node-core/ui-components/Common/Skeleton';
66
import { useTranslations } from 'next-intl';

apps/site/next.mdx.plugins.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
import rehypeShikiji from '@node-core/rehype-shiki';
3+
import rehypeShikiji from '@node-core/rehype-shiki/plugin';
44
import remarkHeadings from '@vcarl/remark-headings';
55
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
66
import rehypeSlug from 'rehype-slug';

packages/rehype-shiki/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
{
22
"name": "@node-core/rehype-shiki",
33
"type": "module",
4-
"main": "./src/index.mjs",
5-
"module": "./src/index.mjs",
4+
"exports": {
5+
".": "./src/index.mjs",
6+
"./*": "./src/*.mjs"
7+
},
68
"scripts": {
79
"lint:js": "eslint \"**/*.mjs\"",
810
"test": "node --test"
Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,66 @@
11
import { createHighlighterCoreSync } from '@shikijs/core';
22
import { createJavaScriptRegexEngine } from '@shikijs/engine-javascript';
3+
import shikiNordTheme from 'shiki/themes/nord.mjs';
34

4-
import { LANGUAGES, DEFAULT_THEME } from './languages.mjs';
5-
6-
let _shiki;
7-
8-
/**
9-
* Lazy-load and memoize the minimal Shikiji Syntax Highlighter
10-
* @returns {import('@shikijs/core').HighlighterCore}
11-
*/
12-
export const getShiki = () => {
13-
if (!_shiki) {
14-
_shiki = createHighlighterCoreSync({
15-
themes: [DEFAULT_THEME],
16-
langs: LANGUAGES,
17-
// Let's use Shiki's new Experimental JavaScript-based regex engine!
18-
engine: createJavaScriptRegexEngine(),
19-
});
20-
}
21-
return _shiki;
5+
const DEFAULT_THEME = {
6+
// We updating this color because the background color and comment text color
7+
// in the Codebox component do not comply with accessibility standards
8+
// @see https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html
9+
colorReplacements: { '#616e88': '#707e99' },
10+
...shikiNordTheme,
2211
};
2312

2413
/**
25-
* Highlights code and returns the inner HTML inside the <code> tag
26-
*
27-
* @param {string} code - The code to highlight
28-
* @param {string} language - The programming language to use for highlighting
29-
* @returns {string} The inner HTML of the highlighted code
14+
* Creates a syntax highlighter with utility functions
15+
* @param {import('@shikijs/core').HighlighterCoreOptions} options - Configuration options for the highlighter
3016
*/
31-
export const highlightToHtml = (code, language) =>
32-
getShiki()
33-
.codeToHtml(code, { lang: language, theme: DEFAULT_THEME })
34-
// Shiki will always return the Highlighted code encapsulated in a <pre> and <code> tag
35-
// since our own CodeBox component handles the <code> tag, we just want to extract
36-
// the inner highlighted code to the CodeBox
37-
.match(/<code>(.+?)<\/code>/s)[1];
17+
export const createHighlighter = options => {
18+
const shiki = createHighlighterCoreSync({
19+
themes: [DEFAULT_THEME],
20+
langs: [],
21+
engine: createJavaScriptRegexEngine(),
22+
...options,
23+
});
24+
const theme = options.themes?.[0] ?? DEFAULT_THEME;
3825

39-
/**
40-
* Highlights code and returns a HAST tree
41-
*
42-
* @param {string} code - The code to highlight
43-
* @param {string} language - The programming language to use for highlighting
44-
* @returns {import('hast').Element} The HAST representation of the highlighted code
45-
*/
46-
export const highlightToHast = (code, language) =>
47-
getShiki().codeToHast(code, { lang: language, theme: DEFAULT_THEME });
26+
const getLanguageDisplayName = language => {
27+
const languageByIdOrAlias = options.langs.find(
28+
({ name, aliases }) =>
29+
name.toLowerCase() === language.toLowerCase() ||
30+
(aliases !== undefined && aliases.includes(language.toLowerCase()))
31+
);
32+
33+
return languageByIdOrAlias?.displayName ?? language;
34+
};
35+
36+
/**
37+
* Highlights code and returns the inner HTML inside the <code> tag
38+
*
39+
* @param {string} code - The code to highlight
40+
* @param {string} language - The programming language to use for highlighting
41+
* @returns {string} The inner HTML of the highlighted code
42+
*/
43+
const highlightToHtml = (code, language) =>
44+
shiki
45+
.codeToHtml(code, { lang: language, theme })
46+
// Shiki will always return the Highlighted code encapsulated in a <pre> and <code> tag
47+
// since our own CodeBox component handles the <code> tag, we just want to extract
48+
// the inner highlighted code to the CodeBox
49+
.match(/<code>(.+?)<\/code>/s)[1];
50+
51+
/**
52+
* Highlights code and returns a HAST tree
53+
*
54+
* @param {string} code - The code to highlight
55+
* @param {string} language - The programming language to use for highlighting
56+
*/
57+
const highlightToHast = (code, language) =>
58+
shiki.codeToHast(code, { lang: language, theme });
59+
60+
return {
61+
shiki,
62+
getLanguageDisplayName,
63+
highlightToHtml,
64+
highlightToHast,
65+
};
66+
};
Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,43 @@
1-
import { rehypeShikiji } from './plugin.mjs';
2-
export * from './highlighter.mjs';
3-
export * from './languages.mjs';
1+
import cLanguage from 'shiki/langs/c.mjs';
2+
import coffeeScriptLanguage from 'shiki/langs/coffeescript.mjs';
3+
import cPlusPlusLanguage from 'shiki/langs/cpp.mjs';
4+
import diffLanguage from 'shiki/langs/diff.mjs';
5+
import dockerLanguage from 'shiki/langs/docker.mjs';
6+
import httpLanguage from 'shiki/langs/http.mjs';
7+
import iniLanguage from 'shiki/langs/ini.mjs';
8+
import javaScriptLanguage from 'shiki/langs/javascript.mjs';
9+
import jsonLanguage from 'shiki/langs/json.mjs';
10+
import powershellLanguage from 'shiki/langs/powershell.mjs';
11+
import shellScriptLanguage from 'shiki/langs/shellscript.mjs';
12+
import shellSessionLanguage from 'shiki/langs/shellsession.mjs';
13+
import typeScriptLanguage from 'shiki/langs/typescript.mjs';
14+
import yamlLanguage from 'shiki/langs/yaml.mjs';
415

5-
export default rehypeShikiji;
16+
import { createHighlighter } from './highlighter.mjs';
17+
18+
const { shiki, getLanguageDisplayName, highlightToHast, highlightToHtml } =
19+
createHighlighter({
20+
langs: [
21+
...cLanguage,
22+
...coffeeScriptLanguage,
23+
...cPlusPlusLanguage,
24+
...diffLanguage,
25+
...dockerLanguage,
26+
...httpLanguage,
27+
...iniLanguage,
28+
{
29+
...javaScriptLanguage[0],
30+
// We patch the JavaScript language to include the CommonJS and ES Module aliases
31+
// that are commonly used (non-standard aliases) within our API docs and Blog posts
32+
aliases: javaScriptLanguage[0].aliases.concat('cjs', 'mjs'),
33+
},
34+
...jsonLanguage,
35+
...powershellLanguage,
36+
...shellScriptLanguage,
37+
...shellSessionLanguage,
38+
...typeScriptLanguage,
39+
...yamlLanguage,
40+
],
41+
});
42+
43+
export { shiki, getLanguageDisplayName, highlightToHast, highlightToHtml };

packages/rehype-shiki/src/languages.mjs

Lines changed: 0 additions & 68 deletions
This file was deleted.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import powershellLanguage from 'shiki/langs/powershell.mjs';
2+
import shellScriptLanguage from 'shiki/langs/shellscript.mjs';
3+
4+
import { createHighlighter } from './highlighter.mjs';
5+
6+
const { shiki, getLanguageDisplayName, highlightToHast, highlightToHtml } =
7+
createHighlighter({
8+
langs: [...powershellLanguage, ...shellScriptLanguage],
9+
});
10+
11+
export { shiki, getLanguageDisplayName, highlightToHast, highlightToHtml };

packages/rehype-shiki/src/plugin.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import classNames from 'classnames';
44
import { toString } from 'hast-util-to-string';
55
import { SKIP, visit } from 'unist-util-visit';
66

7-
import { highlightToHast } from './highlighter.mjs';
7+
import { highlightToHast } from '.';
88

99
// This is what Remark will use as prefix within a <pre> className
1010
// to attribute the current language of the <pre> element
@@ -53,7 +53,7 @@ function isCodeBlock(node) {
5353
);
5454
}
5555

56-
export function rehypeShikiji() {
56+
export default function rehypeShikiji() {
5757
return function (tree) {
5858
visit(tree, 'element', (_, index, parent) => {
5959
const languages = [];

0 commit comments

Comments
 (0)