swc-plugin-compatibility について
`@lingui/swc-plugin` と SWC ホストの互換性エラーを調査するスキルです。ホストのバージョン確認、互換プラグインの選定と固定、Next.js・Vite・Rspack でのマクロ変換検証を支援します。
主な機能
- 01解決済み SWC ホストの特定
- 02互換プラグインバージョンの選定
- 03`@lingui/core` の peer 要件確認
- 04プラグインの厳密なバージョン固定
- 05Babel フォールバック案内
活用シーン
- 01SWC Wasm プラグインのビルド失敗を調査
- 02ホスト更新後のプラグイン選定
- 03ビルドで Lingui マクロの出力を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lingui/ skills --skill swc-plugin-compatibilityインストール後、Claude Code で/swc-plugin-compatibilityを入力して読み込まれたか確認します。
詳細
SWC プラグインの互換性
ビルド中に次のようなエラーが表示された場合:
failed to invoke plugin on 'Some("/app/src/file.ts")'
failed to run Wasm plugin transform. Please ensure the version of `swc_core` used by the plugin is compatible with the host runtime.
swc_plugin_runner: <n>
: Failed to deserialize program received from host
Failed to execute SWC plugin (Next.js / Turbopack wording of the same failure)
RuntimeError: out of bounds memory access (older hosts)
LayoutError called Result::unwrap() (older hosts)
これは、コードや Lingui のバグではありません。 インストールされている @lingui/swc-plugin は、SWC ホストが実行できないバージョンの swc_core に対してビルドされています。
この問題が発生する理由
@lingui/swc-plugin の各リリースは、固定された 1 つの swc_core バージョンに対してコンパイルされています。プラグインの互換性表に、対応するバージョンが記載されています。ホスト(Next.js にバンドルされた SWC、または @vitejs/plugin-react-swc/Rspack が解決する @swc/core)は、ある範囲の swc_core バージョンのプラグインを受け入れます。その範囲外では、Wasm プラグインは渡された AST をデシリアライズできず、マクロを使うすべてのファイルでビルドが失敗します。
SWC では時間をかけてプラグイン ABI が安定化しているため、バージョンの不一致は以前より減っていますが、それでもホストがプラグインより先行したり、プラグインがホストより先行したりすることがあります(それぞれの例については、lingui/swc-plugin の #250 と #253 を参照してください)。対応関係は必ず確認し、思い込みで判断しないでください。
修正方法
ステップ 1:ホストと解決済みバージョンを特定する
| プロジェクト内の手がかり | ホスト | バージョンの確認先 |
|---|---|---|
依存関係に next があり、.babelrc がない | Next.js にバンドルされた SWC | npm ls next |
@vitejs/plugin-react-swc | @swc/core | npm ls @swc/core — プラグインが宣言するキャレット範囲ではなく、ロックファイルで解決されたバージョン |
Rspack/@swc/core を直接使用 | @swc/core | npm ls @swc/core |
Next.js は SWC を内包しており、package.json にある @swc/core は無視します。swc_core を決めるのは Next.js のバージョンだけです。Vite では、package.json が同一の 2 つのプロジェクトでも、異なるバージョンの @swc/core に解決される場合があります。信頼できる情報源はロックファイルです。
ステップ 2:プラグインのバージョンを選ぶ
- ホストが受け入れる
swc_coreの範囲を確認します。エラーメッセージには通常、https://plugins.swc.rs/versions/from-plugin-runner/<n>の URL が表示されます。ブラウザーで開いてください。Next.js の場合は、https://plugins.swc.rs でランタイムにnextを選択し、解決済みバージョンを指定します。このサイトはクライアント側でレンダリングされるため、通常の fetch では空のページが返されます。代わりに、ホスト自体が指定しているバージョンを確認します。Next.js の場合はvercel/next.jsのタグ(v<version>)にあるルートのCargo.tomlのswc_core、@swc/coreの場合は GitHub のリリースノートを確認してください。 - プラグインの互換性表から、その範囲内の
swc_coreを使う 最新の@lingui/swc-pluginを選びます。 - ピア依存関係を確認します:
npm view @lingui/swc-plugin@<version> peerDependencies。各プラグインのメジャーバージョンは、対応する@lingui/coreのメジャーバージョンを必須のピア依存関係として要求します(新しいプラグインのメジャーバージョンが、前の core メジャーバージョンにも対応している場合もあります)。インストール済みの@lingui/coreがピア依存関係の対象外となる候補は使えません。その場合、ビルドが失敗するのではなく、インストールがERESOLVEで失敗します。条件を満たす次に新しいバージョンを選ぶか、「互換性のあるバージョンが存在しない場合」を参照してください。
互換性サイトの情報が、以前リリースより遅れていたことがあります。表とサイトの内容が一致しない場合、またはホストのバージョンがどちらにも記載されていない場合は、ビルドで判断してください。最新のプラグインから試し、マクロを使用するファイルがコンパイルできるまで、swc_core の表を 1 行ずつさかのぼります。
ホストごとに独立してバージョンが変わるため、1 つのリポジトリ内にある 2 つのホスト(Next.js アプリと Vite アプリなど)で、異なるプラグインバージョンが必要になるのは自然なことです。
ステップ 3:バージョンを厳密に固定して確認する
{
"devDependencies": {
"@lingui/swc-plugin": "<exact version>"
}
}
バージョンは厳密に指定し(^ や ~ は付けません)、通常の依存関係の更新でバージョンが変わらないようにします。マクロを使うファイルのビルドが成功し、レンダリング結果にマクロのソースではなく翻訳済みのテキストが表示されれば完了です。
動作を維持する
- プラグインのバージョンを正確に固定し、Renovate/Dependabot の自動マージ対象から除外してください。互換性表を確認してから、意図的にバージョンを上げてください。
- ホストのアップグレードもプラグインのアップグレードとして扱ってください。 ホストはマイナーリリースやパッチリリースで
swc_coreを変更するため、Next.js または@vitejs/plugin-react-swcのバージョンを上げる際も、同じ確認が必要です。両方のパッケージを同じ更新グループにまとめてください。 - SWC またはプラグインに影響するアップグレードの後は、必ずビルドしてください。 確認になるのは変更履歴ではなく、ビルドです。
@lingui/swc-plugin のバージョンは、他の @lingui/* のバージョンには連動しません。独自のリリースサイクルでリリースされるため、バージョン番号からは、peer フィールド以外に、どの @lingui/core と組み合わせられるかは分かりません。
例:Next.js の設定
// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
swcPlugins: [
['@lingui/swc-plugin', {
// Plugin options
}],
],
},
};
export default nextConfig;
例:.swcrc の設定
{
"$schema": "https://json.schemastore.org/swcrc",
"jsc": {
"experimental": {
"plugins": [
["@lingui/swc-plugin", {}]
]
}
}
}
例:Vite の設定
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import { lingui } from "@lingui/vite-plugin";
export default defineConfig({
plugins: [
react({ plugins: [["@lingui/swc-plugin", {}]] }),
lingui(),
],
});
サイレントな失敗:プラグインエントリーの形式が誤っている
すべての SWC プラグインエントリーは、オプションが空でも [name, options] のタプルである必要があります。プラグイン名を文字列だけで渡すと、マクロ変換はサイレントに無効になります。ビルドは成功しますが、<Trans> は解決されず、メッセージはマクロの出力そのままで表示されます。
// ❌ Silently does nothing
react({ plugins: ["@lingui/swc-plugin"] })
// ✅ Tuple with options object
react({ plugins: [["@lingui/swc-plugin", {}]] })
Next.js の swcPlugins と .swcrc の plugins 配列にも同じことが当てはまります。
互換性のあるバージョンがない場合は?
プロジェクトの @lingui/core と一緒にインストールできるプラグインのバージョンがホストに適合しない場合は、推測せず、明確な選択をしてください。
- ホストを、
swc_coreの範囲に一致するプラグインがあるバージョンに変更する(通常は新しいホストの方が、新しいプラグインに対応しています) - Babel 変換に切り替える(
@lingui/babel-plugin-lingui-macro)— 以下の注意事項を参照してください - https://github.com/lingui/swc-plugin で issue または PR を作成する
--legacy-peer-deps でインストールを強行したり、古いプラグインの peer を満たすために @lingui/core をダウングレードしたりするのは、選択肢に含まれません。前者はビルドまで不一致を見えなくし、後者はビルドツールに合わせるためにランタイムを後退させます。
Next.js での Babel フォールバック
npm install -D @lingui/babel-plugin-lingui-macro babel-plugin-macros @babel/types
// .babelrc
{ "presets": ["next/babel"], "plugins": ["macros"] }
experimental.swcPlugins エントリーを削除してください。Babel を使う場合に必要となる、SWC プラグインでは不要だったものが3つあります。
@babel/typesを明示的にインストールすること。 Next は独自の Babel をバンドルしており、プラグインからは利用できません。これをインストールしないと、ビルドはCannot find package '@babel/types'で失敗します。lingui.config.ts(または.js/.mjs)。 Babel マクロはコンパイル時にこのファイルを読み込みます。SWC プラグインは読み込まなかったため、これなしで動作していたプロジェクトはここで失敗します。.babelrcを使うと、プロジェクト全体で Next の SWC コンパイラーが無効になることを受け入れること。 Next はDisabled SWC as replacement for Babel because of custom Babel configurationと出力し、それ以降next.configのcompilerオプションは無視されます。ビルドは遅くなるため、可能であればホストの変更を優先してください。
Babel フォールバックの注意点:@vitejs/plugin-react 6
@vitejs/plugin-react@6 では内蔵 Babel が削除され、babel オプションも完全に削除されました。v6 以降では、次の従来の形式は:
react({ babel: { plugins: ["@lingui/babel-plugin-lingui-macro"] } })
動作しません。TypeScript の設定では TS2353(「babel does not exist in type...」)で失敗し、通常の JS 設定ではサイレントに無視されるため、マクロは変換されません。
Vite での選択肢:
- SWC を使い続ける:上記の手順で選んだ、バージョンを正確に固定した
@lingui/swc-pluginと@vitejs/plugin-react-swcを使う(推奨) - マクロを独立した Babel パスとして実行する(Vite 8 では
@rolldown/plugin-babel、Vite ≤ 7 ではvite-plugin-babel)。設定方法については lingui-framework-setup スキルを参照してください babelオプションを引き続きサポートする@vitejs/plugin-react@^5にバージョンを固定する