Migration
ここでは minista v3 から v4 への移行方法について説明します。
Table of Contents
Overview
v4 は設計が大きく変わっています。v3 まではオールインワンのライブラリでしたが、v4 からは本体が Vite のラッパーとして動作し、SSG や画像最適化などの機能はすべて Vite プラグインとして提供されます。
Changes
- すべての機能を Vite プラグイン化
- コンフィグを Vite 公式に変更
- インポートパスを細分化して変更
- Svgr を Svg コンポーネントに変更
- Icon を Sprite に変更
- Partial Hydration を Island に変更
- Delivery(納品リスト)を廃止
Agent Mode
まず、エディタのエージェントモードを使用して効率的に移行する方法を検討してください。GitHub 上にこのページの Markdown データがありますので、エージェントへの指示としてコピーして使用(またはダウンロードして指示に添付)し、その上でうまくいかなかった箇所を修正してみてください。
Packages
最初にパッケージを更新します。v4 では vite も peerDependencies になりました。
npm install --save-dev minista@latest vite react react-domTypeScript を使用している場合は @types/react @types/react-dom も更新。
npm install --save-dev @types/react @types/react-domPartial Hydration や Search の移行には @vitejs/plugin-react が必要です。
npm install --save-dev @vitejs/plugin-reactConfig
次にコンフィグファイルを更新します。v4 は minista 独自のコンフィグを廃止し Vite 公式と同一になりました。ファイルは minista.config.{ts,js} または vite.config.{ts,js} のどちらでも動作します。
基本設定は Vite 公式に沿って移行。minista 独自の機能は Vite プラグイン化されているため、必要なプラグインをインポートして plugins 配列に追加します。
注意点として、v4 は Vite の SSR ビルドと通常ビルドを連続で行うことを意識してください。ビルド用に設定した内容が SSR ビルドを壊してしまう可能性があります。これは設定を SSR ビルド用・通常ビルド用に切り分けることで解消できます。
import { defineConfig } from "minista"
export default defineConfig({
out: "dist",
assets: {
images: {},
},
})import { defineConfig, pluginSsg, pluginImage } from "minista"
export default defineConfig(({ command, isSsrBuild }) => {
const isDev = command === "serve"
const isSsr = command === "build" && isSsrBuild
const isBuild = command === "build" && !isSsrBuild
return {
plugins: [pluginSsg()],
build: { outDir: isBuild ? "dist" : undefined },
}
})root
※新旧ともに Vite と同じなので変更なし
base
※新旧ともに Vite と同じなので変更なし
public
Vite の publicDir に変更してください。
export default { public: "public" }export default { publicDir: "public" }out
Vite の build.outDir に変更してください。
export default { out: "dist" }export default { build: { outDir: "dist" } }assets.outDir
Vite の build.assetsDir に変更してください。
export default { assets: { outDir: "assets" } }export default { build: { assetsDir: "assets" } }assets.outName
Vite の build.rollupOptions でそれぞれ設定する必要があります。
- CSS・画像・フォント:
build.rollupOptions.output.assetFileNames - JavaScript(chunk):
build.rollupOptions.output.chunkFileNames - JavaScript(entry):
build.rollupOptions.output.entryFileNames
※これらを設定した場合 build.assetsDir は無視されます。
export default { assets: { outName: "pjt-[name]" } }export default {
build: {
rollupOptions: {
output: {
assetFileNames: "assets/pjt-[name][extname]",
chunkFileNames: "assets/pjt-[name].js",
entryFileNames: "assets/pjt-[name].js",
},
},
},
}assets.images
outDir, outName
Vite の build.rollupOptions で設定する必要があります。後述の Separate asset directories を参照して設定してください。
remoteName
minista のプラグイン pluginImage のオプションに変更してください。v3 では固定だった [index] プレースホルダーの位置を指定できます。
export default { assets: { images: { remoteName: "remote" } } }import { pluginImage } from "minista"
export default {
plugins: [pluginImage({ optimize: { remoteName: "remote-[index]" } })],
}optimize
minista のプラグイン pluginImage のオプションに変更してください。v3 では固定だった出力画像の名前([name]-[width]x[height])を変更できます。
export default { assets: { images: { optimize: { layout: "constrained" } } } }import { pluginImage } from "minista"
export default {
plugins: [
pluginImage({
optimize: { name: "[name]-[width]x[height]", layout: "constrained" },
}),
],
}assets.svgr
svgrOptions
SVGR が提供するオプションの中で svgoConfig のみ pluginSvg のオプションとしてそのまま移行できます。その他のオプションはサポートされていないため、後述の Svgr 移行を参照して対応してください。
export default {
assets: { svgr: { svgrOptions: { svgoConfig: { plugins: [] } } } },
}import { pluginSvg } from "minista"
export default { plugins: [pluginSvg({ plugins: [] })] }assets.icons
後述により Icon は Sprite に移行となりますが、事前にオプションの移行先を記載します。
srcDir, outName
オプションとして指定することはなくなり、テンプレートに設置した Sprite の src により実質的に複数のディレクトリをターゲットにできるようになりました。また、src のファイルが存在するディレクトリ名が出力名になります。
export default {
assets: { icons: { srcDir: "src/assets/icons", outName: "[dirname]" } },
}import { Sprite } from "minista/assets"
export default function () {
return <Sprite src="/src/assets/icons/square.svg" />
}outDir
Vite の build.rollupOptions で設定する必要があります。後述の Separate asset directories を参照して設定してください。
svgstoreOptions
依存関係の SVG 最適化ライブラリが svgstore から svgo に変更となったため、同様のオプションは存在しません。pluginSprite に svgo オプションを渡すことで最適化を図ってください。
export default {
assets: {
icons: {
svgstoreOptions: {
cleanSymbols: ["fill", "stroke", "stroke-linejoin", "stroke-width"],
},
},
},
}import { pluginSprite } from "minista"
export default {
plugins: [
pluginSprite({
plugins: [
{
name: "removeAttrs",
params: {
attrs: ["fill", "stroke", "stroke-linejoin", "stroke-width"],
},
},
],
}),
],
}assets.fonts
outDir, outName
Vite の build.rollupOptions で設定する必要があります。後述の Separate asset directories を参照して設定してください。
assets.bundle
outName
minista のプラグイン pluginBundle のオプションに変更してください。
export default { assets: { bundle: { outName: "bundle" } } }import { pluginBundle } from "minista"
export default { plugins: [pluginBundle({ outName: "bundle" })] }assets.partial
後述により Partial Hydration は Island に移行となりますが、事前にオプションの移行先を記載します。
usePreact
自動切り替えは廃止されたため、Vite の resolve.alias を使用してください。
export default { assets: { partial: { usePreact: true } } }const preactAlias = {
react: "preact/compat",
"react-dom": "preact/compat",
}
export default defineConfig(({ command, isSsrBuild }) => {
const isDev = command === "serve"
const isSsr = command === "build" && isSsrBuild
const isBuild = command === "build" && !isSsrBuild
return {
resolve: {
alias: isBuild ? preactAlias : undefined,
},
}
})preact のインストールも必要となります。
$ npm install preactuseIntersectionObserver
IntersectionObserver を使うかどうかはコンフィグではなくコンポーネントのディレクティブで指定するようになりました。client:visible を使用してください。
export default { assets: { partial: { useIntersectionObserver: true } } }import { Counter } from "../components/counter"
export default function () {
return <Counter client:visible />
}outName
minista のプラグイン pluginIsland のオプションに変更してください。v3 では固定だった [index] プレースホルダーの位置を指定できます。
export default { assets: { partial: { outName: "hydrate" } } }import { pluginIsland } from "minista"
export default { plugins: [pluginIsland({ outName: "hydrate-[index]" })] }rootAttrSuffix, rootValuePrefix
rootAttrSuffix は minista のプラグイン pluginIsland のオプションに変更してください。rootValuePrefix で設定していた識別子の接頭辞は廃止され、HTML には数字のみ記載されます。
export default {
assets: {
partial: { rootAttrSuffix: "partial-hydration", rootValuePrefix: "ph" },
},
}import { pluginIsland } from "minista"
export default {
plugins: [pluginIsland({ rootAttrName: "partial-hydration" })],
}ただし、ハイドレーション対象のルート要素に付与される属性名は機能の細分化に伴い変更されているので、同一の値を渡しても異なる名前になります。CSS や JavaScript で参照している場合は注意してください。
<div data-partial-hydration="ph-1">...</div><div
data-partial-hydration-client-directive="load"
data-partial-hydration-client-directive-params
data-partial-hydration-client-snippet="1"
>
...
</div>rootDOMElement, rootStyle
minista のプラグイン pluginIsland のオプションに変更してください。
export default {
assets: {
partial: { rootDOMElement: "div", rootStyle: { display: "contents" } },
},
}import { pluginIsland } from "minista"
export default {
plugins: [
pluginIsland({ rootDOMElement: "div", rootStyle: { display: "contents" } }),
],
}intersectionObserverOptions
IntersectionObserver の設定はそれが使用されるコンポーネントの client:visible ディレクティブで指定するようになりました。
export default {
assets: { partial: { intersectionObserverOptions: { rootMargin: "0px" } } },
}import { Counter } from "../components/counter"
export default function () {
return <Counter client:visible={{ rootMargin: "0px" }} />
}resolve.alias
※新旧ともに Vite と同じなので変更なし
css
※新旧ともに Vite と同じなので変更なし
markdown
Vite プラグイン pluginsMdx のオプションに変更となりますが、一部のプロパティは廃止されており個別設定となります。
Separate asset directories
Vite のデフォルト設定では、すべてのアセットが同じディレクトリに出力されます。CSS・JavaScript・画像・フォントを別々のディレクトリに出力したい場合は、以下のプロパティを設定してください。
- CSS・画像・フォント:
build.rollupOptions.output.assetFileNames - JavaScript(chunk):
build.rollupOptions.output.chunkFileNames - JavaScript(entry):
build.rollupOptions.output.entryFileNames
※これらを設定した場合 build.assetsDir は無視されます。
assetFileNames は拡張子ごとに分けることができます。
import type { PreRenderedAsset } from "rolldown"
import { normalizePath } from "vite"
const assetFileNames = (assetInfo: PreRenderedAsset) => {
const name = assetInfo.name ?? ""
const originalNames = assetInfo.originalFileNames ?? []
const isSprite = originalNames.some((file) =>
normalizePath(file).includes("/.minista/sprite/"),
)
if (name.endsWith(".css")) {
return "assets/css/[name][extname]"
}
if (isSprite) {
return "assets/sprites/[name][extname]"
}
if (/\.(png|jpe?g|gif|bmp|svg|webp|avif)$/.test(name)) {
return "assets/images/[name][extname]"
}
if (/\.(woff2?|ttf|otf|eot)$/.test(name)) {
return "assets/fonts/[name][extname]"
}
return "assets/others/[name][extname]"
}
export default {
build: {
rollupOptions: {
output: {
assetFileNames,
chunkFileNames: "assets/js/[name].js",
entryFileNames: "assets/js/[name].js",
},
},
},
}