mirror of
https://github.com/MisskeyIO/misskey
synced 2024-11-27 14:28:49 +09:00
fix(frontend): shikiの言語・テーマの定義ファイルをCDN(esm.sh)から取るようにする (#13598)
* fix(frontend): shikiの言語・テーマの定義ファイルをCDN(esm.sh)から取るようにする * fix CHANGELOG.md
This commit is contained in:
parent
5f6863b77e
commit
115d91812e
@ -18,6 +18,8 @@
|
|||||||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459)
|
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459)
|
||||||
- Fix: ページタイトルでローカルユーザーとリモートユーザーの区別がつかない問題を修正
|
- Fix: ページタイトルでローカルユーザーとリモートユーザーの区別がつかない問題を修正
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/528)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/528)
|
||||||
|
- Fix: コードブロックのシンタックスハイライトで使用される定義ファイルをCDNから取得するように #13177
|
||||||
|
- CDNから取得せずMisskey本体にバンドルする場合は`pacakges/frontend/vite.config.ts`を修正してください。
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
|
- Enhance: エンドポイント`antennas/update`の必須項目を`antennaId`のみに
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
"rollup": "4.12.0",
|
"rollup": "4.12.0",
|
||||||
"sanitize-html": "2.12.1",
|
"sanitize-html": "2.12.1",
|
||||||
"sass": "1.71.1",
|
"sass": "1.71.1",
|
||||||
"shiki": "1.1.7",
|
"shiki": "1.2.0",
|
||||||
"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.162.0",
|
"three": "0.162.0",
|
||||||
|
@ -9,9 +9,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { bundledLanguagesInfo } from 'shiki';
|
import { bundledLanguagesInfo } from 'shiki/langs';
|
||||||
import type { BuiltinLanguage } from 'shiki';
|
import type { BundledLanguage } from 'shiki/langs';
|
||||||
import { getHighlighter, getTheme } from '@/scripts/code-highlighter.js';
|
import { getHighlighter, getTheme } from '@/scripts/code-highlighter.js';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const highlighter = await getHighlighter();
|
const highlighter = await getHighlighter();
|
||||||
const darkMode = defaultStore.reactiveState.darkMode;
|
const darkMode = defaultStore.reactiveState.darkMode;
|
||||||
const codeLang = ref<BuiltinLanguage | 'aiscript'>('js');
|
const codeLang = ref<BundledLanguage | 'aiscript'>('js');
|
||||||
|
|
||||||
const [lightThemeName, darkThemeName] = await Promise.all([
|
const [lightThemeName, darkThemeName] = await Promise.all([
|
||||||
getTheme('light', true),
|
getTheme('light', true),
|
||||||
@ -42,7 +42,7 @@ const html = computed(() => highlighter.codeToHtml(props.code, {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
async function fetchLanguage(to: string): Promise<void> {
|
async function fetchLanguage(to: string): Promise<void> {
|
||||||
const language = to as BuiltinLanguage;
|
const language = to as BundledLanguage;
|
||||||
|
|
||||||
// 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)) {
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
http-equiv="Content-Security-Policy"
|
http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self' https://newassets.hcaptcha.com/ https://challenges.cloudflare.com/ http://localhost:7493/;
|
content="default-src 'self' https://newassets.hcaptcha.com/ https://challenges.cloudflare.com/ http://localhost:7493/;
|
||||||
worker-src 'self';
|
worker-src 'self';
|
||||||
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com;
|
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com https://esm.sh;
|
||||||
style-src 'self' 'unsafe-inline';
|
style-src 'self' 'unsafe-inline';
|
||||||
img-src 'self' data: blob: www.google.com xn--931a.moe localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
|
img-src 'self' data: blob: www.google.com xn--931a.moe localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
|
||||||
media-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
|
media-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
|
||||||
|
@ -3,18 +3,19 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { bundledThemesInfo } from 'shiki';
|
|
||||||
import { getHighlighterCore, loadWasm } from 'shiki/core';
|
import { getHighlighterCore, loadWasm } from 'shiki/core';
|
||||||
import darkPlus from 'shiki/themes/dark-plus.mjs';
|
import darkPlus from 'shiki/themes/dark-plus.mjs';
|
||||||
|
import { bundledThemesInfo } from 'shiki/themes';
|
||||||
|
import { bundledLanguagesInfo } from 'shiki/langs';
|
||||||
import { unique } from './array.js';
|
import { unique } from './array.js';
|
||||||
import { deepClone } from './clone.js';
|
import { deepClone } from './clone.js';
|
||||||
import { deepMerge } from './merge.js';
|
import { deepMerge } from './merge.js';
|
||||||
import type { Highlighter, LanguageRegistration, ThemeRegistration, ThemeRegistrationRaw } from 'shiki';
|
import type { HighlighterCore, LanguageRegistration, ThemeRegistration, ThemeRegistrationRaw } from 'shiki/core';
|
||||||
import { ColdDeviceStorage } from '@/store.js';
|
import { ColdDeviceStorage } from '@/store.js';
|
||||||
import lightTheme from '@/themes/_light.json5';
|
import lightTheme from '@/themes/_light.json5';
|
||||||
import darkTheme from '@/themes/_dark.json5';
|
import darkTheme from '@/themes/_dark.json5';
|
||||||
|
|
||||||
let _highlighter: Highlighter | null = null;
|
let _highlighter: HighlighterCore | null = null;
|
||||||
|
|
||||||
export async function getTheme(mode: 'light' | 'dark', getName: true): Promise<string>;
|
export async function getTheme(mode: 'light' | 'dark', getName: true): Promise<string>;
|
||||||
export async function getTheme(mode: 'light' | 'dark', getName?: false): Promise<ThemeRegistration | ThemeRegistrationRaw>;
|
export async function getTheme(mode: 'light' | 'dark', getName?: false): Promise<ThemeRegistration | ThemeRegistrationRaw>;
|
||||||
@ -51,16 +52,14 @@ export async function getTheme(mode: 'light' | 'dark', getName = false): Promise
|
|||||||
return darkPlus;
|
return darkPlus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getHighlighter(): Promise<Highlighter> {
|
export async function getHighlighter(): Promise<HighlighterCore> {
|
||||||
if (!_highlighter) {
|
if (!_highlighter) {
|
||||||
return await initHighlighter();
|
return await initHighlighter();
|
||||||
}
|
}
|
||||||
return _highlighter;
|
return _highlighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initHighlighter() {
|
async function initHighlighter() {
|
||||||
const aiScriptGrammar = await import('aiscript-vscode/aiscript/syntaxes/aiscript.tmLanguage.json');
|
|
||||||
|
|
||||||
await loadWasm(import('shiki/onig.wasm?init'));
|
await loadWasm(import('shiki/onig.wasm?init'));
|
||||||
|
|
||||||
// テーマの重複を消す
|
// テーマの重複を消す
|
||||||
@ -69,11 +68,12 @@ export async function initHighlighter() {
|
|||||||
...(await Promise.all([getTheme('light'), getTheme('dark')])),
|
...(await Promise.all([getTheme('light'), getTheme('dark')])),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const jsLangInfo = bundledLanguagesInfo.find(t => t.id === 'javascript');
|
||||||
const highlighter = await getHighlighterCore({
|
const highlighter = await getHighlighterCore({
|
||||||
themes,
|
themes,
|
||||||
langs: [
|
langs: [
|
||||||
import('shiki/langs/javascript.mjs'),
|
...(jsLangInfo ? [async () => await jsLangInfo.import()] : []),
|
||||||
aiScriptGrammar.default as unknown as LanguageRegistration,
|
async () => (await import('aiscript-vscode/aiscript/syntaxes/aiscript.tmLanguage.json')).default as unknown as LanguageRegistration,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import { deepClone } from './clone.js';
|
import { deepClone } from './clone.js';
|
||||||
import type { BuiltinTheme } from 'shiki';
|
import type { BundledTheme } from 'shiki/themes';
|
||||||
import { globalEvents } from '@/events.js';
|
import { globalEvents } from '@/events.js';
|
||||||
import lightTheme from '@/themes/_light.json5';
|
import lightTheme from '@/themes/_light.json5';
|
||||||
import darkTheme from '@/themes/_dark.json5';
|
import darkTheme from '@/themes/_dark.json5';
|
||||||
@ -20,7 +20,7 @@ export type Theme = {
|
|||||||
base?: 'dark' | 'light';
|
base?: 'dark' | 'light';
|
||||||
props: Record<string, string>;
|
props: Record<string, string>;
|
||||||
codeHighlighter?: {
|
codeHighlighter?: {
|
||||||
base: BuiltinTheme;
|
base: BundledTheme;
|
||||||
overrides?: Record<string, any>;
|
overrides?: Record<string, any>;
|
||||||
} | {
|
} | {
|
||||||
base: '_none_';
|
base: '_none_';
|
||||||
|
@ -7,7 +7,6 @@ import { markRaw, ref } from 'vue';
|
|||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { miLocalStorage } from './local-storage.js';
|
import { miLocalStorage } from './local-storage.js';
|
||||||
import type { SoundType } from '@/scripts/sound.js';
|
import type { SoundType } from '@/scripts/sound.js';
|
||||||
import type { BuiltinTheme as ShikiBuiltinTheme } from 'shiki';
|
|
||||||
import { Storage } from '@/pizzax.js';
|
import { Storage } from '@/pizzax.js';
|
||||||
import { hemisphere } from '@/scripts/intl-const.js';
|
import { hemisphere } from '@/scripts/intl-const.js';
|
||||||
|
|
||||||
|
@ -5,11 +5,30 @@ import { type UserConfig, defineConfig } from 'vite';
|
|||||||
|
|
||||||
import locales from '../../locales/index.js';
|
import locales from '../../locales/index.js';
|
||||||
import meta from '../../package.json';
|
import meta from '../../package.json';
|
||||||
|
import packageInfo from './package.json' assert { type: 'json' };
|
||||||
import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js';
|
import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js';
|
||||||
import pluginJson5 from './vite.json5.js';
|
import pluginJson5 from './vite.json5.js';
|
||||||
|
|
||||||
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue'];
|
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Misskeyのフロントエンドにバンドルせず、CDNなどから別途読み込むリソースを記述する。
|
||||||
|
* CDNを使わずにバンドルしたい場合、以下の配列から該当要素を削除orコメントアウトすればOK
|
||||||
|
*/
|
||||||
|
const externalPackages = [
|
||||||
|
// shiki(コードブロックのシンタックスハイライトで使用中)はテーマ・言語の定義の容量が大きいため、それらはCDNから読み込む
|
||||||
|
{
|
||||||
|
name: 'shiki',
|
||||||
|
match: /^shiki\/(?<subPkg>(langs|themes))$/,
|
||||||
|
path(id: string, pattern: RegExp): string {
|
||||||
|
const match = pattern.exec(id)?.groups;
|
||||||
|
return match
|
||||||
|
? `https://esm.sh/shiki@${packageInfo.dependencies.shiki}/${match['subPkg']}`
|
||||||
|
: id;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const hash = (str: string, seed = 0): number => {
|
const hash = (str: string, seed = 0): number => {
|
||||||
let h1 = 0xdeadbeef ^ seed,
|
let h1 = 0xdeadbeef ^ seed,
|
||||||
h2 = 0x41c6ce57 ^ seed;
|
h2 = 0x41c6ce57 ^ seed;
|
||||||
@ -112,6 +131,7 @@ export function getConfig(): UserConfig {
|
|||||||
input: {
|
input: {
|
||||||
app: './src/_boot_.ts',
|
app: './src/_boot_.ts',
|
||||||
},
|
},
|
||||||
|
external: externalPackages.map(p => p.match),
|
||||||
output: {
|
output: {
|
||||||
manualChunks: {
|
manualChunks: {
|
||||||
vue: ['vue'],
|
vue: ['vue'],
|
||||||
@ -119,6 +139,15 @@ export function getConfig(): UserConfig {
|
|||||||
},
|
},
|
||||||
chunkFileNames: process.env.NODE_ENV === 'production' ? '[hash:8].js' : '[name]-[hash:8].js',
|
chunkFileNames: process.env.NODE_ENV === 'production' ? '[hash:8].js' : '[name]-[hash:8].js',
|
||||||
assetFileNames: process.env.NODE_ENV === 'production' ? '[hash:8][extname]' : '[name]-[hash:8][extname]',
|
assetFileNames: process.env.NODE_ENV === 'production' ? '[hash:8][extname]' : '[name]-[hash:8][extname]',
|
||||||
|
paths(id) {
|
||||||
|
for (const p of externalPackages) {
|
||||||
|
if (p.match.test(id)) {
|
||||||
|
return p.path(id, p.match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cssCodeSplit: true,
|
cssCodeSplit: true,
|
||||||
|
@ -806,8 +806,8 @@ importers:
|
|||||||
specifier: 1.71.1
|
specifier: 1.71.1
|
||||||
version: 1.71.1
|
version: 1.71.1
|
||||||
shiki:
|
shiki:
|
||||||
specifier: 1.1.7
|
specifier: 1.2.0
|
||||||
version: 1.1.7
|
version: 1.2.0
|
||||||
strict-event-emitter-types:
|
strict-event-emitter-types:
|
||||||
specifier: 2.0.0
|
specifier: 2.0.0
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
@ -5324,8 +5324,8 @@ packages:
|
|||||||
string-argv: 0.3.1
|
string-argv: 0.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@shikijs/core@1.1.7:
|
/@shikijs/core@1.2.0:
|
||||||
resolution: {integrity: sha512-gTYLUIuD1UbZp/11qozD3fWpUTuMqPSf3svDMMrL0UmlGU7D9dPw/V1FonwAorCUJBltaaESxq90jrSjQyGixg==}
|
resolution: {integrity: sha512-OlFvx+nyr5C8zpcMBnSGir0YPD6K11uYhouqhNmm1qLiis4GA7SsGtu07r9gKS9omks8RtQqHrJL4S+lqWK01A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@sideway/address@4.1.4:
|
/@sideway/address@4.1.4:
|
||||||
@ -6646,7 +6646,7 @@ packages:
|
|||||||
ts-dedent: 2.2.0
|
ts-dedent: 2.2.0
|
||||||
type-fest: 2.19.0
|
type-fest: 2.19.0
|
||||||
vue: 3.4.21(typescript@5.3.3)
|
vue: 3.4.21(typescript@5.3.3)
|
||||||
vue-component-type-helpers: 1.8.27
|
vue-component-type-helpers: 2.0.6
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -17658,10 +17658,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
/shiki@1.1.7:
|
/shiki@1.2.0:
|
||||||
resolution: {integrity: sha512-9kUTMjZtcPH3i7vHunA6EraTPpPOITYTdA5uMrvsJRexktqP0s7P3s9HVK80b4pP42FRVe03D7fT3NmJv2yYhw==}
|
resolution: {integrity: sha512-xLhiTMOIUXCv5DqJ4I70GgQCtdlzsTqFLZWcMHHG3TAieBUbvEGthdrlPDlX4mL/Wszx9C6rEcxU6kMlg4YlxA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/core': 1.1.7
|
'@shikijs/core': 1.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/side-channel@1.0.4:
|
/side-channel@1.0.4:
|
||||||
@ -19445,6 +19445,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
|
resolution: {integrity: sha512-6bnLkn8O0JJyiFSIF0EfCogzeqNXpnjJ0vW/SZzNHfe6sPx30lTtTXlE5TFs2qhJlAtDFybStVNpL73cPe3OMQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/vue-component-type-helpers@2.0.6:
|
||||||
|
resolution: {integrity: sha512-qdGXCtoBrwqk1BT6r2+1Wcvl583ZVkuSZ3or7Y1O2w5AvWtlvvxwjGhmz5DdPJS9xqRdDlgTJ/38ehWnEi0tFA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/vue-demi@0.14.7(vue@3.4.21):
|
/vue-demi@0.14.7(vue@3.4.21):
|
||||||
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
|
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
Loading…
Reference in New Issue
Block a user