paint-brush
Vite 用のカスタム プラグインの作成: 最も簡単なガイド@gmakarov
1,012 測定値
1,012 測定値

Vite 用のカスタム プラグインの作成: 最も簡単なガイド

German Makarov9m2024/01/21
Read on Terminal Reader

長すぎる; 読むには

開発サーバーの場合、最新のブラウザでサポートされているネイティブ ES モジュールを備えた esbuild を使用します。コードを 1 つのファイルにバンドルする必要がなく、高速な HRM (ホット モジュール交換) が可能です。 バンドルには、柔軟で大規模なエコシステムがあるため、rollup.js が使用されます。これにより、さまざまな出力形式で高度に最適化された本番バンドルを作成できます。 Vite のプラグイン インターフェイスは Rollup に基づいていますが、開発サーバーと連携するための追加のオプションとフックが含まれています。
featured image - Vite 用のカスタム プラグインの作成: 最も簡単なガイド
German Makarov HackerNoon profile picture
0-item

Viteは開発者の間でますます人気が高まっていますが、コミュニティは ( Webpackほど) 大きくないため、問題を解決するには独自のカスタム プラグインを作成する必要がある場合があります。この記事では、 Vite用のプラグインを作成する方法について説明し、私自身のプラグインについて詳しく説明します。

Vite でのプラグインの仕組み

プラグインを作成するには、Vite が開発サーバー (コマンドvite ) とバンドル (コマンドvite build ) に異なるビルド システムを使用することを理解しておくことが重要です。


開発サーバーの場合、最新のブラウザでサポートされているネイティブ ES モジュールを備えたesbuildを使用します。コードを 1 つのファイルにバンドルする必要がなく、高速な HRM (ホット モジュール交換) が可能です。


バンドルには、柔軟で大規模なエコシステムがあるため、 rollup.jsが使用されます。これにより、さまざまな出力形式で高度に最適化された本番バンドルを作成できます。


Vite のプラグイン インターフェイスは Rollup に基づいていますが、開発サーバーと連携するための追加のオプションとフックが付いています。

基本的なプラグインの作成

プラグインを作成するときは、それをvite.config.jsにインライン化できます。新しいパッケージを作成する必要はありません。プラグインがプロジェクトで役立つことがわかったら、それをコミュニティと共有し、Vite エコシステムに貢献することを検討してください。


また、rollup.js にはより大きなコミュニティとエコシステムがあるため、rollup.js 用のプラグインを作成することを検討すると、Vite でも同様に機能します。したがって、プラグイン機能がバンドルに対してのみ機能する場合は、Vite の代わりに rollup.js プラグインを使用でき、ユーザーは Vite プロジェクトでロールアップ プラグインを問題なく使用できます。


rollup 用のプラグインを作成すると、rollup.js のみを使用するより多くのユーザーをカバーできます。プラグインが開発サーバーに影響を与える場合は、Vite プラグインを使用します。


vite.config.tsで直接プラグインの作成を開始しましょう。


 // vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin { return { name: 'my-plugin', configResolved(config) { console.log(config); }, }; } export default defineConfig({ plugins: [ myPlugin(), ], });


この例では、開発サーバーとバンドルの両方の段階でコンソールで Vite 設定が解決されるとすぐに Vite 設定を出力するmyPluginというプラグインを作成しました。 dev サーバー モードでのみ構成を出力したい場合は、バンドルにapply: 'serve'apply: 'build'を追加する必要があります。


 // vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin { return { name: 'my-plugin', apply: 'serve', configResolved(config) { console.log(config); }, }; } export default defineConfig({ plugins: [ myPlugin(), ], });


また、プラグインの配列を返すこともできます。これは、開発サーバーとバンドルの機能を分離するのに役立ちます。


 // vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin[] { return [ { name: 'my-plugin:serve', apply: 'serve', configResolved(config) { console.log('dev server:', config); }, }, { name: 'my-plugin:build', apply: 'build', configResolved(config) { console.log('bundle:', config); }, }, ]; } export default defineConfig({ plugins: [ myPlugin(), ], });


