Vite連携

最新のJavaScriptアプリケーションには、洗練されたビルドツールが必要です。Nette Assetsは、次世代のフロントエンドビルドツールであるViteとのファーストクラスの連携を提供します。設定の手間なしで、ホットモジュールリプレイスメント(HMR)による超高速開発と最適化された本番ビルドを実現します。

  • ゼロ設定 – ViteとPHPテンプレート間の自動ブリッジ
  • 完全な依存関係管理 – 1つのタグですべてのアセットを処理
  • ホットモジュールリプレイスメント – JavaScriptとCSSの即時更新
  • 最適化された本番ビルド – コード分割とツリーシェイキング

Nette AssetsはViteとシームレスに連携するため、テンプレートを通常通り記述しながら、これらすべての恩恵を受けることができます。

Viteのセットアップ

Viteをステップバイステップでセットアップしましょう。ビルドツールに慣れていなくても心配ありません。すべて説明します!

ステップ1: Viteをインストールする

まず、プロジェクトにViteとNetteプラグインをインストールします。

npm install -D vite @nette/vite-plugin

これにより、Viteと、ViteがNetteと完全に連携するのに役立つ特別なプラグインがインストールされます。

ステップ2: プロジェクト構造

標準的なアプローチは、ソースアセットファイルをプロジェクトルートのassets/フォルダーに配置し、コンパイルされたバージョンをwww/assets/に配置することです。

web-project/
├── assets/                   ← ソースファイル (SCSS, TypeScript, ソース画像)
│   ├── public/               ← 静的ファイル (そのままコピーされる)
│   │   └── favicon.ico
│   ├── images/
│   │   └── logo.png
│   ├── app.js                ← メインエントリポイント
│   └── style.css             ← スタイル
└── www/                      ← public ディレクトリ (ドキュメントルート)
	├── assets/               ← コンパイルされたファイルがここに入る
	└── index.php

assets/フォルダーにはソースファイル、つまり記述するコードが含まれています。Viteはこれらのファイルを処理し、コンパイルされたバージョンをwww/assets/に配置します。

ステップ3: Viteを設定する

プロジェクトルートにvite.config.tsファイルを作成します。このファイルは、Viteにソースファイルの場所とコンパイルされたファイルの出力先を指示します。

Nette Viteプラグインには、設定を簡素化するスマートなデフォルトが付属しています。フロントエンドのソースファイルはassets/ディレクトリ(rootオプション)にあり、コンパイルされたファイルはwww/assets/outDirオプション)に配置されると想定しています。必要なのはエントリポイントを指定することだけです。

import { defineConfig } from 'vite';
import nette from '@nette/vite-plugin';

export default defineConfig({
	plugins: [
		nette({
			entry: 'app.js',
		}),
	],
});

アセットをビルドするために別のディレクトリ名を指定したい場合は、いくつかのオプションを変更する必要があります。

export default defineConfig({
	root: 'assets', // ソースアセットのルートディレクトリ

	build: {
		outDir: '../www/assets',  // コンパイルされたファイルの出力先
	},

	// ... その他の設定 ...
});

outDirパスはrootからの相対パスと見なされるため、先頭に../があります。

ステップ4: Netteを設定する

common.neonでNette AssetsにViteについて伝えます。

assets:
	mapping:
		default:
			type: vite      # NetteにViteMapperを使用するよう指示
			path: assets

ステップ5: スクリプトを追加する

これらのスクリプトをpackage.jsonに追加します。

{
	"scripts": {
		"dev": "vite",
		"build": "vite build"
	}
}

これで次のことができます。

  • npm run dev – ホットリロード付き開発サーバーを開始
  • npm run build – 最適化された本番ファイルを作成

エントリポイント

エントリポイントは、アプリケーションが開始するメインファイルです。このファイルから、他のファイル(CSS、JavaScriptモジュール、画像)をインポートし、依存関係ツリーを作成します。Viteはこれらのインポートを追跡し、すべてをバンドルします。

エントリポイントassets/app.jsの例:

// スタイルをインポート
import './style.css'

// JavaScriptモジュールをインポート
import netteForms from 'nette-forms';
import naja from 'naja';

// アプリケーションを初期化
netteForms.initOnLoad();
naja.initialize();

テンプレートでは、エントリポイントを次のように挿入できます。

{asset 'app.js'}

Nette Assetsは、必要なすべてのHTMLタグ(JavaScript、CSS、およびその他の依存関係)を自動的に生成します。

複数のエントリポイント

大規模なアプリケーションでは、個別のエントリポイントが必要になることがよくあります。

