enhance(frontend): shiki v1に移行 (#13138)

* enhance(frontend): shiki v1に移行

* optimize chunks, エラーを握りつぶす

* wasmを分離

* バンドルサイズの警告の最小値を650kBに引き上げ

* optimize
This commit is contained in:
かっこかり 2024-02-02 15:05:18 +09:00 committed by GitHub
parent e5876440cb
commit 9e1145df81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 37 additions and 52 deletions

View file

@ -60,7 +60,7 @@
"rollup": "4.9.6", "rollup": "4.9.6",
"sanitize-html": "2.11.0", "sanitize-html": "2.11.0",
"sass": "1.70.0", "sass": "1.70.0",
"shiki": "0.14.7", "shiki": "1.0.0-beta.3",
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.160.1", "three": "0.160.1",

View file

@ -5,13 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<template> <template>
<div :class="['codeBlockRoot', { 'codeEditor': codeEditor }]" v-html="html"></div> <div :class="[$style.codeBlockRoot, { [$style.codeEditor]: codeEditor }]" v-html="html"></div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, watch } from 'vue'; import { ref, computed, watch } from 'vue';
import { BUNDLED_LANGUAGES } from 'shiki'; import { bundledLanguagesInfo } from 'shiki';
import type { Lang as ShikiLang } from 'shiki'; import type { BuiltinLanguage } from 'shiki';
import { getHighlighter } from '@/scripts/code-highlighter.js'; import { getHighlighter } from '@/scripts/code-highlighter.js';
const props = defineProps<{ const props = defineProps<{
@ -22,24 +22,25 @@ const props = defineProps<{
const highlighter = await getHighlighter(); const highlighter = await getHighlighter();
const codeLang = ref<ShikiLang | 'aiscript'>('js'); const codeLang = ref<BuiltinLanguage | 'aiscript'>('js');
const html = computed(() => highlighter.codeToHtml(props.code, { const html = computed(() => highlighter.codeToHtml(props.code, {
lang: codeLang.value, lang: codeLang.value,
theme: 'dark-plus', theme: 'dark-plus',
})); }));
async function fetchLanguage(to: string): Promise<void> { async function fetchLanguage(to: string): Promise<void> {
const language = to as ShikiLang; const language = to as BuiltinLanguage;
// Check for the loaded languages, and load the language if it's not loaded yet. // Check for the loaded languages, and load the language if it's not loaded yet.
if (!highlighter.getLoadedLanguages().includes(language)) { if (!highlighter.getLoadedLanguages().includes(language)) {
// Check if the language is supported by Shiki // Check if the language is supported by Shiki
const bundles = BUNDLED_LANGUAGES.filter((bundle) => { const bundles = bundledLanguagesInfo.filter((bundle) => {
// Languages are specified by their id, they can also have aliases (i. e. "js" and "javascript") // Languages are specified by their id, they can also have aliases (i. e. "js" and "javascript")
return bundle.id === language || bundle.aliases?.includes(language); return bundle.id === language || bundle.aliases?.includes(language);
}); });
if (bundles.length > 0) { if (bundles.length > 0) {
await highlighter.loadLanguage(language); console.log(`Loading language: ${language}`);
await highlighter.loadLanguage(bundles[0].import);
codeLang.value = language; codeLang.value = language;
} else { } else {
codeLang.value = 'js'; codeLang.value = 'js';
@ -57,8 +58,8 @@ watch(() => props.lang, (to) => {
}, { immediate: true }); }, { immediate: true });
</script> </script>
<style scoped lang="scss"> <style module lang="scss">
.codeBlockRoot :deep(.shiki) { .codeBlockRoot :global(.shiki) {
padding: 1em; padding: 1em;
margin: .5em 0; margin: .5em 0;
overflow: auto; overflow: auto;
@ -74,7 +75,7 @@ watch(() => props.lang, (to) => {
min-width: 100%; min-width: 100%;
height: 100%; height: 100%;
& :deep(.shiki) { & :global(.shiki) {
padding: 12px; padding: 12px;
margin: 0; margin: 0;
border-radius: 6px; border-radius: 6px;

View file

@ -1,7 +1,6 @@
import { setWasm, setCDN, Highlighter, getHighlighter as _getHighlighter } from 'shiki'; import { getHighlighterCore, loadWasm } from 'shiki/core';
import darkPlus from 'shiki/themes/dark-plus.mjs';
setWasm('/assets/shiki/dist/onig.wasm'); import type { Highlighter, LanguageRegistration } from 'shiki';
setCDN('/assets/shiki/');
let _highlighter: Highlighter | null = null; let _highlighter: Highlighter | null = null;
@ -13,16 +12,19 @@ export async function getHighlighter(): Promise<Highlighter> {
} }
export async function initHighlighter() { export async function initHighlighter() {
const highlighter = await _getHighlighter({ const aiScriptGrammar = await import('aiscript-vscode/aiscript/syntaxes/aiscript.tmLanguage.json');
theme: 'dark-plus',
langs: ['js'],
});
await highlighter.loadLanguage({ await loadWasm(import('shiki/onig.wasm?init'));
path: 'languages/aiscript.tmLanguage.json',
id: 'aiscript', const highlighter = await getHighlighterCore({
scopeName: 'source.aiscript', themes: [darkPlus],
aliases: ['is', 'ais'], langs: [
import('shiki/langs/javascript.mjs'),
{
aliases: ['is', 'ais'],
...aiScriptGrammar.default,
} as unknown as LanguageRegistration,
],
}); });
_highlighter = highlighter; _highlighter = highlighter;

View file

@ -797,8 +797,8 @@ importers:
specifier: 1.70.0 specifier: 1.70.0
version: 1.70.0 version: 1.70.0
shiki: shiki:
specifier: 0.14.7 specifier: 1.0.0-beta.3
version: 0.14.7 version: 1.0.0-beta.3
strict-event-emitter-types: strict-event-emitter-types:
specifier: 2.0.0 specifier: 2.0.0
version: 2.0.0 version: 2.0.0
@ -5951,6 +5951,10 @@ packages:
string-argv: 0.3.1 string-argv: 0.3.1
dev: true dev: true
/@shikijs/core@1.0.0-beta.3:
resolution: {integrity: sha512-SCwPom2Wn8XxNlEeqdzycU93SKgzYeVsedjqDsgZaz4XiiPpZUzlHt2NAEQTwTnPcHNZapZ6vbkwJ8P11ggL3Q==}
dev: false
/@sideway/address@4.1.4: /@sideway/address@4.1.4:
resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==}
dependencies: dependencies:
@ -9297,10 +9301,6 @@ packages:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'} engines: {node: '>=12'}
/ansi-sequence-parser@1.1.1:
resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==}
dev: false
/ansi-styles@3.2.1: /ansi-styles@3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -14693,6 +14693,7 @@ packages:
/jsonc-parser@3.2.0: /jsonc-parser@3.2.0:
resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
dev: true
/jsonfile@4.0.0: /jsonfile@4.0.0:
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
@ -18247,13 +18248,10 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'} engines: {node: '>=8'}
/shiki@0.14.7: /shiki@1.0.0-beta.3:
resolution: {integrity: sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==} resolution: {integrity: sha512-z7cHTNSSvwGx2DfeLwjSNLo+HcVxifgNIzLm6Ye52eXcIwNHXT0wHbhy7FDOKSKveuEHBwt9opfj3Hoc8LE1Yg==}
dependencies: dependencies:
ansi-sequence-parser: 1.1.1 '@shikijs/core': 1.0.0-beta.3
jsonc-parser: 3.2.0
vscode-oniguruma: 1.7.0
vscode-textmate: 8.0.0
dev: false dev: false
/side-channel@1.0.4: /side-channel@1.0.4:
@ -20019,14 +20017,6 @@ packages:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
/vscode-oniguruma@1.7.0:
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==}
dev: false
/vscode-textmate@8.0.0:
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
dev: false
/vue-component-type-helpers@1.8.27: /vue-component-type-helpers@1.8.27:
resolution: {integrity: sha512-0vOfAtI67UjeO1G6UiX5Kd76CqaQ67wrRZiOe7UAb9Jm6GzlUr/fC7CV90XfwapJRjpCMaZFhv1V0ajWRmE9Dg==} resolution: {integrity: sha512-0vOfAtI67UjeO1G6UiX5Kd76CqaQ67wrRZiOe7UAb9Jm6GzlUr/fC7CV90XfwapJRjpCMaZFhv1V0ajWRmE9Dg==}
dev: true dev: true

View file

@ -35,13 +35,6 @@ async function copyFrontendLocales() {
} }
} }
async function copyFrontendShikiAssets() {
await fs.cp('./packages/frontend/node_modules/shiki/dist', './built/_frontend_dist_/shiki/dist', { dereference: true, recursive: true });
await fs.cp('./packages/frontend/node_modules/shiki/languages', './built/_frontend_dist_/shiki/languages', { dereference: true, recursive: true });
await fs.cp('./packages/frontend/node_modules/aiscript-vscode/aiscript/syntaxes', './built/_frontend_dist_/shiki/languages', { dereference: true, recursive: true });
await fs.cp('./packages/frontend/node_modules/shiki/themes', './built/_frontend_dist_/shiki/themes', { dereference: true, recursive: true });
}
async function copyBackendViews() { async function copyBackendViews() {
await fs.cp('./packages/backend/src/server/web/views', './packages/backend/built/server/web/views', { recursive: true }); await fs.cp('./packages/backend/src/server/web/views', './packages/backend/built/server/web/views', { recursive: true });
} }
@ -81,7 +74,6 @@ async function build() {
copyFrontendFonts(), copyFrontendFonts(),
copyFrontendTablerIcons(), copyFrontendTablerIcons(),
copyFrontendLocales(), copyFrontendLocales(),
copyFrontendShikiAssets(),
copyBackendViews(), copyBackendViews(),
buildBackendScript(), buildBackendScript(),
buildBackendStyle(), buildBackendStyle(),