npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@docfy/plugin-shiki

v0.14.2

Published

An opt-in Shiki syntax highlighting preset for Docfy

Readme

@docfy/plugin-shiki

An opt-in Shiki syntax-highlighting preset for Docfy, with first-class support for Ember's .gjs/.gts file types.

This package is standalone: shiki is never a dependency of @docfy/core or @docfy/ember. Consumers who want syntax highlighting install this package and spread its return value into their own rehypePlugins.

Why this exists

Wiring up Shiki (or rehype-highlight) by hand for a Docfy site normally means re-deriving the same handful of settings every time: which themes to use, how to map gjs/gts/hbs fence languages onto real grammars, and how to enable {1,3-5}-style line highlighting. This preset packages all of that up so you don't have to.

Glimmer support is the main reason this package exists. Shiki bundles first-class glimmer-js and glimmer-ts TextMate grammars (scope source.gts), so a .gts/.gjs code fence gets real tokenisation — including inside <template> tags — instead of silently falling back to plain JavaScript (or plain text).

Installation

pnpm add @docfy/plugin-shiki

Usage

import Docfy from '@docfy/core';
import docfyShiki from '@docfy/plugin-shiki';

const docfy = new Docfy({
  rehypePlugins: [
    // ...your other rehype plugins
    ...docfyShiki(),
  ],
});

Why this preset builds its own highlighter

@docfy/core drives its rehype pipeline with unified().runSync(...) (see packages/core/src/-private/remark.ts), never the async .run()/.process(). Shiki's own @shikijs/rehype default export is async-only — it lazily boots a singleton highlighter the first time the tree transformer runs — so wiring it in directly makes runSync throw.

@docfy/ember-cli (the classic, non-Vite build) also loads a consumer's docfy.config.* with a synchronous require(). A module that contains a top-level await anywhere in its graph is an async ES module, and Node throws ERR_REQUIRE_ASYNC_MODULE the moment such a config merely imports it — so this package cannot use a top-level await either, even to build its highlighter once at startup.

To stay synchronous end-to-end, this preset:

  • Loads its grammars and themes via plain, static import statements (see "Supported languages" and "Supported themes" below) — never a dynamic import() or a top-level await. This applies just as much to any extra grammar you pass via langs (see "Adding a language" below).
  • Builds a Shiki HighlighterCore via createHighlighterCoreSync, using the pure-JS regex engine (no WASM to load). Calling docfyShiki() with no langs/langAlias reuses one memoized highlighter across calls, built the first time it's needed rather than at import time — a consumer that imports this package but never calls docfyShiki() doesn't pay for it at all. Passing langs and/or langAlias builds a dedicated highlighter for that call instead, since langAlias can only be set at construction time (see "Language aliases" below).
  • Uses @shikijs/rehype/core's rehypeShikiFromHighlighter, which — given an already-built highlighter and no lazy-loaded languages — returns a genuinely synchronous unified transformer.

Supported languages

Preloading every language Shiki bundles (~200 grammars, ~11.6MB of JSON) would cost real parse time at import, whether or not a given site uses most of them. Instead, this preset preloads a curated set covering the glimmer grammars that are the point of the package, plus the languages Docfy's own docs (and typical Ember app docs) actually fence:

glimmer-ts, glimmer-js, handlebars, javascript, typescript, jsx, tsx, json, css, scss, html, markdown, shellscript, diff, yaml.

It also registers these language aliases so fences written the way Ember docs are actually written resolve to the grammars above:

| Fence language | Resolves to | | -------------- | ------------ | | gts | glimmer-ts | | gjs | glimmer-js | | hbs | handlebars |

You can add to (or override) this table with the langAlias option — see "Adding a language" below.

Adding a language

A fence whose language is not in the curated list above (for example ```rust) is, by default, not an error: @shikijs/rehype leaves any <pre> whose language isn't loaded completely untouched — no .shiki wrapper, no theme classes, no Shiki-applied highlighting — it renders as plain, unhighlighted fenced code, exactly as if no highlighter were configured for it. A docs build never fails because someone wrote a fence in a language this preset doesn't preload.

If you actually want that language highlighted, pass its grammar via the langs option. Each entry is a statically-imported module from @shikijs/langs (or any other Shiki-compatible grammar you import yourself) — never a dynamic import(), since this package has to stay synchronous end-to-end (see "Why this preset builds its own highlighter" above):

import rust from '@shikijs/langs/rust';
import shiki from '@docfy/plugin-shiki';

export default {
  rehypePlugins: [autolinkHeadings, ...shiki({ langs: [rust] })],
};

A ```rust fence now tokenizes for real. langs is additive — it doesn't replace the curated set this preset already preloads.

If the language you need is only reachable under a different fence name (for example your docs use ```rs rather than ```rust), pair langs with langAlias, which is merged over this preset's own gjs/gts/hbs table:

shiki({ langs: [rust], langAlias: { rs: 'rust' } });

langAlias on its own (without a matching langs entry) cannot make a new language highlight — see "Language aliases" below for why, and why the two options work together the way they do.

Supported themes

This preset statically preloads three themes: github-light, github-dark (the defaults), and nord, and — unlike languages — there is currently no option to add more; passing an unloaded theme name throws, because the underlying highlighter is built synchronously and cannot fetch a theme afterwards.

Overriding themes

docfyShiki({
  themes: { light: 'github-light', dark: 'nord' },
});

Language aliases

An earlier version of this package removed a langAlias option, because at the time the highlighter was built once, synchronously, at module import time — before docfyShiki(options) was ever called. An alias supplied at call time could only ever change the data-language attribute this preset writes on the rendered <pre>; it could never register a new alias with Shiki's grammar resolver, which was already fixed by then. A caller adding, say, { svelte: 'html' } would see their fence mislabelled rather than actually highlighted as HTML — an option that appears to work and silently does not, which is worse than no option.

langAlias is back because that constraint no longer holds: the highlighter is now built inside docfyShiki() itself (see "Adding a language" above), so an alias supplied there is baked into the same construction call as any langs you pass alongside it, and genuinely participates in grammar resolution. langAlias merges over the package's own gjs/gts/hbs table — it can override one of those three, but not remove the other two.

Passing langAlias without a matching langs entry (or one of the languages this preset already preloads) still can't highlight anything new — an alias can only point at a grammar that's actually loaded. But it no longer looks like it worked when it didn't: a fence whose alias points at an unloaded grammar is left completely untouched (see "Adding a language" above) — no data-language attribute either, exactly like any other unsupported language — rather than being mislabelled with a data-language that implies it highlighted.

Extra transformers

import { transformerNotationDiff } from '@shikijs/transformers';

docfyShiki({
  transformers: [transformerNotationDiff()],
});

transformers is appended after this preset's own defaults (transformerMetaHighlight, transformerMetaWordHighlight, and two small internal transformers that add the data-language="..." and data-highlighted attributes described above).

Line highlighting

Marking specific lines in a fence, e.g.:

```ts {2,4-5}
// ...
```

works because this preset wires up transformerMetaHighlight from @shikijs/transformers. Line highlighting is not a feature of Shiki (or of Docfy) on its own — it only works when this preset (or an equivalent Shiki configuration that includes transformerMetaHighlight) is in use. Highlighted lines get both a highlighted class and a data-highlighted attribute, so you can style them with either .highlighted or [data-highlighted] in your own CSS.

License

This project is licensed under the MIT License.