Preview First
.md / .html / 画像 / .pdf を開いたときに、そのタブを最初からプレビュー表示にする VS Code 拡張機能です。
できること
| 種類 |
拡張子 |
表示 |
| Markdown |
.md .markdown .mdown .mkd |
組み込み Markdown 拡張と同じレンダリング + コードのシンタックスハイライト。ツールバーなし |
| HTML |
.html .htm .xhtml |
iframe で実際にレンダリング。未保存の内容もそのまま反映。再読み込み / 外部ブラウザ ボタンあり |
| 画像 |
.png .jpg .jpeg .gif .webp .bmp .ico .avif .svg |
ズーム / パン / 等倍 / Fit、透過はチェッカー柄で表示 |
| PDF |
.pdf |
埋め込み表示(環境によっては外部アプリへの導線にフォールバック) |
プレビュー ⇔ ソースコードの切り替え
エディタのタイトルバー(「グループをロックする」などが出るバー)にアイコンが出ます。
| 今の表示 |
出るアイコン |
押すと |
| プレビュー |
$(file-code) ソースコード表示 |
通常のテキストエディタで開き直す |
| テキスト |
$(open-preview) プレビュー表示 |
プレビューで開き直す |
出し分けは activeCustomEditorId で判定しています。このコンテキストキーはカスタムエディタがアクティブなときだけ
viewType が入り、通常のテキストエディタでは空文字になるので、両方が同時に出ることはありません。
ソースコード表示のアイコンは中身がテキストの拡張子(.md .html .svg など)でのみ出します。画像や PDF では意味がないためです。
切り替え元のタブは自動で閉じます。ただし未保存の変更があるタブは閉じません(保存ダイアログで作業を止めないため)。
この挙動は previewFirst.switch.closeOriginalTab で無効にできます。
コマンドパレットからも Preview First: プレビュー表示 / Preview First: ソースコード表示 で呼べます。
設定
| キー |
既定値 |
内容 |
previewFirst.openIn |
newWindow |
newWindow = 別の VS Code ウィンドウに切り離す / beside = 同じウィンドウの右側のグループに移す / currentTab = 開いたタブをそのままプレビューにする |
previewFirst.toolbar.autoHide |
false |
true にするとツールバーが半透明になり、マウスを近づけたときだけはっきり表示 |
previewFirst.switch.closeOriginalTab |
true |
表示を切り替えたとき、切り替え元のタブを閉じる |
previewFirst.markdown.maxWidth |
980 |
本文の最大幅 (px)。0 で制限なし |
previewFirst.markdown.codeHighlight |
true |
コードブロックのシンタックスハイライト |
previewFirst.html.renderMode |
srcdoc |
srcdoc = エディタの内容を直接 iframe に流し込む / file = ディスク上のファイルを URL で読ませる |
previewFirst.html.autoReload |
onSave |
onSave / onChange / off(srcdoc では常に入力に追従します) |
切り離しのしくみ
プレビューがアクティブになった時点で、openIn に応じて VS Code のコマンドを呼びます。
openIn |
呼ぶコマンド |
newWindow |
workbench.action.moveEditorToNewWindow |
beside |
workbench.action.moveEditorToRightGroup |
これらはどちらもアクティブなエディタを対象にするため、実行前に「アクティブなタブが目的のプレビューであること」を確認しています。
確認しないと無関係のタブを飛ばしてしまいます。
また切り離した直後は webview が作り直されて処理が再入するので、同じ URI は数秒間だけ再切り離しを抑止しています。
別ウィンドウの位置(VS Code 本体へのパッチ)
VS Code は auxiliary window の初期位置をこう計算します。
x = Math.max(親ウィンドウの中央 - 1024/2, 0)
y = Math.max(親ウィンドウの中央 - 768/2, 0)
この Math.max(…, 0) は「負の座標は画面外」という前提ですが、Windows の仮想デスクトップでは
主モニターより上/左に置いたモニターの座標は負になります。この環境では
DISPLAY1 (主) X= 0 Y= 0 1536x960
DISPLAY2 X=1536 Y=-1413 2560x1440 ← ほぼ全域が負
なので、DISPLAY2 で最大化した VS Code から切り離すと max(-1413+720-384, 0) = 0 となり、
Y=0 = DISPLAY2 の下端 27px 手前にウィンドウが貼りつきます。
scripts/patch-vscode-auxwindow.js がこのクランプを外します。
node .\scripts\patch-vscode-auxwindow.js # 変更内容の表示のみ
node .\scripts\patch-vscode-auxwindow.js --apply # 適用
node .\scripts\patch-vscode-auxwindow.js --revert # 元に戻す
workbench.desktop.main.js は product.json のチェックサム対象なので、書き換えたあと
sha256 → base64 → 末尾 = 除去 で再計算して書き戻します(これをしないと「インストールが壊れています」の警告が出ます)。
VS Code を更新すると上書きされます。 scripts/install-autopatch.ps1 でタスクスケジューラに登録すると、
ログオン時と 30 分ごとに当たり直します(管理者権限不要、wscript 経由でウィンドウを出さずに実行)。
.\scripts\install-autopatch.ps1 # 登録
.\scripts\install-autopatch.ps1 -Remove # 解除
実行履歴は %LOCALAPPDATA%\preview-first\autopatch.log。
タスクはこのフォルダ内のスクリプトを絶対パスで参照するので、プロジェクトを移動したら登録し直してください。
難読化後の変数名(i r a)が変わると当たらなくなりますが、その場合はログに FAILED を残して停止します。
壊れた状態にはならず、位置の挙動がパッチ前に戻るだけです。
位置を指定する API は無い
VS Code のフローティングウィンドウ(auxiliary window)の位置は本体側で決まっており、拡張機能からは指定できません。
df53daabb1 のバンドルを読むと、呼び出し側が明示的な bounds を渡さないかぎり次の式になります。
x = 親ウィンドウの中央 - 1024/2
y = 親ウィンドウの中央 - 768/2 既定サイズ 1024x768(最小 400x270)
つまり常に親の VS Code ウィンドウの中央に開きます。bounds を渡している呼び出し口はエディタのドラッグ&ドロップだけで、
moveEditorToNewWindow は渡しません。位置を保存するしくみも無いので、一度動かしても次に開くとまた中央に戻ります。
window.newWindowDimensions はフル機能のウィンドウ用の設定で、フローティングウィンドウには効きません。
位置を安定させたい場合は openIn を beside か currentTab にしてください。
特定の拡張子だけ元に戻したいとき
この拡張機能は該当する拡張子の既定エディタを置き換えるので、検索結果や「定義へ移動」からの遷移もプレビューになります。
一部だけ従来どおりにしたい場合は、拡張機能を無効化せずに settings.json で上書きできます。
"workbench.editorAssociations": {
"*.html": "default", // HTML だけ従来のテキストエディタに戻す
"*.png": "imagePreview.previewEditor" // 画像だけ VS Code 組み込みのビューアに戻す
}
インストール先に注意(WSL で作業している場合)
この拡張機能はカスタムエディタを提供するので、ファイルのある側の拡張機能ホストで動く必要があります。
VS Code を WSL リモートウィンドウで使っている場合、それは WSL 側です。
Windows 側の %USERPROFILE%\.vscode\extensions にだけ入れても、WSL ウィンドウでは一切読み込まれません。
このため package.json に "extensionKind": ["workspace"] を明示しています。
現在の導入先は WSL (~/.vscode-server/extensions/local.preview-first-<version>) の 1 か所だけです。
開発
cd preview-first
npm install
コードを直したら、次の 1 コマンドでパッケージ化から WSL への再導入までやります。
.\scripts\deploy-wsl.ps1 # 別ディストロなら $env:PREVIEW_FIRST_DISTRO で指定
そのあと WSL ウィンドウで 開発者: ウィンドウの再読み込み(Ctrl+Shift+P)。
- F5 でも拡張機能開発ホストを起動できます(
.vscode/launch.json 設定済み)。ただし Windows 側で起動するので、WSL 上のファイルで試したい場合は上のデプロイ方式を使ってください。
scripts/deploy-wsl.ps1 は意図的に ASCII のみで書いています。Windows PowerShell 5.1 は BOM なしの .ps1 を ANSI として読むため、日本語を入れると保存のたびに壊れるからです。
やってはいけないこと
%USERPROFILE%\.vscode\extensions\preview-first にこのフォルダへのジャンクションを張る方法は使わないでください。
VS Code のアンインストール処理がジャンクションを辿ってソース本体を削除する危険があるうえ、
VS Code がリモートへ自動コピーする際に編集途中のスナップショットを掴むことがあります。
構成
extension.js activate / コマンド登録
lib/util.js 拡張子 → viewType の対応、CSP nonce、localResourceRoots など
lib/popout.js プレビューを別ウィンドウ / 右グループへ切り離す
lib/toggle.js プレビュー ⇔ ソースコードの開き直しと、元タブの後始末
lib/shell.js webview の HTML 骨格とツールバーの組み立て
lib/highlight.js markdown-it 出力のコードブロックを highlight.js に通す
providers/*.js 種類ごとの CustomEditorProvider
media/* webview 側の CSS / JS
既知の制限
- HTML プレビューはローカルサーバを立てないので、サーバが要る処理(相対パスへの
fetch、Live Reload など)は動きません。
- PDF の埋め込み表示は VS Code / Electron 側の PDF ビューアに依存します。表示できない場合は「OS の既定アプリで開く」が出ます。
- Markdown のレンダリングは組み込みの
markdown.api.render に依存しています。組み込みの Markdown 拡張を無効化していると素のテキスト表示になります。