This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is @nette/vite-plugin - a Vite plugin that integrates Vite with Nette Framework and Latte templating engine. The plugin handles:
- Asset management between Vite's dev server and Nette applications
- Dev server URL communication via JSON info file (
nette.json) - Default configuration optimized for Nette project structure
- CORS configuration for dev server integration
# Build TypeScript to JavaScript (compiles src/ to dist/)
npm run build
# Run all tests
npm test
# Run linter
npm run lint
# Auto-fix linting issues
npm run lint:fixThe plugin implements three Vite hooks in sequence:
-
confighook: Applies Nette-specific defaults before Vite resolves configuration- Sets
roottoassets/directory - Sets
build.outDirtowww/assets/(validateswww/exists) - Configures CORS for dev server integration
- Resolves entry points from plugin config
- Sets
-
configResolvedhook: Stores resolved Vite configuration for use in other hooks -
configureServerhook: Sets up dev server info file generation- Only runs in
servemode (not during build) - Attaches listeners to HTTP server lifecycle
- Only runs in
Purpose: Communicates dev server URL from Vite to Nette/PHP backend
Flow:
- When dev server starts listening → writes
www/assets/.vite/nette.jsonwithdevServerURL - Updates
resolvedConfig.server.originto the same URL (critical for asset references) - When server closes → removes the JSON file
- SIGINT handler ensures cleanup on Ctrl+C
File structure:
{
"devServer": "http://localhost:5173"
}Why server.origin matters: Setting this ensures that asset references in CSS/JS (images, fonts, etc.) load from the dev server URL instead of attempting to load from the backend. Without this, imported assets would 404 during development.
The plugin provides convention over configuration optimized for Nette Framework projects:
- Default
root:assets/(Nette convention for source assets) - Default
outDir:www/assets/(requireswww/directory to exist - throws error if missing) - Default
base: empty string (assets served from document root, not subdirectory) - Default
publicDir:public/relative to root (static files copied as-is to outDir) - Manifest: enabled by default (required for Nette Assets to resolve hashed filenames)
- Assets directory: empty string (no subdirectory like
/static, files output directly tooutDir)
All defaults can be overridden via user's vite.config.js.
Design rationale: These defaults match standard Nette project structure where www/ is the document root and contains an assets/ subdirectory for compiled frontend files. Source assets live in project root's assets/ folder to keep them separate from the public web directory.
When entry option is provided:
- Single string: converted to array with one resolved path
- Array: each entry resolved relative to
root - Absolute paths: used as-is without prefix
- Result becomes
build.rollupOptions.input
The plugin configures CORS to allow:
- Vite's default allowed origins
- The project's own host (http/https depending on config)
This enables the Nette backend to fetch assets from Vite dev server during development.
Why automatic CORS is needed: Even when Vite runs on the same hostname as the PHP app (e.g., myapp.local), CORS is required because the dev server runs on a different port. The plugin automatically includes the project's host in allowed origins to solve this.
The plugin bridges two operational modes:
Development Mode (when nette.json exists and app is in debug mode):
- Vite dev server runs (
npm run dev) - Plugin creates
www/assets/.vite/nette.jsonwith dev server URL - Nette Assets PHP library detects this file
- Assets load directly from Vite dev server with Hot Module Replacement (HMR)
- Template tag
{asset 'app.js'}→<script src="http://localhost:5173/app.js" type="module"></script>
Production Mode (when nette.json doesn't exist):
- Optimized build created (
npm run build) - Vite generates
manifest.jsoninoutDir/.vite/ - Nette Assets reads manifest to resolve hashed filenames
- Template tag
{asset 'app.js'}→<script src="/assets/app-4a8f9c7.js" type="module"></script>
Only these assets can be loaded via {asset} in production:
- Entry points specified in plugin config's
entryoption - Public folder files from
assets/public/(copied as-is) - Dynamic imports referenced by JavaScript/CSS (auto-discovered by Vite)
Regular files in assets/ are not directly loadable unless imported by an entry point. This is by design - Vite only bundles assets that are part of the dependency graph.
Framework: Mocha with Node's built-in assert
Test organization:
index.test.ts: Plugin configuration, hooks, and integration testsinfo-file.test.ts: Info file generation, cleanup, and edge casesutils.ts: Shared test utilities (temp directory cleanup)
Key patterns:
- Each test creates isolated temp directory via
beforeEach - Tests change
process.cwd()to temp directory afterEachcleanup restores original cwd and removes temp files- Mock HTTP server with event handlers to simulate Vite dev server
- Asynchronous tests use callbacks for event-driven assertions
Mock structure for server tests:
const mockDevServer = {
httpServer: {
on: (event, callback) => { /* simulate events */ },
address: () => ({ port: 5173 })
}
};- Target: ES2020
- Module: ESNext (for Vite compatibility)
- Output:
dist/directory with declaration files - Source:
src/directory (single file:index.ts) - Strict mode: Enabled
Uses @nette/eslint-plugin with TypeScript support:
- Node.js and Mocha globals configured
- Browser environment disabled (Node-only plugin)
- Customized config via
nette.configs.customize()
Validation: Plugin validates that www/ directory exists when using default outDir. Throws descriptive error if missing:
The output directory "www/assets" does not exist. Please set "build.outDir" in your Vite config.
Cleanup: SIGINT handler ensures info file is removed even on abrupt termination.