Skip to content

Commit 9cc01bc

Browse files
authored
feat: introduce web bundle (#56)
1 parent 1695612 commit 9cc01bc

23 files changed

+1766
-1399
lines changed

docs/.vitepress/components/LanguagesList.vue

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { ref } from 'vue'
2+
import { computed, ref } from 'vue'
33
import { usePlayground } from '../store/playground'
44
55
const play = usePlayground()
@@ -9,10 +9,27 @@ function preview(id: string) {
99
play.lang = id
1010
showModel.value = true
1111
}
12+
13+
const bundle = ref('all')
14+
15+
const langs = computed(() => {
16+
if (bundle.value === 'web')
17+
return play.bundledLangsWeb
18+
return play.bundledLangsFull
19+
})
1220
</script>
1321

1422
<template>
1523
<div>
24+
<div flex="~ gap-0.5 items-center">
25+
<input id="radio-all" v-model="bundle" type="radio" name="lang" value="all">
26+
<label for="radio-all">Full Bundle</label>
27+
<div mx2 />
28+
<input id="radio-web" v-model="bundle" type="radio" name="lang" value="web">
29+
<label for="radio-web">Web Bundle</label>
30+
<div mx2 />
31+
<a href="/guide/bundles">?</a>
32+
</div>
1633
<table>
1734
<thead>
1835
<tr>
@@ -23,7 +40,7 @@ function preview(id: string) {
2340
</tr>
2441
</thead>
2542
<tbody>
26-
<tr v-for="l in play.allLanguages" :key="l.id">
43+
<tr v-for="l in langs" :key="l.id">
2744
<td>{{ l.name }}</td>
2845
<td><code>{{ l.id }}</code></td>
2946
<td>

docs/.vitepress/config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const GUIDES: DefaultTheme.NavItemWithLink[] = [
99
{ text: 'Getting Started', link: '/guide/' },
1010
{ text: 'Installation', link: '/guide/install' },
1111
{ text: 'Shorthands', link: '/guide/shorthands' },
12+
{ text: 'Bundles', link: '/guide/bundles' },
1213
{ text: 'Dual Themes', link: '/guide/dual-themes' },
1314
{ text: 'Transformers', link: '/guide/transformers' },
1415
{ text: 'Compat Build', link: '/guide/compat' },

docs/.vitepress/store/playground.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export const usePlayground = defineStore('playground', () => {
2323
import: undefined!,
2424
},
2525
])
26+
const bundledLangsFull = shallowRef<BundledLanguageInfo[]>([])
27+
const bundledLangsWeb = shallowRef<BundledLanguageInfo[]>([])
28+
2629
const input = useLocalStorage('shikiji-playground-input', '')
2730
const output = ref('<pre></pre>')
2831
const preStyle = ref('')
@@ -38,7 +41,8 @@ export const usePlayground = defineStore('playground', () => {
3841
if (typeof window !== 'undefined') {
3942
(async () => {
4043
const { getHighlighter, addClassToHast } = await import('shikiji')
41-
const { bundledLanguagesInfo } = await import('shikiji/langs')
44+
const { bundledLanguagesInfo: bundleFull } = await import('shikiji/bundle/full')
45+
const { bundledLanguagesInfo: bundleWeb } = await import('shikiji/bundle/web')
4246
const { bundledThemesInfo } = await import('shikiji/themes')
4347
const highlighter = await getHighlighter({
4448
themes: [theme.value],
@@ -60,7 +64,9 @@ export const usePlayground = defineStore('playground', () => {
6064
}
6165

6266
allThemes.value = bundledThemesInfo
63-
allLanguages.value = bundledLanguagesInfo
67+
allLanguages.value = bundleFull
68+
bundledLangsFull.value = bundleFull
69+
bundledLangsWeb.value = bundleWeb
6470

6571
watch(input, run, { immediate: true })
6672

@@ -102,6 +108,8 @@ export const usePlayground = defineStore('playground', () => {
102108
theme,
103109
allLanguages,
104110
allThemes,
111+
bundledLangsFull,
112+
bundledLangsWeb,
105113
input,
106114
output,
107115
isLoading,

docs/guide/bundles.md

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
outline: deep
3+
---
4+
5+
# Bundles
6+
7+
The main `shikiji` entries bundles all supported themes and languages via lazy dynamic imports. The efficiency shouldn't be a concern to most of the scenarios as the grammar would only be imported/downloaded when it is used. However, when you bundle Shikiji into browsers runtime or web workers, even those files are not imported, they still add up to your dist size. We provide the [fine-grained bundle](/guide/install#fine-grained-bundle) to help you compose languages and themes one-by-one as you need.
8+
9+
To make it easier, we also provide some pre-composed bundles for you to use:
10+
11+
## `shikiji/bundle/full`
12+
13+
The full bundle includes all themes and languages, same as the main `shikiji` entry.
14+
15+
## `shikiji/bundle/web`
16+
17+
The bundle the includes all themes and common web languages like (HTML, CSS, JS, TS, JSON, Markdown, etc.) and some web frameworks (Vue, JSX, Svelte, etc.).
18+
19+
Use as normal, all functions from `shikiji` are also available in the bundle:
20+
21+
```ts
22+
import {
23+
BundledLanguage,
24+
BundledTheme,
25+
codeToHtml,
26+
getHighlighter
27+
} from 'shikiji/bundle/web' // [!code highlight]
28+
29+
const highlighter = await getHighlighter({
30+
langs: ['html', 'css', 'js'],
31+
themes: ['github-dark', 'github-light'],
32+
})
33+
```

docs/guide/install.md

+12-5
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ const code = shiki.codeToHtml('const a = 1', {
126126
})
127127
```
128128

129+
### Bundle Presets
130+
131+
We also provide some pre-composed bundles for you to use easily, learn more about them in the [bundles section](/guide/bundles).
132+
129133
### CJS Usage
130134

131135
`shikiji` is published as ESM-only to reduce the package size. It's still possible to use it in CJS, as Node.js supports importing ESM modules dynamically in CJS.
@@ -138,7 +142,7 @@ import { getHighlighter } from 'shikiji'
138142

139143
async function main() {
140144
const shiki = await getHighlighter({
141-
themes: ['nord'],
145+
themes: ['vitesse-dark'],
142146
langs: ['javascript'],
143147
})
144148

@@ -154,7 +158,7 @@ async function main() {
154158
const { getHighlighter } = await import('shikiji')
155159

156160
const shiki = await getHighlighter({
157-
themes: ['nord'],
161+
themes: ['vitesse-dark'],
158162
langs: ['javascript'],
159163
})
160164

@@ -166,7 +170,7 @@ async function main() {
166170

167171
To use `shikiji` in the browser via CDN, you can use [esm.run](https://esm.run) or [esm.sh](https://esm.sh).
168172

169-
```html
173+
```html theme:rose-pine
170174
<body>
171175
<div id="foo"></div>
172176

@@ -177,7 +181,10 @@ To use `shikiji` in the browser via CDN, you can use [esm.run](https://esm.run)
177181
// import { codeToHtml } from 'https://esm.run/shikiji@0.8.0'
178182
179183
const foo = document.getElementById('foo')
180-
foo.innerHTML = await codeToHtml('console.log("Hi, Shiki on CDN :)")', { lang: 'js', theme: 'vitesse-light' })
184+
foo.innerHTML = await codeToHtml('console.log("Hi, Shiki on CDN :)")', {
185+
lang: 'js',
186+
theme: 'rose-pine'
187+
})
181188
</script>
182189
</body>
183190
```
@@ -192,7 +199,7 @@ Cloudflare Workers [does not support initializing WebAssembly from binary data](
192199

193200
Meanwhile, it's also recommended to use the [Fine-grained Bundle](#fine-grained-bundle) approach to reduce the bundle size.
194201

195-
```ts
202+
```ts theme:nord
196203
import { getHighlighterCore, loadWasm } from 'shikiji/core'
197204
import nord from 'shikiji/themes/nord.mjs'
198205
import js from 'shikiji/langs/javascript.mjs'

docs/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121
"unocss": "^0.58.0",
2222
"unplugin-vue-components": "^0.26.0",
2323
"vitepress": "1.0.0-rc.30",
24-
"vue": "^3.3.11"
24+
"vue": "^3.3.13"
2525
}
2626
}

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
"@rollup/plugin-terser": "^0.4.4",
2525
"@types/fs-extra": "^11.0.4",
2626
"@types/hast": "^3.0.3",
27-
"@types/node": "^20.10.4",
28-
"@vitest/coverage-v8": "^1.0.4",
27+
"@types/node": "^20.10.5",
28+
"@vitest/coverage-v8": "^1.1.0",
2929
"ansi-sequence-parser": "^1.1.1",
3030
"bumpp": "^9.2.1",
3131
"eslint": "npm:eslint-ts-patch@8.55.0-1",
@@ -42,7 +42,7 @@
4242
"pnpm": "^8.12.1",
4343
"prettier": "^3.1.1",
4444
"rimraf": "^5.0.5",
45-
"rollup": "^4.9.0",
45+
"rollup": "^4.9.1",
4646
"rollup-plugin-copy": "^3.5.0",
4747
"rollup-plugin-dts": "^6.1.0",
4848
"rollup-plugin-esbuild": "^6.1.0",
@@ -53,9 +53,9 @@
5353
"typescript": "^5.3.3",
5454
"unbuild": "^2.0.0",
5555
"vite": "^5.0.10",
56-
"vitest": "^1.0.4",
56+
"vitest": "^1.1.0",
5757
"vue-tsc": "^1.8.25",
58-
"wrangler": "^3.21.0"
58+
"wrangler": "^3.22.1"
5959
},
6060
"pnpm": {
6161
"patchedDependencies": {

packages/shikiji-core/src/types.ts

+17
Original file line numberDiff line numberDiff line change
@@ -578,4 +578,21 @@ export interface ThemedTokenWithVariants extends TokenBase {
578578
variants: Record<string, TokenStyles>
579579
}
580580

581+
export type DynamicImportLanguageRegistration = () => Promise<{ default: LanguageRegistration[] }>
582+
export type DynamicImportThemeRegistration = () => Promise<{ default: ThemeRegistration }>
583+
584+
export interface BundledLanguageInfo {
585+
id: string
586+
name: string
587+
import: DynamicImportLanguageRegistration
588+
aliases?: string[]
589+
}
590+
591+
export interface BundledThemeInfo {
592+
id: string
593+
displayName: string
594+
type: 'light' | 'dark'
595+
import: DynamicImportThemeRegistration
596+
}
597+
581598
export {}

packages/shikiji-twoslash/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"shikiji-core": "workspace:*"
6060
},
6161
"devDependencies": {
62-
"@iconify-json/carbon": "^1.1.26",
62+
"@iconify-json/carbon": "^1.1.27",
6363
"@iconify-json/codicon": "^1.1.39",
6464
"hast-util-from-html": "^2.0.1",
6565
"shiki": "^0.14.7",

packages/shikiji/package.json

+16-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@
3737
"types": "./dist/themes.d.mts",
3838
"default": "./dist/themes.mjs"
3939
},
40+
"./bundle/full": {
41+
"types": "./dist/bundle-full.d.mts",
42+
"default": "./dist/bundle-full.mjs"
43+
},
44+
"./bundle/web": {
45+
"types": "./dist/bundle-web.d.mts",
46+
"default": "./dist/bundle-web.mjs"
47+
},
4048
"./dist/*": "./dist/*",
4149
"./*": "./dist/*"
4250
},
@@ -57,6 +65,12 @@
5765
"themes": [
5866
"./dist/themes.d.mts"
5967
],
68+
"bundle/full": [
69+
"./dist/bundle-full.d.mts"
70+
],
71+
"bundle/web": [
72+
"./dist/bundle-web.d.mts"
73+
],
6074
"*": [
6175
"./dist/*",
6276
"./*"
@@ -78,8 +92,8 @@
7892
"shikiji-core": "workspace:*"
7993
},
8094
"devDependencies": {
81-
"tm-grammars": "^0.0.6",
82-
"tm-themes": "^0.0.3",
95+
"tm-grammars": "^1.0.2",
96+
"tm-themes": "^1.0.0",
8397
"vscode-oniguruma": "^1.7.0"
8498
}
8599
}

packages/shikiji/rollup.config.mjs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const entries = [
1717
'src/themes.ts',
1818
'src/langs.ts',
1919
'src/wasm.ts',
20+
'src/bundle-full.ts',
21+
'src/bundle-web.ts',
2022
]
2123

2224
const external = [

packages/shikiji/scripts/prepare/langs.ts

+26-18
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ export async function prepareLangs() {
2222
}
2323

2424
const json: LanguageRegistration = {
25-
...lang,
2625
...content,
2726
name: content.name || lang.name,
2827
scopeName: content.scopeName || lang.scopeName,
2928
displayName: lang.displayName,
3029
embeddedLangs: lang.embedded,
30+
aliases: lang.aliases,
3131
}
3232

3333
// F# and Markdown has circular dependency
@@ -43,7 +43,7 @@ import type { LanguageRegistration } from 'shikiji-core'
4343
4444
${deps.map(i => `import ${i.replace(/[^\w]/g, '_')} from './${i}'`).join('\n')}
4545
46-
const lang = Object.freeze(${JSON.stringify(json, null, 2)}) as unknown as LanguageRegistration
46+
const lang = Object.freeze(${JSON.stringify(json)}) as unknown as LanguageRegistration
4747
4848
export default [
4949
${[
@@ -54,14 +54,18 @@ ${[
5454
`, 'utf-8')
5555
}
5656

57-
async function writeLanguageBundleIndex(fileName: string, ids: string[]) {
58-
const bundled = ids.map(id => grammars.find(i => i.name === id)!)
57+
async function writeLanguageBundleIndex(
58+
fileName: string,
59+
ids: string[],
60+
exclude: string[] = [],
61+
) {
62+
const bundled = ids.map(id => grammars.find(i => i.name === id)!).filter(i => !exclude.includes(i.name))
5963

6064
const info = bundled.map(i => ({
6165
id: i.name,
6266
name: i.displayName || i.name,
6367
aliases: i.aliases,
64-
import: `__(() => import('./langs/${i.name}')) as DynamicLangReg__`,
68+
import: `__(() => import('./langs/${i.name}')) as DynamicImportLanguageRegistration__`,
6569
}) as const)
6670
.sort((a, b) => a.id.localeCompare(b.id))
6771

@@ -70,33 +74,37 @@ ${[
7074
await fs.writeFile(
7175
`src/assets/${fileName}.ts`,
7276
`${COMMENT_HEAD}
73-
import type { LanguageRegistration } from 'shikiji-core'
74-
75-
type DynamicLangReg = () => Promise<{ default: LanguageRegistration[] }>
76-
77-
export interface BundledLanguageInfo {
78-
id: string
79-
name: string
80-
import: DynamicLangReg
81-
aliases?: string[]
82-
}
77+
import type { DynamicImportLanguageRegistration, BundledLanguageInfo } from 'shikiji-core'
8378
8479
export const bundledLanguagesInfo: BundledLanguageInfo[] = ${JSON.stringify(info, null, 2).replace(/"__|__"/g, '').replace(/"/g, '\'')}
8580
8681
export const bundledLanguagesBase = Object.fromEntries(bundledLanguagesInfo.map(i => [i.id, i.import]))
8782
8883
export const bundledLanguagesAlias = Object.fromEntries(bundledLanguagesInfo.flatMap(i => i.aliases?.map(a => [a, i.import]) || []))
8984
90-
export type BuiltinLanguage = ${type}
85+
export type BundledLanguage = ${type}
9186
9287
export const bundledLanguages = {
9388
...bundledLanguagesBase,
9489
...bundledLanguagesAlias,
95-
} as Record<BuiltinLanguage, DynamicLangReg>
90+
} as Record<BundledLanguage, DynamicImportLanguageRegistration>
9691
`,
9792
'utf-8',
9893
)
9994
}
10095

101-
await writeLanguageBundleIndex('langs', grammars.map(i => i.name))
96+
await writeLanguageBundleIndex(
97+
'langs-bundle-full',
98+
grammars.map(i => i.name),
99+
)
100+
await writeLanguageBundleIndex(
101+
'langs-bundle-web',
102+
[
103+
...grammars.filter(i => i.categories?.includes('web')).map(i => i.name),
104+
'shellscript',
105+
],
106+
[
107+
'coffee',
108+
],
109+
)
102110
}

0 commit comments

Comments
 (0)