syntax styling utilities and components for TypeScript, Svelte, SvelteKit 🎨
fuz_code is a rework of Prism. The main changes:
Like Prism, there are zero dependencies (unless you count Prism's @types/prismjs
),
but there are two optional dependencies:
prism-svelte
and a Svelte component for convenient usage.color-scheme
preference.
A zero-dependency theme
is also provided that uses the less-customizable light-dark()
, see below for more.Compared to Shiki,
this library is much lighter
(with its faster shiki/engine/javascript
, 503kB minified to 16kB, 63kb gzipped to 5.6kB),
and vastly faster
for runtime usage because it uses JS regexps instead of
the Onigurama regexp engine
used by TextMate grammars.
Shiki also has 38 dependencies instead of 0.
However this is not a fair comparison because Shiki is designed mainly for buildtime usage,
and Prism grammars are much simpler and less powerful than TextMate's.
npm i -D @ryanatkn/fuz_code
import {syntax_styler} from '@ryanatkn/fuz_code';
syntax_styler.stylize('<h1>hello world</h1>', 'svelte');
Themes are just CSS files, so they work with any JS framework.
With SvelteKit:
// +layout.svelte
import '@ryanatkn/fuz_code/theme.css';
The primary themes (currently just one) have a dependency on my CSS library Moss for color-scheme awareness. See the Moss docs for its usage.
A dependency-free version of the default theme is provided,
but note that the colors are staticly defined instead of using
Moss' style variables.
They use light-dark()
which means they're hardcoded to the inferred color-scheme
,
rather than being settable by a user option unlike the Moss version. This could be improved using a class convention like .dark
.
// no dependencies:
import '@ryanatkn/fuz_code/theme_standalone.css';
I encourage you to poke around src/lib
if you're interested in using fuz_code.
Enabled by default:
Docs are a work in progress:
Please open issues if you need any help.
markdown
and regexp
Code.svelte
Performance is a high priority to best support runtime usage. This project is still early and there are more gains to be had.
Note that this benchmark is somewhat unfair to Shiki because it's not designed for runtime usage, and it probably does a significantly better job at the task at hand because it uses TextMate grammars.
Results styling the Svelte sample:
Task name | Throughput average (ops/s) | Throughput median (ops/s) | Samples |
---|---|---|---|
syntax_styler.stylize | 3149 ± 0.56% | 3333 | 6004 |
Prism.highlight | 2748 ± 0.51% | 2500 | 5293 |
Shiki engine/javascript | 69 ± 0.59% | 69 | 138 |
Shiki engine/oniguruma | 41 ± 0.27% | 40 | 82 |
Directly runnable benchmarks are not included yet - I don't know if I'll add them here or make a separate project.
To run the benchmarks yourself:
npm i -D shiki prismjs prism-svelte @types/prismjs @ryanatkn/fuz_code
Then add this file and import it somewhere like $routes/+page.svelte
:
// $lib/benchmark.ts
import {Bench} from 'tinybench';
import Prism from 'prismjs';
import 'prism-svelte';
import {createHighlighterCoreSync} from 'shiki/core';
import {createJavaScriptRegexEngine} from 'shiki/engine/javascript';
import svelte_shiki from 'shiki/langs/svelte.mjs';
import nord from 'shiki/themes/nord.mjs';
import {createOnigurumaEngine} from 'shiki/engine/oniguruma';
import {syntax_styler} from '$lib/index.js';
import {sample_svelte_code} from '$lib/code_sample_inputs.js';
console.log('benchmarking');
const bench = new Bench({name: 'syntax styling', time: 2000});
const shiki_highlighter_js = createHighlighterCoreSync({
themes: [nord],
langs: [svelte_shiki],
engine: createJavaScriptRegexEngine(),
});
const shiki_highlighter_builtin = createHighlighterCoreSync({
themes: [nord],
langs: [svelte_shiki],
engine: await createOnigurumaEngine(import('shiki/wasm')),
});
bench
.add('syntax_styler.stylize', () => {
syntax_styler.stylize(sample_svelte_code, 'svelte');
})
.add('Prism.highlight', () => {
Prism.highlight(sample_svelte_code, Prism.langs.svelte, 'svelte');
})
.add('Shiki engine/javascript', () => {
shiki_highlighter_js.codeToHtml(sample_svelte_code, {lang: 'svelte', theme: 'nord'});
})
.add('Shiki engine/oniguruma', () => {
shiki_highlighter_builtin.codeToHtml(sample_svelte_code, {lang: 'svelte', theme: 'nord'});
});
await bench.run();
console.log(bench.name);
console.table(bench.table());
the Svelte grammar
is based on prism-svelte
by @pngwn