Vite Integration
Modern JavaScript applications require sophisticated build tools. Nette Assets provides first-class integration with Vite, the next-generation frontend build tool. Get lightning-fast development with Hot Module Replacement (HMR) and optimized production builds with zero configuration hassle.
- Zero configuration – automatic bridge between Vite and PHP templates
- Complete dependency management – one tag handles all assets
- Hot Module Replacement – instant JavaScript and CSS updates
- Optimized production builds – code splitting and tree shaking
Setting Up Vite
First, install Vite in your project:
npm install -D vite
# or for TypeScript
npm install -D vite typescript
Create Vite configuration file vite.config.ts
:
import { defineConfig } from 'vite';
import path from 'path';
export default defineConfig(() => {
return {
root: 'assets', // set assets/ as the root directory for Vite to resolve imports
base: 'assets', // base URL for assets
build: {
manifest: true, // generate manifest.json - essential for Nette Assets
outDir: path.resolve(__dirname, 'www/assets'), // must match Nette Assets 'path' config
assetsDir: '', // Don't create additional nested directories for assets
},
};
});
In your configuration:
assets:
mapping:
default:
type: vite
path: assets
That's it! Nette Assets automatically handles everything else.
Entry Points and Dependencies
Modern JavaScript applications often split code into multiple files. An “entry point” is your main file that imports other modules, CSS, and assets.
Example entry point assets/main.js
:
import './style.css'
import { initApp } from './app.js'
import { setupNavigation } from './components/navigation.js'
// Initialize your application
document.addEventListener('DOMContentLoaded', () => {
initApp()
setupNavigation()
})
In modern JavaScript development, CSS is often imported directly in JavaScript files rather than included separately in HTML. This approach allows bundlers like Vite to process and bundle CSS and provide hot reloading for CSS changes.
Add entry point to vite.config.ts
:
export default defineConfig(() => {
return {
build: {
rollupOptions: {
input: {
main: path.resolve(__dirname, 'assets/main.js'),
},
},
},
};
});
When you reference this entry point in your template:
{asset 'main.js'}
Nette Assets automatically generates all necessary HTML tags:
<!-- Main JavaScript bundle -->
<script src="/assets/main-4a8f9c7.js" type="module" crossorigin></script>
<!-- Vendor chunks (if any) preloaded for performance -->
<link rel="modulepreload" href="/assets/vendor-8c7fa9b.js" crossorigin>
<!-- Extracted CSS -->
<link rel="stylesheet" href="/assets/main-2b9c8d7.css" crossorigin>
All dependencies are handled automatically – you write one line, get complete asset management.
Production Builds
In production, Vite generates optimized bundles with hashed filenames:
npm run build
Vite generates:
- Minified JavaScript bundles
- Extracted and optimized CSS
- Hashed filenames for cache-busting
- A manifest file mapping source files to built files
Development Workflow
Development mode is an optional feature that provides significant benefits for modern web development. The main benefit is Hot Module Replacement (HMR), which works for both JavaScript and CSS. This means you can see changes instantly in your browser without losing application state – forms stay filled, modals remain open, and your debugging session continues uninterrupted.
To enable it, activate the devServer
option in your configuration:
assets:
mapping:
default:
type: vite
devServer: true
Additionally, update your vite.config.ts
:
export default defineConfig(() => {
return {
build: {
// ...
},
server: {
host: 'localhost', // the host on which your development site runs
cors: true, // enable CORS for cross-origin requests
},
};
});
The CORS configuration is important because your PHP application (typically running on a different port like 80 or 443) needs to load assets from Vite's dev server running on port 5173. Without CORS enabled, browsers would block these cross-origin requests.
Start Vite's development server:
npm run dev
When option devServer
is enabled and your application runs in debug mode, Nette Assets automatically
connects to Vite's dev server. It detects the current URL and replaces the host with port 5173 to load assets directly from the
dev server:
{asset 'main.js'}
{* In development: <script src="http://localhost:5173/assets/main.js" type="module"></script> *}
This seamless integration means you don't need to manually switch between development and production asset URLs – Nette Assets handles this automatically based on your environment.
Working with Public Files
Files in Vite's assets/public/
directory aren't processed by Vite but are copied as-is to the output. The
ViteMapper handles these seamlessly:
{* References a file from public/ directory *}
{asset 'favicon.ico'}
{* Also works with nested paths *}
{asset 'images/logo.png'}
For public files, you can use FilesystemMapper features like automatic extension detection:
assets:
mapping:
default:
type: vite
path: assets
extension: [webp, jpg, png] # Try WebP first, fallback to JPG/PNG
versioning: true # Add cache-busting parameters
Dynamic Imports
Vite automatically splits code for optimal loading:
// Dynamically import heavy components
const loadChart = () => import('./components/chart.js')
button.addEventListener('click', async () => {
const { Chart } = await loadChart()
new Chart(data)
})
Dynamic imports create separate chunks loaded on demand. However, {asset 'main.js'}
does not automatically
preload these dynamic imports. This is intentional – preloading all possible dynamic imports could hurt performance by
downloading unused code.
If you want to preload specific dynamic imports that you know will be needed, use the {preload}
tag:
{* Main entry point *}
{asset 'main.js'}
{* Preload critical dynamic imports *}
{preload 'components/chart.js'}
This gives you fine-grained control over which resources are preloaded based on your application's actual needs.
TypeScript Support
TypeScript works out of the box:
// assets/main.ts
interface User {
name: string
email: string
}
export function greetUser(user: User): void {
console.log(`Hello, ${user.name}!`)
}
Just reference your TypeScript files:
{asset 'assets/main.ts'}