Highlight.js のバンドルサイズを削減する

2020/02/16 02:02:272020/06/07 21:51:39


追記: この記事は highlight.js <= 9.18.1 の環境を想定しています。

みなさん、Hightlight.js 使ってますか?
  • Caramelize での codeBlock シンタックスハイライトに用いています

ところで…
デカくないですか?

どうやって削減
個別 import していきましょう
  • hightlight.js のトップレベルには型定義がありますが、languages にはありません
  • 使いそうなものを頑張って require していきます
理想.ts
["bash"].map(language => {return [language, require(`highlight.js/lib/languages/${language}`)]})
  • こういう記法ができれば良かったのですが
  • これをやると綺麗に全部読まれます(はじめにもどる)
  • 使いそうな言語
使いそう.ts
export const languages: { [k: string]: any } = { 
  sh: bash, 
  bash: bash, 
  coffee: coffeescript, 
  cpp: cpp, 
  cs: cs, 
  crystal: crystal, 
  css: css, 
  d: d, 
  dockerfile: dockerfile, 
  el: elixir, 
  elixir: elixir, 
  elm: elm, 
  er: erlang, 
  erlang: erlang, 
  glsl: glsl, 
  go: go, 
  hs: haskell, 
  java: java, 
  js: javascript, 
  javascript: javascript, 
  jsx: javascript, 
  json: json, 
  kt: kotlin, 
  kotlin: kotlin, 
  less: less, 
  lua: lua, 
  md: markdown, 
  markdown: markdown, 
  m: matlab, 
  matlab: matlab, 
  perl: perl, 
  php: php, 
  powershell: powershell, 
  python: python, 
  r: r, 
  rb: ruby, 
  ruby: ruby, 
  rs: rust, 
  rust: rust, 
  scala: scala, 
  scss: scss, 
  sql: sql, 
  stylus: stylus, 
  swift: swift, 
  tex: tex, 
  typescript: typescript, 
  ts: typescript, 
  tsx: javascript, 
  yml: yaml, 
  vue: vue, 
  xml: xml, 
}
  • これを実際に使いそうなところで languages[ext] してやると存在判定ができて便利です
  • typescript に ts, typescript 両方の名前で登録しているのは、下でライブラリ外の定義を使う時に subLanguage として正しい名前での参照を求めるからです

ライブラリ外の定義を使う
こんなときがあります
こういう時にこうしたくなってしまいますね
取り込みたい.ts
import hljs from "highlight.js" 
import vue from "highlightjs-vue" 
 
hljs.registerLanguage("vue", vue)
でも、こうすると…
  • highlight.js/lib
悲しいことがありました…になってしまう

じゃあどうすれば全部入りにならずに記法を登録できるか
正答例.ts
// @ts-ignore /lib/highlight には定義がありません 
import hljs from "highlight.js/lib/highlight" 
import vue from "highlightjs-vue" 
  
 hljs.registerLanguage("vue", vue)
まあ highlightjs-vue はパッケージ形態が特殊なのでこれじゃ取り込めないんですけどね
highlightjs-vue の場合の正答例.ts
// @ts-ignore 
 import hljs from "highlight.js/lib/highlight" 
// @ts-ignore 
import { definer as vue } from "highlightjs-vue/dist/highlightjs-vue.esm" 
 
hljs.registerLanguage("vue", vue)
ts-ignore ばかりのコードになってしまいました…
実際に採用しているコードでは languages に入れた後 map で登録しているので、registerLanguage はそちらで行っています
登録.ts
Object.entries(languages).map(([language, parser]) => { 
  hljs.registerLanguage(language, parser) 
})

結果
こうして無事バンドルサイズが小さくなりました

最終的なコードは これ
  • MIT ライセンスに従ってパクってOK!


著者の画像

ci7lus

@ci7lus

Caramelize - Made withCaramelizeand / Privacy