ほぼそれだけです。 Vite 設定に小さなプラグインを簡単に追加できます。プラグインが大きくなりすぎる場合は、別のファイルに移動するか、パッケージを作成することを好みます。


もっと複雑なものが必要な場合は、Vite のドキュメントで調べることができる便利なフックがたくさんあります。ただし、例として、以下に私自身のプラグインを分解してみましょう。

実際のプラグインを分解する

そこで、アイコン ファイルに基づいて SVG スプライトを作成するプラグインvite-plugin-svg-spritemapを用意しました。

目標は、 src/iconsフォルダー内のすべてのアイコン.svg取得し、その内容を SVG スプライトと呼ばれる単一の.svgファイルに収集することです。バンドル段階から始めましょう。


 import { Plugin, ResolvedConfig } from 'vite'; import path from 'path'; import fs from 'fs-extra'; function myPlugin(): Plugin { let config: ResolvedConfig; return { name: 'my-plugin:build', apply: 'build', async configResolved(_config) { config = _config; }, writeBundle() { const sprite = getSpriteContent({ pattern: 'src/icons/*.svg' }); const filePath = path.resolve(config.root, config.build.outDir, 'sprite.svg'); fs.ensureFileSync(filePath); fs.writeFileSync(filePath, sprite); }, }; }


  1. フックconfigResolved使用すると、次のフックで使用することが解決されたときに構成を取得できます。


  2. バンドル プロセスの完了後にwriteBundleフックが呼び出されます。ここで、 sprite.svgファイルを作成します。


  3. getSpriteContent関数は、 src/icons/*.svgパターンに基づいて、準備された SVG スプライトの文字列を返します。これについてはこれ以上深くは説明しません。 SVG スプライト生成のプロセス全体を説明した私の他の記事をチェックしてください。


  4. 次に、 path.resolve()で SVG スプライト コンテンツを配置するsprite.svgへの絶対パスを作成し、 fs.ensureFileSyncでファイルが存在することを確認 (または作成) し、そこに SVG スプライト コンテンツを書き込みます。 。


ここで、最も興味深い部分である開発サーバーの段階について説明します。ここではwriteBundle使用できず、開発サーバーの実行中はファイルをホストできないため、サーバーミドルウェアを使用してsprite.svgへのリクエストをキャッチする必要があります。


 import { Plugin, ResolvedConfig } from 'vite'; function myPlugin(): Plugin { let config: ResolvedConfig; return { name: `my-plugin:serve`, apply: 'serve', async configResolved(_config) { config = _config; }, configureServer(server) { // (1) return () => { server.middlewares.use(async (req, res, next) => { // (2) if (req.url !== '/sprite.svg') { return next(); // (3) } const sprite = getSpriteContent({ pattern, prefix, svgo, currentColor }); res.writeHead(200, { // (4) 'Content-Type': 'image/svg+xml, charset=utf-8', 'Cache-Control': 'no-cache', }); res.end(sprite); }); }; }, }; }


  1. configureServerは開発サーバーを構成するためのフックです。 Vite の内部ミドルウェアがインストールされる前にトリガーされます。私の場合、内部ミドルウェアの後にカスタムミドルウェアを追加する必要があるため、関数を返します。


  2. 開発サーバーへのすべてのリクエストをキャッチするカスタム ミドルウェアを追加するには、 server.middlewares.use()を使用します。ファイルの動作をエミュレートできるように、URL [localhost:3000/sprite.svg](http://localhost:3000/sprite.svg)リクエストを検出するために必要です。


  3. リクエスト URL が/sprite.svgではない場合 - 次のミドルウェアにスキップします (つまり、チェーン内の次のハンドラーに制御を渡します)。


  4. ファイルのコンテンツを準備するには、 getSpriteContentの結果を変数spriteに入れ、設定されたヘッダー (コンテンツ タイプと 200 HTTP ステータス) を含む応答として送信します。


その結果、ファイルの動作をシミュレートしました。


ただし、 src/icons内のファイルが変更、削除、または追加された場合は、サーバーを再起動して、 getSpriteContentを介して新しいスプライト コンテンツを生成する必要があります。このために、ファイル監視ライブラリ - chokidarを使用します。 chokidar ハンドラーをコードに追加しましょう。


 import { Plugin, ResolvedConfig } from 'vite'; import chokidar from 'chokidar'; function myPlugin(): Plugin { let config: ResolvedConfig; let watcher: chokidar.FSWatcher; // Defined variable for chokidar instance. return { name: `my-plugin:serve`, apply: 'serve', async configResolved(_config) { config = _config; }, configureServer(server) { function reloadPage() { // Function that sends a signal to reload the server. server.ws.send({ type: 'full-reload', path: '*' }); } watcher = chokidar .watch('src/icons/*.svg', { // Watch src/icons/*.svg cwd: config.root, // Define project root path ignoreInitial: true, // Don't trigger chokidar on instantiation. }) .on('add', reloadPage) // Add listeners to add, modify, delete. .on('change', reloadPage) .on('unlink', reloadPage); return () => { server.middlewares.use(async (req, res, next) => { if (req.url !== '/sprite.svg') { return next(); } const sprite = getSpriteContent({ pattern, prefix, svgo, currentColor }); res.writeHead(200, { 'Content-Type': 'image/svg+xml, charset=utf-8', 'Cache-Control': 'no-cache', }); res.end(sprite); }); }; }, }; }


ご覧のとおり、プラグイン作成の API はそれほど複雑ではありません。 Vite または Rollup から自分のタスクに合ったフックを見つけるだけです。この例では、Rollup.js のwriteBundle (前述したように、バンドルの生成に使用されます) を使用し、Rollup.js にはネイティブの開発サーバー サポートがないため、Vite のconfigureServer使用しています。


writeBundleの場合は非常に単純で、SVG スプライトのコンテンツを取得してファイルに入れました。開発サーバーの場合、なぜ同じことができないのか混乱しました。他の作者のプラグインも調べてみましたが、どれもほぼ同じことを行います。


そこで、 configureServerを使用し、 server引数を介して、 sprite.svgリクエストをインターセプトすることで開発サーバーへのすべてのリクエストをトリガーするミドルウェアを追加します。

Vite フックの使用

前に述べたように、より便利なプラグインを作成するには、フックを調べる必要があります。それらについてはドキュメントで詳しく説明されています。

https://vitejs.dev/guide/api-plugin#universal-hooks

https://vitejs.dev/guide/api-plugin#vite-specific-hooks

プラグインに名前を付ける方法

命名に関しては、Vite にはプラグインに関するいくつかの規則があるため、終了する前に確認しておくことをお勧めします。いくつかの重要なポイントを次に示します。


  • Vite プラグインには、 vite-plugin-プレフィックスが付いた一意の名前が必要です。


  • vite-pluginキーワードを package.json に含めます。


  • プラグインのドキュメントに、Vite 専用プラグインである理由を説明するセクションを含めます (Vite 固有のプラグイン フックを使用するなど)。


  • プラグインが特定のフレームワークでのみ動作する場合は、その名前をプレフィックスの一部として含めます ( vite-plugin-vue-vite-plugin-react-vite-plugin-svelte- )。

プラグインを公開して共有する方法

プラグインを NPM で公開することに決めた場合は、知識と専門知識を共有することが IT コミュニティの基本原則であり、集団的な成長を促進するため、これをお勧めします。パッケージを公開および保守する方法については、私のガイドを参照してください → NPM パッケージを作成する最も簡単な方法


また、プラグインを vite のコミュニティ リスト ( awesome-vite)に送信することを強くお勧めします。そこでは多くの人が最適なプラグインを探しており、Vite エコシステムに貢献する絶好の機会となるでしょう。プラグインを送信するプロセスは簡単です。条件を満たしていることを確認してプル リクエストを作成するだけです。用語のリストはここでご覧いただけます。


全体として、(ロールアップではなく) Vite に特化し、オープンソースであり、適切なドキュメントが必要です。プラグインを頑張ってください!