--- parent: ../Tips title: SyntaxHighlighter の非同期読み込み date: 2021-08-09 tags: JavaScript, 非同期処理 --- 本稿では, コードをハイライトするライブラリ//SyntaxHighlighter//の//非同期読み込み方法//について説明します. === # SyntaxHighlighter について SyntaxHighlighter は, Webサイト上でコードをハイライトするためのライブラリです. * ["syntaxhighlighter"](https://github.com/syntaxhighlighter/syntaxhighlighter). GitHub. Accessed at 2021.08.09. SyntaxHighlighterは, バージョン`2.1.364`が2009年にリリースされていることから, 古くからあるライブラリです. # 環境 本稿で対象にしている SyntaxHighlighter のバージョンは, `3.0.83`です. # 従来の読み込み方法 従来の読み込み方法は以下の通りでした. ```html <head> <script type="text/javascript" src="syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="syntaxhighlighter/styles/shCoreDefault.css"> </head> <body> ... <script> SyntaxHighlighter.autoloader( 'applescript syntaxhighlighter/scripts/shBrushAppleScript.js', 'actionscript3 as3 syntaxhighlighter/scripts/shBrushAS3.js' , 'bash shell syntaxhighlighter/scripts/shBrushBash.js' , 'coldfusion cf syntaxhighlighter/scripts/shBrushColdFusion.js' , 'cpp c syntaxhighlighter/scripts/shBrushCpp.js' , 'c# c-sharp csharp syntaxhighlighter/scripts/shBrushCSharp.js' , 'css syntaxhighlighter/scripts/shBrushCss.js' , 'delphi pascal syntaxhighlighter/scripts/shBrushDelphi.js' , 'diff patch pas syntaxhighlighter/scripts/shBrushDiff.js' , 'erl erlang syntaxhighlighter/scripts/shBrushErlang.js' , 'groovy syntaxhighlighter/scripts/shBrushGroovy.js' , 'java syntaxhighlighter/scripts/shBrushJava.js' , 'jfx javafx syntaxhighlighter/scripts/shBrushJavaFX.js' , 'js jscript javascript syntaxhighlighter/scripts/shBrushJScript.js' , 'perl pl syntaxhighlighter/scripts/shBrushPerl.js' , 'php syntaxhighlighter/scripts/shBrushPhp.js' , 'text plain syntaxhighlighter/scripts/shBrushPlain.js' , 'ps powershell syntaxhighlighter/scripts/shBrushPowerShell.js' , 'py python syntaxhighlighter/scripts/shBrushPython.js' , 'ruby rails ror rb syntaxhighlighter/scripts/shBrushRuby.js' , 'sass scss syntaxhighlighter/scripts/shBrushSass.js' , 'scala syntaxhighlighter/scripts/shBrushScala.js' , 'sql syntaxhighlighter/scripts/shBrushSql.js' , 'vb vbnet syntaxhighlighter/scripts/shBrushVb.js' , 'xml xhtml xslt html syntaxhighlighter/scripts/shBrushXml.js' ); SyntaxHighlighter.all(); </script> </body> ``` スクリプト`shCore.js`, `shAutoloader.js`, スタイル`shCoreDefault.css`を順に読み込み, ハイライトの定義ファイルを自動で読み込む機能を設定しています. この方法には問題があり, 上の処理の間Webページのレンダリングが妨げられます. ブラウザはデフォルトで, HTMLの解析中にスクリプトがあると, HTMLの解析を一時停止し, スクリプトの読み込みと実行を行います^[BlockingJS-googledev]. 外部スクリプトの場合はリソースがダウンロードされるのを待つ必要もありますが, その際リソースのダウンロードによってネットワーク ラウンド トリップが発生し, ページが最初に表示されるまでの時間が長くなる可能性があります^[BlockingJS-googledev]. # 非同期読み込み方法 SyntaxHighlighter を非同期に読み込む方法を説明します. この方法は, MathJaxの非同期読み込み方法に基づいています. * ["Configuring and Loading MathJax"](http://docs.mathjax.org/en/latest/web/configuration.html#configuring-and-loading-in-one-script). MathJax. accessed at 2021.08.10. まず, 以下のファイルを用意します. `load-syntaxhighlighter.js`: ```js ;(function () { const sh = window.SyntaxHighlighter if (!sh || !sh.src) { return } const { src } = sh const process = async () => { const waitDOMLoaded = () => new Promise(resolve => { document.readyState !== "loading" ? resolve() : document.addEventListener("DOMContentLoaded", resolve) }) const loadScript = src => { return new Promise((resolve, reject) => { const script = document.createElement("script") script.src = src script.async = true script.onload = resolve script.onerror = reject document.head.appendChild(script) }) } const loadStyle = src => { return new Promise((resolve, reject) => { const style = document.createElement("link") style.rel = "preload" style.type = "text/css" style.as = "style" style.href = src style.onload = () => { style.rel = "stylesheet" resolve() } style.onerror = reject document.head.appendChild(style) }) } try { loadStyle(`${src}/styles/shCoreDefault.css`) await loadScript(`${src}/scripts/shCore.js`) await loadScript(`${src}/scripts/shAutoloader.js`) await waitDOMLoaded() SyntaxHighlighter.autoloader( `applescript ${src}/scripts/shBrushAppleScript.js`, `actionscript3 as3 ${src}/scripts/shBrushAS3.js`, `bash shell ${src}/scripts/shBrushBash.js`, `coldfusion cf ${src}/scripts/shBrushColdFusion.js`, `cpp c ${src}/scripts/shBrushCpp.js`, `c# c-sharp csharp ${src}/scripts/shBrushCSharp.js`, `css ${src}/scripts/shBrushCss.js`, `delphi pascal ${src}/scripts/shBrushDelphi.js`, `diff patch pas ${src}/scripts/shBrushDiff.js`, `erl erlang ${src}/scripts/shBrushErlang.js`, `groovy ${src}/scripts/shBrushGroovy.js`, `java ${src}/scripts/shBrushJava.js`, `jfx javafx ${src}/scripts/shBrushJavaFX.js`, `js jscript javascript ${src}/scripts/shBrushJScript.js`, `perl pl ${src}/scripts/shBrushPerl.js`, `php ${src}/scripts/shBrushPhp.js`, `text plain ${src}/scripts/shBrushPlain.js`, `ps powershell ${src}/scripts/shBrushPowerShell.js`, `py python ${src}/scripts/shBrushPython.js`, `ruby rails ror rb ${src}/scripts/shBrushRuby.js`, `sass scss ${src}/scripts/shBrushSass.js`, `scala ${src}/scripts/shBrushScala.js`, `sql ${src}/scripts/shBrushSql.js`, `vb vbnet ${src}/scripts/shBrushVb.js`, `xml xhtml xslt html ${src}/scripts/shBrushXml.js` ) SyntaxHighlighter.all() } catch (error) { console.error(error) } } process() })() ``` `shCoreDefault.css`を非同期に読み込みながら, `shCore.js`, `shAutoloader.js`を順番に読み込み, DOMが読み込まれるのを待ってから, `autoloader`を開始しています. 次に, `<head>`タグ内で, SyntaxHighlighterのディレクトリ場所を設定をした後, 上のファイルを非同期で読み込みます. ```html <head> <script> SyntaxHighlighter = { src: "path/to/syntaxhighlighter" } </script> <script src="path/to/load-syntaxhighlighter.js" async></script> </head> ``` 以上で, レンダリングを妨げずにコードがハイライトされます. # 今後 本稿で, SyntaxHighlighter の非同期読み込みについて説明しましたが, 今後 SyntaxHighlighter は使われなくなると思います. 2021-08-09現在, SyntaxHighlighter の[GitHubページ](https://github.com/syntaxhighlighter/syntaxhighlighter)を見ると, 最終更新日が2017年8月あたりで止まっています. また, 公式サイトであった`alexgorbatchev.com/SyntaxHighlighter`のリンクが切れています. SyntaxHighlighterから乗り換える先となるライブラリを以下に挙げておきます. * ["highlight.js"](https://highlightjs.org/). accessed at 2021-08-09 * ["Prism"](https://prismjs.com/). accessed at 2021-08-09 # 参考文献 [BlockingJS-googledev]: ["レンダリングを妨げる JavaScript を削除する"](https://developers.google.com/speed/docs/insights/BlockingJS?hl=ja). Google Developers. accessed at 2021-08-09.