VScode 上で今開いているファイルを Vite でプレビューする拡張を作ったら便利
ほしかったので作ったシリーズ。
画像を見たらどういうものか伝わると思う。
自分で使っているが、ある程度の縛りがあるが、かなり快適。
これは何
現在開いているファイルを vite でビルドして、 vscode 内の Webview Panel としてプレビューする VSCode 拡張。
// props を持たないファイル名と同名のコンポーネント
export default function Sub() {
return <h1 className="flex">
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Click mee
</button>
</h1>
}
または __PREVIEW__
コンポーネントが export されていればそれを使う。
// props を持たないファイル名と同名のコンポーネント
export default function Sub(props: {name: string}) {
return <h1 className="flex">
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Click {props.name}
</button>
</h1>
}
// ここが render される
export const __PREVIEW__ = () => {
return <Sub name="dummy" />
}
他にも .svelte
や .html
にも対応してる。対応パターンは以下。
注意点として、 dynamic import が絡むとプレビューに失敗する。
React+Tailwind が動いているプロジェクトのサンプル
webview panel で作った利点として、 vscode は electron なので、 実は Chrome と同じ devtool を内蔵している。 Developper: Toggle Developper Tools
から devtool を開き vscode 内の要素としてインスペクトするこができる。
debugger もそのまま使える。
似たような HTML プレビューツールとして https://marketplace.visualstudio.com/items?itemName=antfu.browse-lite があるが、これは中で puppeteer を動かして画像を転送しているだけなので、解像度がボケボケになってしまう。vscode-vite も同じ問題を抱えている。
今回は webview panel で動かしているので解像度の問題はないが、 vscode が自動的に注入する CSS に影響を受けてしまう可能性はある。
導入
まだ vscode marketplace にアップロードしてないので、バイナリ(vsix)から入れる想定。
$ wget https://github.com/mizchi/vscode-vite-preview/raw/main/extensions/vite-preview/releases/vite-preview-0.0.1.vsix
## CLI から vscode にインストール
$ code --install-extension vite-preview-0.0.1.vsix
これで vscode のコマンドとして Vite Preview: Preview Current
(デフォルトでは ctrl-alt+r) が使えるようになる。これは現在開いているファイルを vite でビルドし、それを vscode 内の webview として表示する。
ただ、そのプロジェクトの vite の設定が済んでいる必要がある。
Create project
$ pnpm create vite@latest myapp
$ cd myapp
$ pnpm install
## Optional
$ pnpm add tailwindcss postcss autoprefixer -D
$ pnpm tailwind init
Optional: postcss and tailwind
tailwind.config.js と postcss.config.js からのファイル参照を絶対パス指定に修正する。(TODO: 直したい...)
const path = require("path");
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
path.join(__dirname, "src/**/*.{html,ts,tsx,svelte}"),
],
theme: {
extend: {},
},
plugins: [],
}
const path = require("path");
module.exports = {
plugins: {
autoprefixer: {},
tailwindcss: {
config: path.join(__dirname, "tailwind.config.js"),
},
}
}
Optional: preview.html
vite.config.ts
と同じディレクトリに preview.html
を置くと、それがプレビュー時に使われるエントリポイントになる。
例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body.vscode-light,
body.vscode-dark {
color: black;
background-color: white;
}
#preview-root {
padding: 10px;
box-sizing: border-box;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="preview-root"></div>
<script type="module" src="/src/pre.ts"></script>
<script type="module" src="/__PREVIEW__.tsx"></script>
</body>
</html>
この vscode 拡張は、現在開いているファイルのコンテキストを自動で類推して /__PREVIEW__.tsx
の中身を自動生成する。
どのように動いているか
https://github.com/richardtallent/vite-plugin-singlefile を元に作った専用のプラグインで、今の開いているファイルをマウントする単一HTMLとして吐き出し、それを vscode の webview の HTML として埋め込んで開いている。
作ってて困った点として、vite を vscode 拡張の権限で動かそうとすると、 sosukesuzuki も困っていた vm.Script 内では dynamic import が使えない問題に直面した。
なので、vscode-prettier と同じく worker_threads 内で vite を動かすようにするとなんとか動いた。
今後
もうちょっと自分で使い込んで、本当に必要なパターンを発見したら vscode marketplace に公開したい。
今現在、前提が多くてコードを読みながらでないと使える気がしない。postcss の実行パスの関係で部分的に絶対パスでないといけないとか、dynamic import 周りが動かないとか...
実のところ、これは単独で使うものというより chatgpt に生成させたコードをプレビューするために作っていたので、そのためのパーツになると思う。
Discussion