From af8c80c95124bd784bbe93f9f82cd04e46ddd8f3 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Fri, 24 Jan 2025 22:26:09 +0800 Subject: [PATCH] perf(plugin-shiki): lazy load languages --- docs/plugins/markdown/shiki.md | 8 +-- docs/zh/plugins/markdown/shiki.md | 8 +-- plugins/markdown/plugin-shiki/package.json | 4 +- .../markdown/plugin-shiki/rollup.config.ts | 9 ++- .../markdown/plugin-shiki/src/node/index.ts | 1 - .../highlighter/createShikiHighlighter.ts | 65 +++++++++++++++---- .../highlighter/getHighLightFunction.ts | 10 +-- .../node/markdown/highlighter/getLanguage.ts | 6 +- .../plugin-shiki/src/node/resolveLang.ts | 23 +++++++ .../markdown/plugin-shiki/src/node/shiki.ts | 5 -- .../plugin-shiki/src/node/shikiPlugin.ts | 5 +- .../src/node/transformers/getTransformers.ts | 25 +++++-- .../tests/shiki-preWrapper.spec.ts | 7 +- pnpm-lock.yaml | 38 +++++++++++ 14 files changed, 164 insertions(+), 50 deletions(-) create mode 100644 plugins/markdown/plugin-shiki/src/node/resolveLang.ts delete mode 100644 plugins/markdown/plugin-shiki/src/node/shiki.ts diff --git a/docs/plugins/markdown/shiki.md b/docs/plugins/markdown/shiki.md index c4ac32bd11..0628c4ebf7 100644 --- a/docs/plugins/markdown/shiki.md +++ b/docs/plugins/markdown/shiki.md @@ -41,13 +41,11 @@ export default { - Details: - Languages of code blocks to be parsed by Shiki. + Additional languages to be parsed by Shiki. - This option will be forwarded to `createHighlighter()` method of Shiki. + ::: tip - ::: warning - - We recommend you to provide the languages list you are using explicitly, otherwise Shiki will load all languages and can affect performance. + The plugin now automatically loads the languages used in your markdown files, so you don't need to specify them manually. ::: diff --git a/docs/zh/plugins/markdown/shiki.md b/docs/zh/plugins/markdown/shiki.md index 413af3d65d..e7db0f8e58 100644 --- a/docs/zh/plugins/markdown/shiki.md +++ b/docs/zh/plugins/markdown/shiki.md @@ -41,13 +41,11 @@ export default { - 详情: - Shiki 要解析的代码块的语言。 + 被 Shiki 解析的额外语言。 - 该配置项会被传递到 Shiki 的 `createHighlighter()` 方法中。 + ::: tip - ::: warning - - 我们建议明确传入所有你使用的语言列表,否则 Shiki 会加载所有语言,并可能影响性能。 + 插件现在会自动加载你的 markdown 文件中使用的语言,所以你不需要手动指定它们。 ::: diff --git a/plugins/markdown/plugin-shiki/package.json b/plugins/markdown/plugin-shiki/package.json index 450edd4857..d2f9f2a80c 100644 --- a/plugins/markdown/plugin-shiki/package.json +++ b/plugins/markdown/plugin-shiki/package.json @@ -23,6 +23,7 @@ "type": "module", "exports": { ".": "./lib/node/index.js", + "./resolveLang": "./lib/node/resolveLang.js", "./styles/*": "./lib/client/styles/*", "./package.json": "./package.json" }, @@ -42,7 +43,8 @@ "@vuepress/helper": "workspace:*", "@vuepress/highlighter-helper": "workspace:*", "nanoid": "^5.0.9", - "shiki": "^2.1.0" + "shiki": "^2.1.0", + "synckit": "^0.9.2" }, "peerDependencies": { "vuepress": "2.0.0-rc.19" diff --git a/plugins/markdown/plugin-shiki/rollup.config.ts b/plugins/markdown/plugin-shiki/rollup.config.ts index cb16101b70..a85286f1c1 100644 --- a/plugins/markdown/plugin-shiki/rollup.config.ts +++ b/plugins/markdown/plugin-shiki/rollup.config.ts @@ -1,5 +1,8 @@ import { rollupBundle } from '../../../scripts/rollup.js' -export default rollupBundle('node/index', { - external: ['@shikijs/transformers', 'nanoid', 'shiki'], -}) +export default rollupBundle( + { base: 'node', files: ['index', 'resolveLang'] }, + { + external: ['@shikijs/transformers', 'nanoid', 'shiki', 'synckit'], + }, +) diff --git a/plugins/markdown/plugin-shiki/src/node/index.ts b/plugins/markdown/plugin-shiki/src/node/index.ts index 0183710c3d..a6bd7d475b 100644 --- a/plugins/markdown/plugin-shiki/src/node/index.ts +++ b/plugins/markdown/plugin-shiki/src/node/index.ts @@ -1,4 +1,3 @@ export type * from './options.js' -export * from './shiki.js' export * from './shikiPlugin.js' export type * from './types.js' diff --git a/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/createShikiHighlighter.ts b/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/createShikiHighlighter.ts index 5b631b591f..09fbaf4d28 100644 --- a/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/createShikiHighlighter.ts +++ b/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/createShikiHighlighter.ts @@ -1,19 +1,35 @@ -import type { BundledLanguage, BundledTheme, HighlighterGeneric } from 'shiki' -import { createHighlighter } from 'shiki' -import { bundledLanguageNames } from '../../shiki.js' +import { createRequire } from 'node:module' +import type { + BundledLanguage, + BundledTheme, + HighlighterGeneric, + LanguageRegistration, +} from 'shiki' +import { createHighlighter, isSpecialLang } from 'shiki' +import { createSyncFn } from 'synckit' +import type { ShikiResolveLang } from '../../resolveLang.js' import type { ShikiHighlightOptions } from '../../types.js' +const require = createRequire(import.meta.url) + +const resolveLangSync = createSyncFn( + require.resolve('@vuepress/plugin-shiki/resolveLang'), +) + +export type ShikiLoadLang = (lang: LanguageRegistration | string) => boolean + export const createShikiHighlighter = async ({ - langs = bundledLanguageNames, + langs = [], langAlias = {}, defaultLang, shikiSetup, ...options -}: ShikiHighlightOptions = {}): Promise< - HighlighterGeneric -> => { - const shikiHighlighter = await createHighlighter({ - langs, +}: ShikiHighlightOptions = {}): Promise<{ + highlighter: HighlighterGeneric + loadLang: (lang: LanguageRegistration | string) => boolean +}> => { + const highlighter = await createHighlighter({ + langs: [...langs, ...Object.values(langAlias)], langAlias, themes: 'themes' in options @@ -21,7 +37,34 @@ export const createShikiHighlighter = async ({ : [options.theme ?? 'nord'], }) - await shikiSetup?.(shikiHighlighter) + const loadLang = (langConfig: LanguageRegistration | string): boolean => { + const lang = typeof langConfig === 'string' ? langConfig : langConfig.name + + if ( + !isSpecialLang(lang) && + !highlighter.getLoadedLanguages().includes(lang) + ) { + const resolvedLang = resolveLangSync(lang) + + if (!resolvedLang.length) return false + + console.log('loading lang', lang) + + highlighter.loadLanguageSync(resolvedLang) + } + return true + } + + // patch for twoslash - https://github.com/vuejs/vitepress/issues/4334 + const rawGetLanguage = highlighter.getLanguage + + highlighter.getLanguage = (name) => { + loadLang(name) + + return rawGetLanguage.call(highlighter, name) + } + + await shikiSetup?.(highlighter) - return shikiHighlighter + return { highlighter, loadLang } } diff --git a/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/getHighLightFunction.ts b/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/getHighLightFunction.ts index ff73439602..54efec5aac 100644 --- a/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/getHighLightFunction.ts +++ b/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/getHighLightFunction.ts @@ -7,6 +7,7 @@ import { import type { ShikiHighlightOptions } from '../../types.js' import { attrsToLines } from '../../utils.js' import type { MarkdownFilePathGetter } from './createMarkdownFilePathGetter.js' +import type { ShikiLoadLang } from './createShikiHighlighter.js' import { getLanguage } from './getLanguage.js' import { handleMustache } from './handleMustache.js' @@ -19,20 +20,15 @@ type MarkdownItHighlight = ( export const getHighLightFunction = ( highlighter: HighlighterGeneric, options: ShikiHighlightOptions, + loadLang: ShikiLoadLang, markdownFilePathGetter: MarkdownFilePathGetter, ): MarkdownItHighlight => { const transformers = getTransformers(options) - const loadedLanguages = highlighter.getLoadedLanguages() return (content, language, attrs) => handleMustache(content, (str) => highlighter.codeToHtml(str, { - lang: getLanguage( - language, - loadedLanguages, - options, - markdownFilePathGetter, - ), + lang: getLanguage(language, options, loadLang, markdownFilePathGetter), meta: { /** * Custom `transformers` passed by users may require `attrs`. diff --git a/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/getLanguage.ts b/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/getLanguage.ts index 36856e1f41..35ac380b68 100644 --- a/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/getLanguage.ts +++ b/plugins/markdown/plugin-shiki/src/node/markdown/highlighter/getLanguage.ts @@ -1,20 +1,20 @@ -import { isSpecialLang } from 'shiki' import { colors } from 'vuepress/utils' import type { ShikiHighlightOptions } from '../../types.js' import { logger, resolveLanguage } from '../../utils.js' import type { MarkdownFilePathGetter } from './createMarkdownFilePathGetter.js' +import type { ShikiLoadLang } from './createShikiHighlighter.js' const WARNED_LANGS = new Set() export const getLanguage = ( lang: string, - loadedLanguages: string[], { defaultLang, logLevel }: ShikiHighlightOptions, + loadLang: ShikiLoadLang, markdownFilePathGetter: MarkdownFilePathGetter, ): string => { let result = resolveLanguage(lang) - if (result && !loadedLanguages.includes(result) && !isSpecialLang(result)) { + if (result && !loadLang(lang)) { // warn for unknown languages only once if (logLevel !== 'silent' && !WARNED_LANGS.has(result)) { logger.warn( diff --git a/plugins/markdown/plugin-shiki/src/node/resolveLang.ts b/plugins/markdown/plugin-shiki/src/node/resolveLang.ts new file mode 100644 index 0000000000..86c140a3d2 --- /dev/null +++ b/plugins/markdown/plugin-shiki/src/node/resolveLang.ts @@ -0,0 +1,23 @@ +import type { + DynamicImportLanguageRegistration, + LanguageRegistration, +} from 'shiki' +import { bundledLanguages } from 'shiki' +import { runAsWorker } from 'synckit' + +async function resolveLang(lang: string): Promise { + return ( + ( + bundledLanguages as Record< + string, + DynamicImportLanguageRegistration | undefined + > + ) + [lang]?.() + .then((m) => m.default) ?? [] + ) +} + +runAsWorker(resolveLang) + +export type ShikiResolveLang = typeof resolveLang diff --git a/plugins/markdown/plugin-shiki/src/node/shiki.ts b/plugins/markdown/plugin-shiki/src/node/shiki.ts deleted file mode 100644 index c6ab41daa3..0000000000 --- a/plugins/markdown/plugin-shiki/src/node/shiki.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { bundledLanguages } from 'shiki' - -export { bundledLanguages } from 'shiki' - -export const bundledLanguageNames = Object.keys(bundledLanguages) diff --git a/plugins/markdown/plugin-shiki/src/node/shikiPlugin.ts b/plugins/markdown/plugin-shiki/src/node/shikiPlugin.ts index 6173fbc088..dc81243466 100644 --- a/plugins/markdown/plugin-shiki/src/node/shikiPlugin.ts +++ b/plugins/markdown/plugin-shiki/src/node/shikiPlugin.ts @@ -41,11 +41,12 @@ export const shikiPlugin = (_options: ShikiPluginOptions = {}): Plugin => { const { preWrapper, lineNumbers, collapsedLines } = options const markdownFilePathGetter = createMarkdownFilePathGetter(md) - const shikiHighlighter = await createShikiHighlighter(options) + const { highlighter, loadLang } = await createShikiHighlighter(options) md.options.highlight = getHighLightFunction( - shikiHighlighter, + highlighter, options, + loadLang, markdownFilePathGetter, ) diff --git a/plugins/markdown/plugin-shiki/src/node/transformers/getTransformers.ts b/plugins/markdown/plugin-shiki/src/node/transformers/getTransformers.ts index cecc2c675f..51c62f5647 100644 --- a/plugins/markdown/plugin-shiki/src/node/transformers/getTransformers.ts +++ b/plugins/markdown/plugin-shiki/src/node/transformers/getTransformers.ts @@ -24,7 +24,11 @@ export const getTransformers = ( const transformers: ShikiTransformer[] = [] if (options.notationDiff) { - transformers.push(transformerNotationDiff()) + transformers.push( + transformerNotationDiff({ + matchAlgorithm: 'v3', + }), + ) } if (options.notationFocus) { @@ -32,20 +36,33 @@ export const getTransformers = ( transformerNotationFocus({ classActiveLine: 'has-focus', classActivePre: 'has-focused-lines', + matchAlgorithm: 'v3', }), ) } if (options.notationHighlight) { - transformers.push(transformerNotationHighlight()) + transformers.push( + transformerNotationHighlight({ + matchAlgorithm: 'v3', + }), + ) } if (options.notationErrorLevel) { - transformers.push(transformerNotationErrorLevel()) + transformers.push( + transformerNotationErrorLevel({ + matchAlgorithm: 'v3', + }), + ) } if (options.notationWordHighlight) { - transformers.push(transformerNotationWordHighlight()) + transformers.push( + transformerNotationWordHighlight({ + matchAlgorithm: 'v3', + }), + ) transformers.push(transformerMetaWordHighlight()) } diff --git a/plugins/markdown/plugin-shiki/tests/shiki-preWrapper.spec.ts b/plugins/markdown/plugin-shiki/tests/shiki-preWrapper.spec.ts index 19c1fa367e..5f239298a5 100644 --- a/plugins/markdown/plugin-shiki/tests/shiki-preWrapper.spec.ts +++ b/plugins/markdown/plugin-shiki/tests/shiki-preWrapper.spec.ts @@ -18,7 +18,7 @@ import { } from '../src/node/markdown/index.js' import type { ShikiPluginOptions } from '../src/node/options.js' -const shikiHighlighter = await createShikiHighlighter() +const { highlighter, loadLang } = await createShikiHighlighter() const createMarkdown = ({ preWrapper = true, @@ -26,13 +26,14 @@ const createMarkdown = ({ collapsedLines = false, ...options }: ShikiPluginOptions = {}): MarkdownIt => { - const md = MarkdownIt() + const md = new MarkdownIt() const markdownFilePathGetter = createMarkdownFilePathGetter(md) md.options.highlight = getHighLightFunction( - shikiHighlighter, + highlighter, options, + loadLang, markdownFilePathGetter, ) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83aaf15d4f..91a4c0cfb2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -942,6 +942,9 @@ importers: shiki: specifier: ^2.1.0 version: 2.1.0 + synckit: + specifier: ^0.9.2 + version: 0.9.2 vuepress: specifier: 2.0.0-rc.19 version: 2.0.0-rc.19(@vuepress/bundler-vite@2.0.0-rc.19(@types/node@22.10.10)(jiti@2.4.2)(lightningcss@1.29.1)(sass-embedded@1.83.4)(sass@1.83.4)(terser@5.37.0)(tsx@4.19.2)(typescript@5.7.3)(yaml@2.7.0))(@vuepress/bundler-webpack@2.0.0-rc.19(esbuild@0.24.2)(typescript@5.7.3))(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) @@ -2794,36 +2797,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.0': resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.0': resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.0': resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.0': resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.0': resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.0': resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} @@ -2851,6 +2860,10 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@playwright/test@1.50.0': resolution: {integrity: sha512-ZGNXbt+d65EGjBORQHuYKj+XhCewlwpnSd/EDuLPZGSiEWmgOJB5RmMCCYGy5aMfTs9wx61RivfDKi8H/hcMvw==} engines: {node: '>=18'} @@ -2957,51 +2970,61 @@ packages: resolution: {integrity: sha512-3pA7xecItbgOs1A5H58dDvOUEboG5UfpTq3WzAdF54acBbUM+olDJAPkgj1GRJ4ZqE12DZ9/hNS2QZk166v92A==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.32.0': resolution: {integrity: sha512-Y7XUZEVISGyge51QbYyYAEHwpGgmRrAxQXO3siyYo2kmaj72USSG8LtlQQgAtlGfxYiOwu+2BdbPjzEpcOpRmQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.32.0': resolution: {integrity: sha512-r7/OTF5MqeBrZo5omPXcTnjvv1GsrdH8a8RerARvDFiDwFpDVDnJyByYM/nX+mvks8XXsgPUxkwe/ltaX2VH7w==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.32.0': resolution: {integrity: sha512-HJbifC9vex9NqnlodV2BHVFNuzKL5OnsV2dvTw6e1dpZKkNjPG6WUq+nhEYV6Hv2Bv++BXkwcyoGlXnPrjAKXw==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.32.0': resolution: {integrity: sha512-VAEzZTD63YglFlWwRj3taofmkV1V3xhebDXffon7msNz4b14xKsz7utO6F8F4cqt8K/ktTl9rm88yryvDpsfOw==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.32.0': resolution: {integrity: sha512-Sts5DST1jXAc9YH/iik1C9QRsLcCoOScf3dfbY5i4kH9RJpKxiTBXqm7qU5O6zTXBTEZry69bGszr3SMgYmMcQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.32.0': resolution: {integrity: sha512-qhlXeV9AqxIyY9/R1h1hBD6eMvQCO34ZmdYvry/K+/MBs6d1nRFLm6BOiITLVI+nFAAB9kUB6sdJRKyVHXnqZw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.32.0': resolution: {integrity: sha512-8ZGN7ExnV0qjXa155Rsfi6H8M4iBBwNLBM9lcVS+4NcSzOFaNqmt7djlox8pN1lWrRPMRRQ8NeDlozIGx3Omsw==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.32.0': resolution: {integrity: sha512-VDzNHtLLI5s7xd/VubyS10mq6TxvZBp+4NRWoW+Hi3tgV05RtVm4qK99+dClwTN1McA6PHwob6DEJ6PlXbY83A==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.32.0': resolution: {integrity: sha512-qcb9qYDlkxz9DxJo7SDhWxTWV1gFuwznjbTiov289pASxlfGbaOD54mgbs9+z94VwrXtKTu+2RqwlSTbiOqxGg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.32.0': resolution: {integrity: sha512-pFDdotFDMXW2AXVbfdUEfidPAk/OtwE/Hd4eYMTNVVaCQ6Yl8et0meDaKNL63L44Haxv4UExpv9ydSf3aSayDg==} @@ -5758,24 +5781,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.29.1: resolution: {integrity: sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.29.1: resolution: {integrity: sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.29.1: resolution: {integrity: sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.29.1: resolution: {integrity: sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog==} @@ -7728,6 +7755,10 @@ packages: resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} engines: {node: '>=16.0.0'} + synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + engines: {node: ^14.18.0 || >=16.0.0} + table@6.9.0: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} @@ -10372,6 +10403,8 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@pkgr/core@0.1.1': {} + '@playwright/test@1.50.0': dependencies: playwright: 1.50.0 @@ -15808,6 +15841,11 @@ snapshots: sync-message-port@1.1.3: {} + synckit@0.9.2: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.8.1 + table@6.9.0: dependencies: ajv: 8.17.1