VSCode Web Extension for Zenn Preview がほしい
TL; DR
-
markdown-it-zenn
みたいな感じでzenn-markdown-html
周りの処理を Plugin として抜き出しましょう(最優先タスク) -
markdown.previewScripts
にzenn-embed-elements
を使うのがよくわからん(力不足) - CSS分離はできたので,
package.json
の自動更新&拡張機能の自動ビルド手続きがほしい
@catnose99 氏~~~ markdown-it-zenn
プラグインだけでもシュシュっとつくっておくれよ~~2時間もあればできる気がするので~~
経緯
以下の Feature Request を投げたが,調べているうちに自分でも実装できそうな(そのほうが早そうな)気がしたので以下,検討していく
Web Extensions
github.dev
では,ブラウザ上でリポジトリ内のコードを編集できるが,拡張機能に関しては大きく制限がある(有料版の Codespaces は別らしい? が,ここでは誰でも使えることを想定する)
ブラウザ上でも使える拡張機能を特に "Web Extensions" と呼ぶらしい.
通常の拡張機能と同様に package.json
で構成する一方で,main
エントリーポイントは機能せず,代わりに browser
を使えということになっている[1].
拡張機能をつくるときに両方のエントリポイントを指定することはできるが,Web Extensions を使いたいときに browser
が指定されていない場合,github.dev 側でインストールできないように制限されるらしい.
制限
The web extension's main file is defined by the
browser
property. The script runs in the web extension host in a Browser WebWorker environment. It is restricted by the browser worker sandbox and has limitations compared to normal extensions running in a Node.js runtime.
ここをみると,どのような制限があるかわかる.まぁ,サーバ側ランタイムである Node.js の記法は使えないから気をつけてね,ってことらしい.JavaScript まったくわからん
つまりは,ブラウザ上で実行できる JS スクリプトだけがつかえるよ!って理解でよさそう.
準備
npm install -g yo generator-code
してから yo code
ってコマンドを打てばいい感じに制限のギャップを吸収する Configuration (via webpack) を準備してくれるらしい.
example
npm yo code
# ? What type of extension do you want to create? New Web Extension (TypeScript)
# ? What's the name of your extension? vscode-zenn-preview
### Press <Enter> to choose default for all options below ###
# ? What's the identifier of your extension? helloworld
# ? What's the description of your extension? LEAVE BLANK
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? No
# ? Which package manager to use? npm
# ? Do you want to open the new folder with Visual Studio Code? Open with `code`
CSS の適用
yo code
で作成したプロジェクトルートには,package.json
が生成されている.これに contributes
プロパティが追加されているのを確認し,さらに markdown.previewStyles
を追記する.このプロパティの値は配列になっていて,適用したい順番で必要な CSS ファイルへの相対パスを並べる.以下の例では,ルートディレクトリに style.css
というファイルを置いて参照している.
{
"contributes": {
"markdown.previewStyles": [
"./style.css"
]
}
}
先行事例
Markdown Extension の先行事例として,Markdown Preview Github Styling というものが紹介されていた.VSCode のプレビューに GFM Style を適用する拡張機能である.とりあえずはこれのソースを見て真似てみよう.
markdown-it
Plugin
The VS Code Markdown preview supports the CommonMark specification[1]. Extensions can add support for additional Markdown syntax by contributing a markdown-it plugin.
VSCode は markdown-it
に対応しているらしい.これも有効にするためには, package.json
の Contributes
プロパティに markdown.markdownItPlugins
を追加してやればよい.
{
"contributes": {
"markdown.markdownItPlugins": true
}
}
Plugin の書き方
拡張機能として extendMarkdownIt(md)
という関数を書き,activate
してやればいいそうだ.browser
のエントリポイントとして指定したファイルに,以下のような記述を書けば良い.
import type MarkdownIt from 'markdown-it';
import * as emoji from 'markdown-it-emoji';
export function activate() {
return {
extendMarkdownIt(md: MarkdownIt) {
return md.use(emoji);
}
};
}
上記コードは markdown-emoji
内の src/index.ts
中に書かれたものである.なるほど案外簡単に作れそうだし,md.use(somePlugins)
っていう書き方は個人的にかな~~り最近みた.なんと都合のいいことに,zenn-markdown-html
でも同様の書き方だった.これはイケる(確信)
Preview 内部で実行するスクリプト
zenn-editor
が提供する機能のうち,zenn-embed-elements
だけはどうすればいいのかわからない.useEffect()
を使って Dynamic import しているが,拡張機能は React 製ではないのでう~ん……
などと考えているうちに,要するに後から非同期的にスクリプトが動くようにすればいいんだろ?ということに気づいた.
というか,ご丁寧にも既に公式ドキュメントに書かれていた(まだ試せていないが多分これでおk).
For advanced functionality, extensions may contribute scripts that are executed inside of the Markdown preview. Contributed scripts are loaded asynchronously and reloaded on every content change.
{
"contributes": {
"markdown.previewScripts": [
"./main.js"
]
}
}
非同期に実行するだけでもありがたいのに,ファイルに変更があるたびにリロードしてくれてもう最高じゃん?
現時点(2022-01-09)での問題点
package.json
に Contributes
プロパティを追加し,そこへ以下の三項目を追記すればいいことはわかった.
markdown.previewStyles
markdown.markdownItPlugins
markdown.previewScripts
2については .true
にして有効化するだけで解決するが,1と3については未だ問題がある
どちらも,パッケージではなく「生のファイルデータ」として用意せねばならない.初期状態として設置するのは簡単だが,外部スクリプトを参照している以上,それらの更新に遅れてしまう事態は避けたい.
追記:2022/01/09 18:30
逆に1についてはバンドル側でなんとかできてしまった.2も既にできている部分的なものを抽出してやればいいだけっぽい.真の問題は3で,JS のそれなりの経験者じゃないとわからない可能性がある.Node ランタイムじゃないのムズすぎる(は?)
理想的には,zenn-editor
のパッケージ として一括管理してもらうのが一番よい.だが,
lerna を使ったモノレポ管理をしています [1]
とあるように,lerna
の中に組み込んだコミットを作ってPRを作る必要がありそうだ.モノレポ管理も同時並行で学ぶのはキツイわね……(情弱)
markdown.previewStyles
の問題
browser
のエントリポイントとなるファイル src/extension.ts
において zenn-content-css
のインポートを宣言しておき,webpack でコンパイルする際に css-loader
[1] を活用して分離させればよい [2] ことがわかった.一先ず,「生のファイルデータとして用意する」という問題の方は解決した.
更新云々については,package.json
側の問題にスコープが移ったことになる.何らかの手段で監視し,自動的にパッケージ更新&ビルド&リリースということになるだろうか.この辺の本番環境的な動きは未だ経験浅く想像がおぼつかない…
markdown.markdownItPlugins
の問題
イケる!と書いたが,zenn-markdown-html
は markdown-it
の plugin ではなく,Markdown 形式のテキストを HTML 形式のテキストに変えているだけであった.[1]
これでは流用できない!他のプラグイン記述部分は export されておらず,外部からは参照できない……
新たなタスクとして,「markdown-it-zenn
をつくる」が追加された瞬間である.仕方がねぇな~~猫の鼻がよ~~~~~~😹
markdown-it
の GitHub ページには,プラグイン作者へのアドバイスが載せられていた.これを見つつ,既存のプラグインの組み合わせで新たにプラグインを作る感じで頑張る のがいいと思う,[2] がんばるぞい!!
-
当該部分の
markdownHtml(markdown)
↩︎ -
というかこれはソースコード見て移せばいいだけなのであった(やるだけ定期) ↩︎
markdown.previewScripts
の問題
まんまこのワードで調べてみても,全然何も出てこない.と思ったらこの記法は v1.63 からの新しいものである模様 [1].
追記:2022/01/10
GitHub 全体で検索かけてみた結果を見ると参考になるかもしれない……あとで確認のこと.
唯一まともにまとまっているのが公式っぽい Extension であるところの Markdown Preview Mermaid Support 内部にあるソースコードしかないという事実……つらいねぇ😢
エントリポイントになっている page.js
を観察してみると,よくわかったようなわからんような複雑な気持ちになってきてしまった.果たしてこのような形に zenn-embed-elements
を適用させることができるのか?というかもしかして Typescript じゃなくて生 JS 書かなきゃあイケない機運かも??なんにせよ今のままでは見識と時間が足りない.一旦後回しとする.
-
Extension Guides にもロクな情報がなくて草ァ ↩︎
経過報告:2022/01/14
そのまま流用するだけだったのでおそらくプラグイン自体は書けたはずだが,拡張機能としてVSCodeに仕込むのが全然わからん!となっている
そもそも読み込まれているのか?とかどういうときに有効化しているのか?とか全然何もわかってない…
というかもうzenn-cli起動すればいいかな…の気持ちが強くなりつつある(こんなにも苦労しているのに実現できないのは俺が悪いんじゃなくて複雑怪奇になってしまったVSCode側に問題があるんやないか?という話)
【朗報】公式で対応してくれた模様【最高体験が発生】
cf.
というわけで、この scrap は閉じます
10ヶ月もしないうちに色々変わってすごいなぁ……