diff --git a/content/7.blog/21.shiki-v1.md b/content/7.blog/21.shiki-v1.md index 63237288c..2b543722e 100644 --- a/content/7.blog/21.shiki-v1.md +++ b/content/7.blog/21.shiki-v1.md @@ -1,9 +1,9 @@ --- -title: The Evolution of Shiki v1.0 -description: Shiki v1.0 came with many improvements and features - see how Nuxt drives the evolution of Shiki! +title: Эволюция Shiki v1.0 +description: В Shiki v1.0 появилось множество улучшений и возможностей - посмотрите, как Nuxt способствует развитию Shiki! image: /assets/blog/shiki-cover.png authors: - - name: Anthony Fu + - name: Энтони Фу avatarUrl: https://github.com/antfu.png link: https://github.com/antfu twitter: antfu7 @@ -11,12 +11,12 @@ date: 2024-03-11T00:00:00.000Z category: Статья --- -[Shiki](https://github.com/shikijs/shiki) is a syntax highlighter that uses [TextMate grammars and themes](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide#textmate-grammars), the same engine that powers VS Code. It provides one of the most accurate and beautiful syntax highlighting for your code snippets. It was created by [Pine Wu](https://github.com/octref) back in 2018, when he was part of the VS Code team. It started as an experiment to use [Oniguruma](https://github.com/microsoft/vscode-oniguruma) to do syntax highlighting. +[Shiki](https://github.com/shikijs/shiki) — это инструмент для подсветки синтаксиса, который использует [грамматики и темы TextMate](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide#textmate-grammars), тот же движок, который поддерживает VS Code. Он обеспечивает одну из самых точных и красивых подсветок синтаксиса для сниппетов кода. Shiki был создан [Пайн Ву](https://github.com/octref) еще в 2018 году, когда он был частью команды VS Code. Он начинался как эксперимент по использованию [Oniguruma](https://github.com/microsoft/vscode-oniguruma) для подсветки синтаксиса. -Different from existing syntax highlighters like [Prism](https://prismjs.com/) and [Highlight.js](https://highlightjs.org/) that designed to run in the browser, Shiki took a different approach by **highlighting ahead of time**. It ships the highlighted HTML to the client, producing accurate and beautiful syntax highlighting with **zero JavaScript**. It soon took off and became a very popular choice, especially for static site generators and documentation sites. +В отличие от существующих подсветчиков синтаксиса, таких как [Prism](https://prismjs.com/) и [Highlight.js](https://highlightjs.org/), которые были разработаны для работы в браузере, Shiki применил другой подход, **подсвечивая заранее**. Он отправляет подсвеченный HTML клиенту, создавая точную и красивую подсветку синтаксиса с **нулем JavaScript**. Вскоре Shiki получил широкое распространение и стал очень популярным выбором, особенно для генераторов статических сайтов и сайтов документации. -::collapsible{name="Shiki Example"} -For example, with the code snippet below: +::collapsible{name="Пример Shiki"} +Например, с помощью фрагмента кода ниже: ```ts export default defineNuxtConfig({ @@ -26,7 +26,7 @@ export default defineNuxtConfig({ }) ``` -Shiki will generate the following HTML: +Shiki сгенерирует следующий HTML-код: ```html
@@ -40,64 +40,64 @@ Shiki will generate the following HTML:``` -It might look a bit overwhelming if you read it, but **this piece of HTML works everywhere without any JavaScript or CSS**. TextMate grammars has a very rich representation of the types of every token (TextMate scopes). Since Shiki flattens all the tokens into styled spans, it achieves accurate results that most traditional CSS-based highlighters have difficulties achieving. +Может показаться немного ошеломляющим, если вы это прочтете, но **этот фрагмент HTML работает везде без JavaScript или CSS**. Грамматики TextMate имеют очень богатое представление типов каждого токена (области действия TextMate). Поскольку Shiki сглаживает все токены в стилизованные span, он достигает точных результатов, которые с трудом достигаются большинством традиционных хайлайтеров на основе CSS. :: -While Shiki is awesome, it's still a library that is designed to run on Node.js. This means it is limited to highlighting static code only and would have trouble with dynamic code, because Shiki doesn't work in the browser. In addition, Shiki relies on the WASM binary of Oniguruma, as well as a bunch of heavy grammar and theme files in JSON. It uses Node.js filesystem and path resolution to load these files, which is not accessible in the browser. +Хотя Shiki великолепен, это все еще библиотека, разработанная для работы на Node.js. Это означает, что она ограничена подсветкой только статического кода и будет иметь проблемы с динамическим кодом, поскольку Shiki не работает в браузере. Кроме того, Shiki полагается на двоичный файл WASM Oniguruma, а также на кучу тяжелых файлов грамматики и тем в JSON. Он использует файловую систему Node.js и разрешение путей для загрузки этих файлов, которые недоступны в браузере. -To improve that situation, I [started this RFC](https://github.com/shikijs/shiki/issues/91) that later landed with [this PR](https://github.com/shikijs/shiki/pull/109) and shipped in Shiki v0.9. While it abstracted the file loading layer to use fetch or filesystem based on the environment, it's still quite complicated to use as you need to serve the grammars and theme files somewhere in your bundle or CDN manually, then call the `setCDN` method to tell Shiki where to load these files. +Чтобы улучшить эту ситуацию, я [начал этот RFC](https://github.com/shikijs/shiki/issues/91), который позже оказался в [этом PR](https://github.com/shikijs/shiki/pull/109) и был отправлен в Shiki v0.9. Хотя он абстрагировал уровень загрузки файлов для использования fetch или файловой системы в зависимости от среды, его все еще довольно сложно использовать, поскольку вам нужно вручную обслуживать грамматики и файлы тем где-то в вашем пакете или CDN, а затем вызывать метод `setCDN`, чтобы сообщить Shiki, куда загружать эти файлы. -The solution is not perfect but at least it made it possible to run Shiki in the browser to highlight dynamic content. We have been using that approach since then - until the story of this article began. +Решение не идеальное, но, по крайней мере, оно позволило запустить Shiki в браузере для подсветки динамического контента. С тех пор мы использовали этот подход - до тех пор, пока не началась история этой статьи. -## The Start +## Начало -Nuxt is putting a lot effort in pushing the [web to the edge](/blog/nuxt-on-the-edge), making the web more accessible with lower latency and better performance. Like CDN servers, edge hosting services such as [CloudFlare Workers](https://workers.cloudflare.com/) are deployed all over the world. Users get the content from the nearest edge server without the round trips to the origin server which could be thousands of miles away. With the awesome benefits it provides, it also comes with some trade-offs. For example, edge servers use a restricted runtime environment. CloudFlare Workers also does not support file system access and usually don't preserve the state between requests. While Shiki's main overhead is loading the grammars and themes upfront, that wouldn't work well in the edge environment. +Nuxt прилагает много усилий для продвижения [веба на распределенные серверы](/blog/nuxt-on-the-edge), делая веб более доступным с меньшей задержкой и лучшей производительностью. Как и серверы CDN, службы граничного хостинга, такие как [CloudFlare Workers](https://workers.cloudflare.com/), развернуты по всему миру. Пользователи получают контент с ближайшего сервера без необходимости совершать путешествие на исходный сервер, который может находиться за тысячи миль. Наряду с потрясающими преимуществами, которые они предоставляют, они также идут на некоторые компромиссы. Например, переферийные серверы используют ограниченное runtime-окружение. CloudFlare Workers также не поддерживает доступ к файловой системе и обычно не сохраняет состояние между запросами. Хотя основные накладные расходы Shiki заключаются в предварительной загрузке грамматик и тем, это не будет хорошо работать в переферийной среде. -It all started with a chat between [Sébastien](https://twitter.com/Atinux) and me. We were trying to make [Nuxt Content](https://github.com/nuxt/content) which uses Shiki to highlight the code blocks, to work on the edge. +Все началось с чата между [Себастьеном](https://twitter.com/Atinux) и мной. Мы пытались сделать [Nuxt Content](https://github.com/nuxt/content), который использует Shiki для подсветки блоков кода, для работы на переферии. -![Chat History Between Sébastien and Anthony](/assets/blog/shiki-start-chat.png){.rounded-lg.shadow.max-w-[700px].border.dark:border-gray-700} +![История чата между Себастьеном и Энтони](/assets/blog/shiki-start-chat.png){.rounded-lg.shadow.max-w-[700px].border.dark:border-gray-700} -I started the experiments by patching [`shiki-es`](https://github.com/pi0/shiki-es) (a ESM build of Shiki by [Pooya Parsa](https://github.com/pi0)) locally, to convert the grammars and themes files into [ECMAScript Module (ESM)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) so that it could be understood and bundled by the build tools. This was done to create the code bundle for CloudFlare Workers to consume without using the filesystem nor making network requests. +Я начал эксперименты с локального исправления [`shiki-es`](https://github.com/pi0/shiki-es) (сборка Shiki ESM от [Пуйя Парса](https://github.com/pi0)) для преобразования файлов грамматик и тем в [модуль ECMAScript (ESM)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) так, чтобы его можно было понять и объединить инструментами сборки. Это было сделано для создания пакета кода для CloudFlare Workers, который можно было бы использовать без использования файловой системы или выполнения сетевых запросов. -```ts [Before - Read JSON assets from filesystem] +```ts [До — чтение JSON-ресурсов из файловой системы] import fs from 'fs/promises' const cssGrammar = JSON.parse(await fs.readFile('../langs/css.json', 'utf-8')) ``` -```ts [After - Using ESM import] +```ts [После - Использование импорта ESM] const cssGrammar = await import('../langs/css.mjs').then(m => m.default) ``` -We need to wrap the JSON files into ESM as inline literal so that we can use [`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) to dynamically import them. The difference is that `import()` is a standard JavaScript feature that works everywhere, while `fs.readFile` is a Node.js specific API that only works in Node.js. Having `import()` statically would also make bundlers like [Rollup](https://rollupjs.org/) and [webpack](https://webpack.js.org/) able to construct the module relationship graph and [emit the bundled code as chunks](https://rollupjs.org/tutorial/#code-splitting). +Нам было нужно обернуть JSON-файлы в ESM в виде встроенного литерала, чтобы мы могли использовать [`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) для их динамического импорта. Разница в том, что `import()` — это стандартная функция JavaScript, которая работает везде, в то время как `fs.readFile` — это API, специфичный для Node.js, который работает только в Node.js. Наличие `import()` статически также позволило бы сборщикам, таким как [Rollup](https://rollupjs.org/) и [webpack](https://webpack.js.org/), создавать граф взаимосвязей модулей и [выдавать связанный код в виде чанков](https://rollupjs.org/tutorial/#code-splitting). -Then, I realized that it actually takes more than that to make it work on edge runtimes. Since bundlers expect imports to be resolvable at build time (meaning that in order to support all the languages and themes), we need to list all the import statements in every single grammar and theme file in the codebase. This would end up with a huge bundle size with a bunch of grammars and themes that you might not actually use. This problem is particularly important in the edge environment, where the bundle size is critical for performance. +Затем я понял, что на самом деле требуется больше, чтобы заставить его работать в рантайме распределенных серверов. Поскольку сборщики ожидают, что импорты будут разрешимы во время сборки (то есть для поддержки всех языков и тем), нам нужно перечислить все операторы импорта в каждом файле грамматики и темы в кодовой базе. Это приведет к огромному размеру пакета с кучей грамматик и тем, которые вы, возможно, на самом деле не используете. Эта проблема особенно важна в среде периферийных серверов, где размер пакета имеет решающее значение для производительности. -So, we needed to figure out a better middle ground to make it work better. +Поэтому нам нужно было найти золотую середину, чтобы все работало лучше. -## The Fork - Shikiji +## Форк - Shikiji -Knowing this might fundamentally change the way Shiki works, and since we don't want to risk breaking the existing Shiki users with our experiments, I started a fork of Shiki called [Shikiji](https://github.com/antfu/shikiji). I rewrote the code from scratch while keeping the previous API design decisions in mind. The goal is to make Shiki runtime-agnostic, performant and efficient, like the philosophy we have at [UnJS](https://github.com/unjs). +Зная, что это может кардинально изменить способ работы Shiki, и поскольку мы не хотим рисковать сломать проекты существующих пользователей Shiki нашими экспериментами, я начал форк Shiki под названием [Shikiji](https://github.com/antfu/shikiji). Я переписал код с нуля, сохранив предыдущие решения по дизайну API. Цель состоит в том, чтобы сделать Shiki независимым от рантайма, производительным и эффективным, согласно философии, которой мы придерживаемся в [UnJS](https://github.com/unjs). -To make that happen, we need to make Shikiji completely ESM-friendly, pure and [tree-shakable](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking). This goes all the way up to the dependencies of Shiki such as [`vscode-oniguruma`](https://github.com/microsoft/vscode-oniguruma) and [`vscode-textmate`](https://github.com/microsoft/vscode-textmate), which are provided in [Common JS (CJS)](https://requirejs.org/docs/commonjs.html) format. `vscode-oniguruma` also contains a WASM binding generated by [`emscripten`](https://github.com/emscripten-core/emscripten) that contains [dangling promises](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md) that will make CloudFlare Workers fail to finish the request. We ended up by embedding the WASM binary into a [base64 string](https://en.wikipedia.org/wiki/Base64) and shipping it as an ES module, manually rewriting the WASM binding to avoid dangling promises, and [vendored `vscode-textmate`](https://github.com/shikijs/shiki/blob/main/CONTRIBUTING.md#clone) to compile from its source code and produce the efficient ESM output. +Чтобы это произошло, нам нужно сделать Shikiji полностью дружественным к ESM, чистым и [tree-shakable](https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking). Это касается и зависимостей Shiki, таких как [`vscode-oniguruma`](https://github.com/microsoft/vscode-oniguruma) и [`vscode-textmate`](https://github.com/microsoft/vscode-textmate), которые предоставляются в формате [Common JS (CJS)](https://requirejs.org/docs/commonjs.html). `vscode-oniguruma` также содержит привязку WASM, сгенерированную [`emscripten`](https://github.com/emscripten-core/emscripten), которая содержит [неиспользуемые промисы](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md), из-за которых CloudFlare Workers не смогут завершить запрос. В итоге мы встроили двоичный файл WASM в [строку base64](https://en.wikipedia.org/wiki/Base64) и поставляли его как модуль ES, вручную переписав привязку WASM, чтобы избежать неиспользуемых промисов, и [предоставляли его `vscode-textmate`](https://github.com/shikijs/shiki/blob/main/CONTRIBUTING.md#clone) для компиляции из исходного кода и создания эффективного вывода ESM. -The end result was very promising. We managed to get Shikiji working on any runtime environment, with even the possibility to [import it from CDN and run in the browser](https://shiki.style/guide/install#cdn-usage) with a single line of code. +Конечный результат оказался многообещающим. Нам удалось заставить Shikiji работать в любой среде выполнения, даже с возможностью [импортировать его из CDN и запустить в браузере](https://shiki.style/guide/install#cdn-usage) с помощью одной строки кода. -We also took the chance to improve the API and the internal architecture of Shiki. We switched from simple string concatenation to use [`hast`](https://github.com/syntax-tree/hast), creating an Abstract Syntax Tree (AST) for generating the HTML output. This opens up the possibility of exposing a [Transformers API](https://shiki.style/guide/transformers) to allow users to modify the intermediate HAST and do many cool integrations that would be very hard to achieve previously. +Мы также воспользовались шансом улучшить API и внутреннюю архитектуру Shiki. Мы перешли от простой конкатенации строк к использованию [`hast`](https://github.com/syntax-tree/hast), создав абстрактное синтаксическое дерево (AST) для генерации выходных данных HTML. Это открывает возможность раскрытия [Transformers API](https://shiki.style/guide/transformers), чтобы позволить пользователям изменять промежуточный HAST и выполнять множество интересных интеграций, которые ранее было бы очень трудно реализовать. -Dark/Light mode support [was a frequently requested feature](https://github.com/shikijs/shiki/issues/33). Because of the static approach Shiki takes, it won't be possible to change the theme on the fly at rendering. The solution in the past was to generate the hightlighted HTML twice, and toggle their visibility based on the user's preference - it wasn't efficient as it duplicate the payload, or used [CSS variables theme](https://github.com/shikijs/shiki/pull/212) which lost the granular highlighting Shiki is great for. With the new architecture that Shikiji has, I took a step back and rethought the problem, and [came up with the idea](https://github.com/shikijs/shiki/issues/33#issuecomment-1676362336) of breaking down the common tokens and merge multiple themes as inlined CSS variables, which provide efficient output while aligning with the Shiki's philosophy. You can learn more about it in [Shiki's documentation](https://shiki.style/guide/dual-themes). +Поддержка темного/светлого режима [была часто запрашиваемой функцией](https://github.com/shikijs/shiki/issues/33). Из-за статического подхода, который использует Shiki, невозможно было менять тему на лету при рендеринге. Решение в прошлом состояло в том, чтобы дважды генерировать HTML с подсветкой и переключать его видимость на основе предпочтений пользователя — это было неэффективно, так как дублировало payload или использовало [CSS переменные темы](https://github.com/shikijs/shiki/pull/212), что теряло гранулярную подсветку, для которой Shiki отлично подходит. С новой архитектурой Shikiji я сделал шаг назад, переосмыслил проблему и [придумал идею](https://github.com/shikijs/shiki/issues/33#issuecomment-1676362336) разбить общие токены и объединить несколько тем как встроенные переменные CSS, которые обеспечивают эффективный вывод, при этом согласуясь с философией Shiki. Вы можете узнать больше об этом в [документации Shiki](https://shiki.style/guide/dual-themes). -To make the migration easier, we also created the [`shikiji-compat` compatibility layer](https://shikiji.netlify.app/guide/compat), which uses Shikiji's new foundation and provides backward compatibility API. +Чтобы упростить миграцию, мы также создали [слой совместимости `shikiji-compat`](https://shikiji.netlify.app/guide/compat), который использует новую основу Shikiji и предоставляет API для обратной совместимости. -To get Shikiji to work on Cloudflare Workers, we had one last challenge as they don't support [initiating WASM instance](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiate_static)s from inlined binary data. Instead it requires importing the static `.wasm` assets for security reasons. This means that our "All-in-ESM" approach does not work well on CloudFlare. This would require extra work for users to provide different WASM sources, which makes the experience more difficult than we intended. At this moment, [Pooya Parsa](https://github.com/pi0) stepped in and made the universal layer [`unjs/unwasm`](https://github.com/unjs/unwasm), which supports the upcoming [WebAssembly/ES Module Integration](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration) proposal. It has been integrated into [Nitro to have automated WASM targets](https://github.com/unjs/nitro/pull/2037). We hope that `unwasm` will help developers to have a better experience when working with WASM. +Чтобы заставить Shikiji работать на Cloudflare Workers, у нас оставалась последняя проблема, поскольку они не поддерживают [инициализацию экземпляра WASM](https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/instantiate_static) из встроенных двоичных данных. Вместо этого по соображениям безопасности требуется импортировать статические ассеты `.wasm`. Это означает, что наш подход "Все-в-ESM" не работает хорошо на CloudFlare. Это потребовало бы от пользователей дополнительной работы по предоставлению различных источников WASM, что делает процесс более сложным, чем мы предполагали. В этот момент [Пуйя Парса](https://github.com/pi0) вмешался и создал универсальный слой [`unjs/unwasm`](https://github.com/unjs/unwasm), который поддерживает предстоящий пропозал [WebAssembly/ES Module Integration](https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration). Он был интегрирован в [Nitro для автоматизации целей WASM](https://github.com/unjs/nitro/pull/2037). Мы надеемся, что `unwasm` поможет разработчикам улучшить опыт работы с WASM. -Overall, the Shikiji rewrite works well. [Nuxt Content](https://github.com/nuxt/content), [VitePress](https://vitepress.dev/) and [Astro](https://astro.build/) have been migrated to it. The feedback we have received has also been very positive. +В целом, переписанный Shikiji работает хорошо. [Nuxt Content](https://github.com/nuxt/content), [VitePress](https://vitepress.dev/) и [Astro](https://astro.build/) были перенесены на него. Отзывы, которые мы получили, также были очень положительными. -## Merging Back +## Обратное слияние -I am a team member of Shiki and have helped to do releases from time to time. While [Pine](https://github.com/octref) is the lead of Shiki, he was busy on other stuff and Shiki's iterations slowed down. During the experiments in Shikiji, I [proposed a few improvements](https://github.com/shikijs/shiki/issues/510) that could help Shiki acquire a modern structure. While generally everyone agreed with that direction, there would have been quite a lot of work to do and no one started to work on that. +Я являюсь членом команды Shiki и время от времени помогал делать релизы. Пока [Пайн](https://github.com/octref) был лидером Shiki, он был занят другими делами, и итерации Shiki замедлились. Во время экспериментов в Shikiji я [предложил несколько улучшений](https://github.com/shikijs/shiki/issues/510), которые могли бы помочь Shiki обрести современную структуру. Хотя в целом все согласились с этим направлением, работы было бы довольно много, и никто не начал над этим работать. -While we were happy to use Shikiji to solve the problems we had, we certainly didn't want to see the community split by two different versions of Shiki. After a call with Pine, we made the consensus to merge the two projects into one: +Хотя мы были рады использовать Shikiji для решения наших проблем, мы определенно не хотели видеть сообщество разделенным на две разные версии Shiki. После созвона с Пайн мы пришли к консенсусу объединить два проекта в один: ::read-more --- @@ -108,27 +108,27 @@ to: https://github.com/shikijs/shiki/pull/557 feat!: merge Shikiji back into Shiki for v1.0 [\#557]{.opacity-50} :: -We are really happy to see that our work in Shikiji has been merged back to Shiki, that not only works for ourselves, but also benefits the entire community. With this merge, it **solves around 95% of the open issues** we have had in Shiki for years: +Мы очень рады видеть, что наша работа в Shikiji была влита обратно в Shiki, что не только работает для нас самих, но и приносит пользу всему сообществу. Благодаря этому слиянию, **решается около 95% открытых issues**, которые у нас были в Shiki в течение многих лет: -![Shikiji Merged Back to Shiki](/assets/blog/shiki-merge-pr.png){.rounded-lg.shadow} +![Shikiji влит обратно в Shiki](/assets/blog/shiki-merge-pr.png){.rounded-lg.shadow} -Shiki now also got [a brand new documentation site](https://shiki.style/) where you can also play it right in your browser (thanks to the agnostic approach!). Many frameworks now has built-in integration with Shiki, maybe you are already using it somewhere! +Shiki также получил [совершенно новый сайт документации](https://shiki.style/), где вы также можете поиграться с ним прямо в браузере (спасибо агностическому подходу!). Многие фреймворки теперь имеют встроенную интеграцию с Shiki, возможно, вы уже используете его где-то! ## Twoslash -[Twoslash](https://github.com/twoslashes/twoslash) is an integration tool to retrieve type information from [TypeScript Language Services](https://github.com/microsoft/TypeScript/wiki/Using-the-Language-Service-API) and generated to your code snippet. It essentially make your static code snippet to have hover type information similiar to your VS Code editor. It's made by [Orta Therox](https://github.com/orta) for the [TypeScript documentation site](https://github.com/microsoft/TypeScript-Website), there you can find [the original source code here](https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ts-twoslasher). Orta also created the [Twoslash integration for Shiki v0.x versions](https://github.com/shikijs/twoslash). Back then, Shiki [did not have proper plugin system](https://github.com/shikijs/shiki/issues/380), that makes the `shiki-twoslash` had to be built as a wrapper over Shiki, make it a bit hard to set up as the existing Shiki integrations won't directly work with Twoslash. +[Twoslash](https://github.com/twoslashes/twoslash) — это инструмент интеграции для извлечения информации о типе из [TypeScript Language Services](https://github.com/microsoft/TypeScript/wiki/Using-the-Language-Service-API) и генерации в ваш сниппет кода. По сути, он делает статический фрагмент кода похожим на редактор VS Code. Он создан [Orta Therox](https://github.com/orta) для [сайта документации TypeScript](https://github.com/microsoft/TypeScript-Website), вы можете найти [исходный код здесь](https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ts-twoslasher). Orta также создал [интеграцию Twoslash для версий Shiki v0.x](https://github.com/shikijs/twoslash). Тогда у Shiki [не было надлежащей системы плагинов](https://github.com/shikijs/shiki/issues/380), из-за чего `shiki-twoslash` приходилось создавать как оболочку над Shiki, что немного усложняло настройку, поскольку существующие интеграции Shiki не работали напрямую с Twoslash. -We also took the chance to revise the Twoslash integrations when we were rewriting Shikiji, also a way to [dog-fooding](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) and verify the extensibility. With the new HAST internal, we are able to [integrate Twoslash as a transformer plugin](https://shiki.style/packages/twoslash), making it works everywhere that Shiki works and also in a composable way to be used with other transformers. +Мы также воспользовались шансом пересмотреть интеграции Twoslash, когда переписывали Shikiji, попробовать ["dog-fooding"](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) и проверить расширяемость. С новым внутренним HAST мы можем [интегрировать Twoslash как плагин-трансформер](https://shiki.style/packages/twoslash), что делает его работающим везде, где работает Shiki, а также тспользовать в виде композабла с другими трансформерами. -With this, we started to think that we could probably get Twoslash to work on [nuxt.com](/), the website you are looking at. nuxt.com uses [Nuxt Content](https://github.com/nuxt/content) under the hood, and different from other documentation tools like VitePress, one of the benefits Nuxt Content provides is that it's able to handle dynamic content and runs on the edge. Since Twoslash is relying on TypeScript as well as the giant types modules graph from your dependencies, that would be not ideal to ship all those things to the edge or browser. Sounds tricky, but challenge accepted! +Далее мы начали думать, что, вероятно, сможем заставить Twoslash работать на [nuxt.com](/), веб-сайте, который вы читаете. nuxt.com под капотом использует [Nuxt Content](https://github.com/nuxt/content), и в отличие от других инструментов документирования, таких как VitePress, одним из преимуществ Nuxt Content является то, что он может обрабатывать динамический контент и работать на распределенных серверах. Поскольку Twoslash полагается на TypeScript, а также на гигантский граф типов модулей из ваших зависимостей, было бы не идеально отправлять все эти вещи на периферийные сервера или в браузер. Звучит сложно, но вызов принят! -We first come up of fetching the types on-demand from CDN, using the [Auto-Type-Acquisition](https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ata) technique that you will see on the [TypeScript playground](https://www.typescriptlang.org/play). We made the [`twoslash-cdn`](https://github.com/antfu/twoslash-cdn) that allows Twoslash to run in any runtime. However, still, it sounds like not the most optimal solution, as it would still require to make many network requests that might defeat the purpose of running on the edge. +Сначала мы пришли к выборке типов из CDN по запросу, используя технику [Auto-Type-Acquisition](https://github.com/microsoft/TypeScript-Website/tree/v2/packages/ata), которую вы увидите на [TypeScript playground](https://www.typescriptlang.org/play). Мы создали [`twoslash-cdn`](https://github.com/antfu/twoslash-cdn), который позволяет Twoslash работать в любой среде выполнения. Однако, это звучит как не самое оптимальное решение, так как все равно потребует делать много сетевых запросов, что может свести на нет смысл работы на периферии. -After a few iterations on the underlying tools (e.g. on [`@nuxtjs/mdc`](https://github.com/nuxt-modules/mdc/pull/129), the markdown compiler used by Nuxt Content), we managed to take the hybrid approach and made [`nuxt-content-twoslash`](https://github.com/antfu/nuxt-content-twoslash) that runs Twoslash on build time and caches the results for edge rendering. This way we could avoid shipping any extra dependencies to the final bundle, but still have the rich interactive code snippets on the website: +После нескольких итераций на базовых инструментах (например, [`@nuxtjs/mdc`](https://github.com/nuxt-modules/mdc/pull/129), компилятора разметки, используемого Nuxt Content), нам удалось применить гибридный подход и создать [`nuxt-content-twoslash`](https://github.com/antfu/nuxt-content-twoslash), который запускает Twoslash во время сборки и кэширует результаты для граничного рендеринга. Таким образом, мы смогли избежать отправки дополнительных зависимостей в финальный пакет, но при этом иметь богатые интерактивные фрагменты кода на веб-сайте: ```vue twoslash @@ -139,23 +139,23 @@ const double = computed(() => count.value * 2) ``` -During that, we also took the chance to refactor [Twoslash](https://github.com/twoslashes/twoslash) with Orta to have a more efficient and modern structure. It also allows us have [`twoslash-vue`](https://github.com/twoslashes/twoslash/tree/main/packages/twoslash-vue) that provides the [Vue SFC](https://ru.vuejs.org/guide/scaling-up/sfc.html) support as you are playing above. It's powered by [Volar.js](https://github.com/volarjs/volar.js) and [`vuejs/language-tools`](https://github.com/vuejs/language-tools). With Volar growing to be framework agnostic and frameworks to work together, we are looking forward to see such integrations to expand to more syntaxes like Astro and Svelte components files in the future. +В то же время мы воспользовались шансом провести рефакторинг [Twoslash](https://github.com/twoslashes/twoslash) с помощью Orta, чтобы иметь более эффективную и современную структуру. Это также позволяет нам иметь [`twoslash-vue`](https://github.com/twoslashes/twoslash/tree/main/packages/twoslash-vue), который обеспечивает поддержку [Vue SFC](https://ru.vuejs.org/guide/scaling-up/sfc.html), как вы видите выше. Он работает на [Volar.js](https://github.com/volarjs/volar.js) и [`vuejs/language-tools`](https://github.com/vuejs/language-tools). Поскольку Volar становится все более независимым от фреймворков, а фреймворки работают вместе, мы с нетерпением ждем, когда в будущем такие интеграции распространятся на большее количество синтаксисов, таких как файлы компонентов Astro и Svelte. -## Integrations +## Интеграции -If you want to give Shiki a try in your own website, here you can find some integrations that we have made: +Если вы хотите попробовать Shiki на своем собственном сайте, здесь вы можете найти некоторые интеграции, которые мы сделали: - [Nuxt](https://shiki.style/packages/nuxt) - - If using [Nuxt Content](https://content.nuxt.com/), Shiki is [build-in](https://content.nuxt.com/get-started/configuration#highlight). For Twoslash, you can add [`nuxt-content-twoslash`](https://github.com/antfu/nuxt-content-twoslash) on top. - - If not, you can use [`nuxt-shiki`](https://github.com/pi0/nuxt-shiki) to use Shiki as Vue component or composibles. + - Если используется [Nuxt Content](https://content.nuxt.com/), Shiki [встроен](https://content.nuxt.com/get-started/configuration#highlight). Для Twoslash можно сверху добавить [`nuxt-content-twoslash`](https://github.com/antfu/nuxt-content-twoslash). + - Если нет, вы можете использовать [`nuxt-shiki`](https://github.com/pi0/nuxt-shiki) для использования Shiki в качестве компонента Vue или композабла. - [VitePress](https://shiki.style/packages/vitepress) - - Shiki is [built-in](https://vitepress.dev/guide/markdown#syntax-highlighting-in-code-blocks). For Twoslash, you can use [`vitepress-twoslash`](https://shiki.style/packages/vitepress#twoslash). -- Low-level integrations - Shiki provides official integrations for markdown compilers: - - [`markdown-it`](https://shiki.style/packages/markdown-it) - Plugin for [`markdown-it`](https://github.com/markdown-it/markdown-it) - - [`rehype`](https://shiki.style/packages/rehype) - Plugin for [`rehype`](https://github.com/rehypejs/rehype) + - Shiki [встроен](https://vitepress.dev/guide/markdown#syntax-highlighting-in-code-blocks). Для Twoslash вы можете использовать [`vitepress-twoslash`](https://shiki.style/packages/vitepress#twoslash). +- Низкоуровневые интеграции — Shiki предоставляет официальные интеграции для компиляторов markdown: + - [`markdown-it`](https://shiki.style/packages/markdown-it) - Плагин для [`markdown-it`](https://github.com/markdown-it/markdown-it) + - [`rehype`](https://shiki.style/packages/rehype) - Плагин для [`rehype`](https://github.com/rehypejs/rehype) -Check out more integrations on [Shiki's Documentation](https://shiki.style/) +Ознакомьтесь с другими интеграциями в [документации Shiki](https://shiki.style/) -## Conclusions +## Выводы -**Our mission at Nuxt is not only to make a better framework for developers, but also to make the entire frontend and web ecosystem a better place.** We are keeping pushing the boundaries and endorse the modern web standards and best practices. We hope you enjoy the new [Shiki](https://github.com/shikijs/shiki), [unwasm](https://github.com/unjs/unwasm), [Twoslash](https://github.com/twoslashes/twoslash) and many other tools we made in the process of making Nuxt and the web better. +**Наша миссия в Nuxt — не только создать лучший фреймворк для разработчиков, но и сделать всю экосистему фронтенда и веба лучше.** Мы продолжаем расширять границы и поддерживать современные веб-стандарты и лучшие практики. Надеемся, вам понравятся новые [Shiki](https://github.com/shikijs/shiki), [unwasm](https://github.com/unjs/unwasm), [Twoslash](https://github.com/twoslashes/twoslash) и многие другие инструменты, которые мы создали в процессе улучшения Nuxt и веба. \ No newline at end of file