unpluginでVite等におけるMSWの記述をスマートにする
本記事では unplugin というツールを利用し、APIのモックに便利な MSW の処理をスマートに記述する方法をご紹介します。
unpluginとは
unplugin
はビルド用の統一プラグインシステムであり、Vite・Rollup・Webpack・esbuild・Rspackといったフロントエンドの主要ビルドツールにおけるプラグインを作成することが可能です。(Rspack のみ experimental )
基本はRollup plugin APIをベースに記述しますが、 Vite 独自の機能などフレームワーク特有のロジックも記述可能です。例えば Vite におけるサーバ設定を変更するconfigureServer
を記述する場合は以下の様に記述します。
export const unplugin = createUnplugin((options: UserOptions, meta) => {
return {
// unpluginの共通処理
name: 'unplugin-prefixed-name',
transformInclude(id) { /* ... */ },
transform(code) { /* ... */ },
// フレームワーク特有の処理
vite: {
// Vite plugin
configureServer(server) {
// ここにサーバ設定を記述
}
}
}
})
つまりunpluginは vite の plugin などを汎用的かつ、様々な環境で利用できるようにするためのプラグイン作成ツールとなります。
MSWにおけるworkerの記述
例として、Vite 上で MSW を利用しブラウザ上(worker)のリクエストをモックするには以下の様な記述となります。(リクエストハンドラの記述方法は省略)
if (import.meta.env.DEV) {
(async() => {
const { worker } = await import('./mocks/browser')
worker.start()
})()
}
上記の処理では、開発時のみ動的 import で worker 処理を実行しています。静的に import をしてしまうとビルド時にバンドルされてしまうためこのような記述になりますが、やや冗長な印象です。 MSW は開発時以外でも Storybook やテストなどでも利用可能なため、環境変数などによる利用制御をもう少しスマートにしたいところです。
unpluginにおける記述
unplugin を用いて実装した結果がこちらになります。
import { worker } from 'unplugin-msw/worker'
worker?.start()
非常にシンプルになりました。worker
がundefined
を含む形になっているのは本番環境など利用しない状態で動作させないようにしているためです。実行されない場合はバンドルもされません。
Vite における設定は以下の様になります。ここで利用可否などを制御可能です。
// vite.config.ts
import MswPlugin from 'unplugin-msw/vite'
export default defineConfig({
plugins: [
MswPlugin({
mockPath: 'mock/handler', // リクエストハンドラのパス
workerEnabled: process.env.NODE_ENV === 'development', // workerの稼働制御
})
],
})
動作の仕組み
unplugin(rollup)の処理はビルド時に下図のようになります。(一部抜粋)
(※https://rollupjs.org/plugin-development/#plugins-overview より引用)
定義したID(resolveId
)が読み込まれた際にload
関数に記載された内容に従って処理を実行します。今回の例では以下のような処理になっていました。
import { worker } from 'unplugin-msw/worker'
unplugin-msw/worker
というresolveId
で定義したパスを解決すると unplugin はビルド時に
import { setupWorker } from 'msw'
import handler from '[指定されたパス]'
export const worker = setupWorker(...handler)
として解決することが可能です。これにより記述をシンプルにすることが出来ました。
本番時などはunplugin-msw/worker
を読み込んだ際に
export const worker = undefined
として解決されるため、MSW が import されずに実行されないという仕組みです。
試してみたい場合
npm でご利用いただけます。
npm i -D unplugin-msw
TypeScript を利用している場合はtsconfig.json
に以下をご記載ください。
{
"compilerOptions": {
"types": [
"unplugin-msw/globals"
]
}
}
ソースコードはこちらです。unplugin の記述方法などはこちらをご参照ください。サーバ用のMSWも利用可能です。
参考
Discussion