Skip to content

Commit

Permalink
use shiki to replace hilightlight.js (#46)
Browse files Browse the repository at this point in the history
* use shiki to replace hilightlight.js

* minimize unnecessary language deps

---------

Co-authored-by: blucas.wu <blucas.wu@huolala.cn>
  • Loading branch information
wqcstrong and blucas.wu authored Oct 11, 2023
1 parent fb094e1 commit b2eeaf5
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 53 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
"clsx": "^1.2.1",
"copy-to-clipboard": "^3.3.3",
"error-stack-parser": "^2.1.4",
"highlight.js": "^11.7.0",
"i18next": "^22.4.10",
"i18next-browser-languagedetector": "^7.0.1",
"immer": "^10.0.1",
Expand Down
18 changes: 10 additions & 8 deletions src/components/CodeBlock/index.less
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
.code-block {
position: relative;
overflow: hidden;
@import (less) 'highlight.js/styles/base16/dracula.css';
pre code {
padding: 32px 20px 24px !important;
font-size: 16px;
line-height: 1.2;
font-family: Cascadia Code, Menlo, Courier, monospace;
pre {
padding: 24px;
border-radius: 12px;
overflow: auto;
code {
font-size: 14px;
line-height: 1.2;
font-family: Cascadia Code, Menlo, Courier, monospace;
}
}

.copy-code {
visibility: hidden;
position: absolute;
right: 0;
top: 0;
padding: 5px 16px;
padding: 4px 12px;
border-bottom-left-radius: 8px;
background-color: rgba(255, 255, 255, 0.3);
color: #fff;
font-size: 14px;
font-size: 12px;
border: none;
cursor: pointer;
}
Expand Down
28 changes: 15 additions & 13 deletions src/components/CodeBlock/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import clsx from 'clsx';
import hljs from 'highlight.js';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import './index.less';
import copy from 'copy-to-clipboard';
import { Space } from 'antd';
import { CheckOutlined } from '@ant-design/icons';
import sh from '@/utils/shiki-highlighter';
import { useAsyncEffect } from 'ahooks';

interface Props {
code: string;
Expand All @@ -17,8 +17,13 @@ export const CodeBlock = ({
codeType = 'language-html',
showCopy = true,
}: Props) => {
const codeContent = useMemo(() => {
return hljs.highlightAuto(code).value;
const [codeContent, setCodeContent] = useState('');
useAsyncEffect(async () => {
const highlighter = await sh.get();
const content = highlighter.codeToHtml(code, {
lang: 'html',
});
setCodeContent(content);
}, [code]);

const [copyStatus, setCopyStatus] = useState(false);
Expand Down Expand Up @@ -54,14 +59,11 @@ export const CodeBlock = ({
)}
</button>
)}
<pre>
<code
className={clsx('hljs', codeType)}
dangerouslySetInnerHTML={{
__html: codeContent,
}}
/>
</pre>
<div
dangerouslySetInnerHTML={{
__html: codeContent,
}}
/>
</div>
);
};
3 changes: 1 addition & 2 deletions src/components/InjectSDK/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ export const InjectSDKModal = ({
),
code: `<script>
window.$pageSpy = new PageSpy();
</script>
`,
</script>`,
},
{
title: t('inject.pass-config'),
Expand Down
7 changes: 3 additions & 4 deletions src/pages/Devtools/ElementPanel/index.less
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@controllerBtnSize: 14px;
.element-panel {
@import (less) 'highlight.js/styles/stackoverflow-light.css';
.element-item {
display: flex;
justify-content: flex-start;
Expand All @@ -18,14 +17,14 @@
.element-controller {
width: @controllerBtnSize;
height: @controllerBtnSize;
&__btn {
// margin-top: 4px;
}
}
.element-content {
font-size: 12px;
line-height: 1.4;
word-break: break-all;
code {
font-size: 12px;
}
&__header,
&__footer {
color: #9b8a9b;
Expand Down
46 changes: 30 additions & 16 deletions src/pages/Devtools/ElementPanel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import React, { memo } from 'react';
import { CaretRightOutlined } from '@ant-design/icons';
import { useMemo, useState } from 'react';
import hljs from 'highlight.js';
import javascript from 'highlight.js/lib/languages/javascript';
import css from 'highlight.js/lib/languages/css';
import './index.less';
import type { ElementContent, Element } from 'hast';
import { camelcaseToHypen, replaceProperties } from './utils';
import { useSocketMessageStore } from '@/store/socket-message';

hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('css', css);
import { useAsyncEffect } from 'ahooks';
import sh from '@/utils/shiki-highlighter';
import type { Lang } from 'shiki';

const tag2lang = {
style: 'css',
Expand All @@ -27,15 +24,15 @@ const getTextBlockLang = (parentNode: Element) => {
return 'text';
};

function hasMemebers(data: any) {
function hasMembers(data: any) {
return !!data && Object.keys(data).length > 0;
}

const ElementAttrs: React.FC<{ data?: Record<string, any> }> = ({
data = {},
}) => {
const attrs = useMemo(() => {
if (!hasMemebers(data)) return '';
if (!hasMembers(data)) return '';
return Object.entries(data).map(([key, val]) => {
const prop = camelcaseToHypen(replaceProperties(key));
return (
Expand Down Expand Up @@ -65,6 +62,29 @@ function ElementItem({
}) {
const [spread, setSpread] = useState(false);
const { type } = ast;

const [textContent, setTextContent] = useState('');
useAsyncEffect(async () => {
if (type !== 'text') return;
console.log({ ast });

const { value } = ast;
const content = value.trim();
if (!content) {
setTextContent('');
return;
}
const highlighter = await sh.get({
lang: lang as Lang,
theme: 'github-light',
});
const result = highlighter.codeToHtml(content, {
lang,
theme: 'github-light',
});
setTextContent(result);
}, [ast]);

if (type === 'element') {
const { tagName, properties, children } = ast as Element;

Expand Down Expand Up @@ -109,16 +129,10 @@ function ElementItem({
);
}
if (type === 'text') {
const { value } = ast;
const content = value.trim();
if (!content) return null;
const htmlString = hljs.highlight(content, {
language: lang,
}).value;
return (
<code
<div
className="element-item plain-text"
dangerouslySetInnerHTML={{ __html: htmlString }}
dangerouslySetInnerHTML={{ __html: textContent }}
/>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/store/socket-message/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const getFixedPageMsg = async (htmlText: string, base: string) => {
const html = file.toString();

const tree = processor.parse(file).children as ElementContent[];
console.log(tree);
return {
tree,
html,
Expand Down
3 changes: 2 additions & 1 deletion src/utils/parseError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ const locateSourceCode = (data: {
[];
const sourceContent = list.join('\n');
const lang = getFileExtension(source) || 'js';
const highlighter = await sh.get(lang as Lang);
const highlighter = await sh.get();
const sourceHTML = highlighter.codeToHtml(sourceContent, {
lang,
theme: 'github-dark',
});
resolve({
line,
Expand Down
18 changes: 15 additions & 3 deletions src/utils/shiki-highlighter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { BUNDLED_LANGUAGES, Highlighter, Lang } from 'shiki';
import {
BUNDLED_LANGUAGES,
BUNDLED_THEMES,
Highlighter,
Lang,
Theme,
} from 'shiki';

class ShikiHighlighter {
private highlighter: Highlighter | null = null;
Expand All @@ -10,15 +16,16 @@ class ShikiHighlighter {
private async init() {
this.highlighter = await window.shiki.getHighlighter({
theme: 'github-dark',
langs: ['js', 'jsx', 'ts', 'tsx', 'mdx', 'vue', 'html'],
langs: ['js', 'jsx', 'ts', 'tsx'],
});
}

// eslint-disable-next-line @typescript-eslint/member-ordering
public async get(lang?: Lang) {
public async get(opts?: { lang?: Lang; theme?: Theme }) {
if (!this.highlighter) {
await this.init();
}
const { lang, theme } = opts || {};
if (lang && !this.highlighter?.getLoadedLanguages().includes(lang)) {
const bundles = BUNDLED_LANGUAGES.filter((bundle) => {
return bundle.id === lang || bundle.aliases?.includes(lang);
Expand All @@ -27,6 +34,11 @@ class ShikiHighlighter {
await this.highlighter?.loadLanguage(lang);
}
}
if (theme && !this.highlighter?.getLoadedThemes().includes(theme)) {
if (BUNDLED_THEMES.includes(theme)) {
await this.highlighter?.loadTheme(theme);
}
}
return this.highlighter!;
}
}
Expand Down
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2602,11 +2602,6 @@ hastscript@^7.0.0:
property-information "^6.0.0"
space-separated-tokens "^2.0.0"

highlight.js@^11.7.0:
version "11.8.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.8.0.tgz#966518ea83257bae2e7c9a48596231856555bb65"
integrity sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==

html-parse-stringify@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
Expand Down

0 comments on commit b2eeaf5

Please sign in to comment.