export default defineConfig({
	plugins: [
		nette({
			entry: [
				'app.js',      // public ページ
				'admin.js',    // 管理パネル
			],
		}),
	],
});

異なるテンプレートで使用します。

{* public ページで *}
{asset 'app.js'}

{* 管理パネルで *}
{asset 'admin.js'}

重要: ソースファイルとコンパイル済みファイル

本番環境では、次のもののみをロードできることを理解することが重要です。

  1. entryで定義されたエントリポイント
  2. assets/public/ディレクトリのファイル

{asset}を使用してassets/から任意のファイルをロードすることはできません。JavaScriptまたはCSSファイルによって参照されているアセットのみです。ファイルがどこからも参照されていない場合、コンパイルされません。Viteに他のアセットを認識させたい場合は、public フォルダーに移動できます。

デフォルトでは、Viteは4KB未満のすべてのアセットをインライン化するため、これらのファイルを直接参照できないことに注意してください。(Vite ドキュメントを参照)。

{* ✓ これは動作します - エントリポイントです *}
{asset 'app.js'}

{* ✓ これは動作します - assets/public/ にあります *}
{asset 'favicon.ico'}

{* ✗ これは動作しません - assets/ 内のランダムなファイルです *}
{asset 'components/button.js'}

開発モード

開発モードは完全にオプションですが、有効にすると大きなメリットがあります。主な利点はホットモジュールリプレイスメント (HMR)です。アプリケーションの状態を失うことなく変更を即座に確認できるため、開発エクスペリエンスがはるかにスムーズで高速になります。

Viteは、開発を信じられないほど高速にする最新のビルドツールです。従来のバンドラーとは異なり、Viteは開発中にコードをブラウザに直接提供するため、プロジェクトの規模に関係なくサーバーの起動が瞬時に行われ、更新も超高速です。

開発サーバーの起動

開発サーバーを実行します。

npm run dev

次のように表示されます。

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

開発中は、このターミナルを開いたままにしてください。

Nette Viteプラグインは、次の条件が満たされたときに自動的に検出します。

  1. Vite開発サーバーが実行中である
  2. Netteアプリケーションがデバッグモードである

両方の条件が満たされると、Nette Assetsはコンパイルされたディレクトリからではなく、Vite開発サーバーからファイルをロードします。

{asset 'app.js'}
{* 開発時: <script src="http://localhost:5173/app.js" type="module"></script> *}
{* 本番時: <script src="/assets/app-4a8f9c7.js" type="module"></script> *}

設定は不要です。ただ動作します!

異なるドメインでの作業

開発サーバーがlocalhost以外のもの(例: myapp.local)で実行されている場合、CORS(Cross-Origin Resource Sharing)の問題が発生する可能性があります。CORSは、ウェブブラウザのセキュリティ機能であり、デフォルトでは異なるドメイン間のリクエストをブロックします。PHPアプリケーションがmyapp.localで実行されているが、Viteがlocalhost:5173で実行されている場合、ブラウザはこれらを異なるドメインと見なし、リクエストをブロックします。

これを解決するには2つのオプションがあります。

オプション1: CORSを設定する

最も簡単な解決策は、PHPアプリケーションからのクロスオリジンリクエストを許可することです。

export default defineConfig({
	// ... その他の設定 ...

	server: {
		cors: {
			origin: 'http://myapp.local',  // PHPアプリのURL
		},
	},
});

オプション2: Viteを同じドメインで実行する

もう1つの解決策は、ViteをPHPアプリケーションと同じドメインで実行することです。

export default defineConfig({
	// ... その他の設定 ...

	server: {
		host: 'myapp.local',  // PHPアプリと同じ
	},
});

実際、この場合でも、開発サーバーは同じホスト名ですが異なるポートで実行されるため、CORSを設定する必要があります。ただし、この場合、CORSはNette Viteプラグインによって自動的に設定されます。

HTTPS開発

HTTPSで開発する場合、Vite開発サーバーには証明書が必要です。最も簡単な方法は、証明書を自動的に生成するプラグインを使用することです。

npm install -D vite-plugin-mkcert

vite.config.tsでの設定方法は次のとおりです。

import mkcert from 'vite-plugin-mkcert';

export default defineConfig({
	// ... その他の設定 ...

	plugins: [
		mkcert(),  // 証明書を自動生成し、httpsを有効にする
		nette(),
	],
});

CORS設定(上記のオプション1)を使用している場合、オリジンURLをhttp://ではなくhttps://を使用するように更新する必要があることに注意してください。

本番ビルド

最適化された本番ファイルを作成します。

npm run build

Viteは次のことを行います。

  • すべてのJavaScriptとCSSをミニファイします
  • コードを最適なチャンクに分割します
  • キャッシュバストのためにハッシュ化されたファイル名を生成します
  • Nette Assets用のマニフェストファイルを作成します

