The plain PHP, Yii2, and Yii3 production examples below target Vite 5 or later and assume this application-owned configuration:
import {defineConfig} from 'vite';
export default defineConfig({
build: {
outDir: 'public/build',
manifest: '.vite/manifest.json',
rollupOptions: {
input: 'resources/js/app.js',
},
},
});Because build.manifest is relative to build.outDir, this configuration writes
<project-root>/public/build/.vite/manifest.json. Each PHP example resolves that same file through the path mechanism of
its application or framework.
Select one immutable configuration at the application's composition root:
use PHPForge\Vite\Configuration\DevelopmentConfiguration;
use PHPForge\Vite\Configuration\ProductionConfiguration;
use PHPForge\Vite\Html\HtmlRenderer;
use PHPForge\Vite\Vite;
$configuration = $isDevelopment
? DevelopmentConfiguration::create(
devServerUrl: 'http://localhost:5173',
)
: ProductionConfiguration::create(
manifestPath: __DIR__ . '/public/build/.vite/manifest.json',
assetBaseUrl: '/build',
);
$vite = Vite::create($configuration, entrypoints: ['resources/js/app.js']);
$assets = $vite->resolve();
echo HtmlRenderer::create()->render($assets);The production example assumes __DIR__ is the absolute project root used by the matching Vite configuration.
Applications may skip HtmlRenderer and integrate the neutral model with their own response, template, or asset system:
use PHPForge\Vite\Asset\InlineModule;
use PHPForge\Vite\Asset\ModulePreload;
use PHPForge\Vite\Asset\ModuleScript;
use PHPForge\Vite\Asset\Stylesheet;
foreach ($vite->resolve() as $asset) {
match (true) {
$asset instanceof ModuleScript => $view->addModuleScript($asset->url),
$asset instanceof Stylesheet => $view->addStylesheet($asset->url),
$asset instanceof ModulePreload => $view->addModulePreload($asset->url),
$asset instanceof InlineModule => $view->addInlineModule($asset->source),
};
}The example methods belong to the consuming application; they are not package APIs.
Register the facade as an application component so Yii2 owns its lazy construction and lifecycle. The package does not
access Yii::getAlias(), the service locator, or yii\web\View:
use PHPForge\Vite\Configuration\DevelopmentConfiguration;
use PHPForge\Vite\Configuration\ProductionConfiguration;
use PHPForge\Vite\Html\HtmlRenderer;
use PHPForge\Vite\Vite;
$config = [
'components' => [
'vite' => [
'class' => Vite::class,
'__construct()' => [
'configuration' => YII_ENV === 'dev'
? DevelopmentConfiguration::create(
devServerUrl: 'http://localhost:5173',
)
: ProductionConfiguration::create(
manifestPath: dirname(__DIR__) . '/public/build/.vite/manifest.json',
assetBaseUrl: '/build',
),
'entrypoints' => ['resources/js/app.js'],
],
],
],
];
/** @var Vite $vite */
$vite = Yii::$app->get('vite');
echo HtmlRenderer::create()->render($vite->resolve());The __construct() entry is Yii2 container syntax. Its values are passed to the framework-independent constructor, and
the concrete manifest path is resolved entirely by the consuming application.
Resolve the framework aliases in the application's dependency-injection configuration, then inject the same Vite class:
use PHPForge\Vite\Configuration\ProductionConfiguration;
use PHPForge\Vite\Vite;
use Yiisoft\Aliases\Aliases;
static function (Aliases $aliases): Vite {
return Vite::create(
ProductionConfiguration::create(
manifestPath: $aliases->get('@public/build/.vite/manifest.json'),
assetBaseUrl: '/build',
),
entrypoints: ['resources/js/app.js'],
);
};Yii2 and Yii3 therefore share the package API; only the application's path-resolution and container wiring differ.
The @public alias must resolve to the public directory configured as build.outDir.
React Refresh and comparable plugin preambles are application concerns. A project can provide a neutral inline module without adding a React dependency to this package:
use PHPForge\Vite\Asset\InlineModule;
use PHPForge\Vite\Configuration\DevelopmentConfiguration;
use PHPForge\Vite\Development\InlineModuleProviderInterface;
use PHPForge\Vite\Vite;
final class ReactRefreshPreamble implements InlineModuleProviderInterface
{
public function provide(string $devServerUrl): InlineModule
{
$refreshUrl = json_encode($devServerUrl . '/@react-refresh', JSON_THROW_ON_ERROR);
return new InlineModule(<<<JS
import RefreshRuntime from {$refreshUrl};
RefreshRuntime.injectIntoGlobalHook(window);
window.\$RefreshReg\$ = () => {};
window.\$RefreshSig\$ = () => type => type;
window.__vite_plugin_react_preamble_installed__ = true;
JS);
}
}
$configuration = DevelopmentConfiguration::create(
devServerUrl: 'http://localhost:5173',
inlineModuleProviders: [new ReactRefreshPreamble()],
);
$vite = Vite::create($configuration, entrypoints: ['resources/js/app.jsx']);Providers run in their configured order before @vite/client and the entrypoint scripts. The application owns the provider
code and the matching Vite plugin dependency.
php-forge/foxy may be used independently by a consuming project to coordinate its
Composer and JavaScript dependencies. It is not installed, invoked, or configured by this package.