出力例:

www/assets/
├── app-4f3a2b1c.js       # メインJavaScript (ミニファイ済み)
├── app-7d8e9f2a.css      # 抽出されたCSS (ミニファイ済み)
├── vendor-8c4b5e6d.js    # 共有依存関係
└── .vite/
	└── manifest.json     # Nette Assetsのマッピング

ハッシュ化されたファイル名により、ブラウザは常に最新バージョンをロードします。

Public フォルダー

assets/public/ディレクトリ内のファイルは、処理されずにそのまま出力にコピーされます。

assets/
├── public/
│   ├── favicon.ico
│   ├── robots.txt
│   └── images/
│       └── og-image.jpg
├── app.js
└── style.css

通常通り参照します。

{* これらのファイルはそのままコピーされます *}
<link rel="icon" href={asset 'favicon.ico'}>
<meta property="og:image" content={asset 'images/og-image.jpg'}>

publicファイルの場合、FilesystemMapperの機能を使用できます。

assets:
	mapping:
		default:
			type: vite
			path: assets
			extension: [webp, jpg, png]  # 最初にWebPを試す
			versioning: true             # キャッシュバストを追加

vite.config.ts設定では、publicDirオプションを使用してpublicフォルダーを変更できます。

動的インポート

Viteは最適なロードのためにコードを自動的に分割します。動的インポートを使用すると、実際に必要なときにのみコードをロードできるため、初期バンドルサイズを削減できます。

// 重いコンポーネントをオンデマンドでロード
button.addEventListener('click', async () => {
	let { Chart } = await import('./components/chart.js')
	new Chart(data)
})

動的インポートは、必要なときにのみロードされる個別のチャンクを作成します。これは「コード分割」と呼ばれ、Viteの最も強力な機能の1つです。動的インポートを使用すると、Viteは動的にインポートされたモジュールごとに個別のJavaScriptファイルを自動的に作成します。

{asset 'app.js'}タグは、これらの動的チャンクを自動的にプリロードしません。これは意図的な動作です。使用されない可能性のあるコードをダウンロードしたくありません。チャンクは、動的インポートが実行されたときにのみダウンロードされます。

ただし、特定の動的インポートが重要であり、すぐに必要になることがわかっている場合は、それらをプリロードできます。

{* メインエントリポイント *}
{asset 'app.js'}

{* 重要な動的インポートをプリロード *}
{preload 'components/chart.js'}

これにより、ブラウザはチャートコンポーネントをバックグラウンドでダウンロードし、必要になったときにすぐに使用できるようにします。

TypeScriptサポート

TypeScriptはそのまま動作します。

// assets/main.ts
interface User {
	name: string
	email: string
}

export function greetUser(user: User): void {
	console.log(`Hello, ${user.name}!`)
}

TypeScriptファイルを通常通り参照します。

{asset 'main.ts'}

完全なTypeScriptサポートには、インストールが必要です。

npm install -D typescript

追加のVite設定

以下に、詳細な説明付きの便利なVite設定オプションをいくつか示します。

export default defineConfig({
	// ソースアセットを含むルートディレクトリ
	root: 'assets',

	// 内容がそのまま出力ディレクトリにコピーされるフォルダー
	// デフォルト: 'public' ('root'からの相対パス)
	publicDir: 'public',

	build: {
		// コンパイルされたファイルの出力先 ('root'からの相対パス)
		outDir: '../www/assets',

		// ビルド前に出力ディレクトリを空にするか?
		// 以前のビルドからの古いファイルを削除するのに便利
		emptyOutDir: true,

		// outDir内の生成されたチャンクとアセットのサブディレクトリ
		// 出力構造を整理するのに役立つ
		assetsDir: 'static',

		rollupOptions: {
			// エントリポイント - 単一のファイルまたはファイルの配列
			// 各エントリポイントは個別のバンドルになる
			input: [
				'app.js',      // メインアプリケーション
				'admin.js',    // 管理パネル
			],
		},
	},

	server: {
		// 開発サーバーをバインドするホスト
		// ネットワークに公開するには '0.0.0.0' を使用
		host: 'localhost',

		// 開発サーバーのポート
		port: 5173,

		// クロスオリジンリクエストのCORS設定
		cors: {
			origin: 'http://myapp.local',
		},
	},

	css: {
		// 開発時にCSSソースマップを有効にする
		devSourcemap: true,
	},

	plugins: [
		nette(),
	],
});

これで完了です!Nette Assetsと連携した最新のビルドシステムが手に入りました。

バージョン: 1.0