Интеграция с Vite

Современные JavaScript-приложения требуют сложных инструментов сборки. Nette Assets обеспечивает первоклассную интеграцию с Vite, инструментом сборки фронтенда нового поколения. Получите молниеносную разработку с горячей заменой модулей (HMR) и оптимизированные производственные сборки без проблем с конфигурацией.

  • Нулевая конфигурация – автоматический мост между Vite и PHP-шаблонами
  • Полное управление зависимостями – один тег обрабатывает все активы
  • Горячая замена модулей – мгновенные обновления JavaScript и CSS
  • Оптимизированные производственные сборки – разделение кода и удаление неиспользуемого кода (tree shaking)

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/                      ← публичный каталог (корневой каталог документа)
	├── 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', // root directory of source assets

	build: {
		outDir: '../www/assets',  // where compiled files go
	},

	// ... other config ...
});

Путь outDir считается относительным к root, поэтому в начале есть ../.

Шаг 4: Настройте Nette

Сообщите Nette Assets о Vite в вашем common.neon:

assets:
	mapping:
		default:
			type: vite      # tells Nette to use the 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 styles
import './style.css'

// Import JavaScript modules
import netteForms from 'nette-forms';
import naja from 'naja';

// Initialize your application
netteForms.initOnLoad();
naja.initialize();

В шаблоне вы можете вставить точку входа следующим образом:

{asset 'app.js'}

Nette Assets автоматически генерирует все необходимые HTML-теги – JavaScript, CSS и любые другие зависимости.

Несколько точек входа

Крупные приложения часто нуждаются в отдельных точках входа:

export default defineConfig({
	plugins: [
		nette({
			entry: [
				'app.js',      // public pages
				'admin.js',    // admin panel
			],
		}),
	],
});

Используйте их в разных шаблонах:

{* In public pages *}
{asset 'app.js'}

{* In admin panel *}
{asset 'admin.js'}

Важно: исходные и скомпилированные файлы

Крайне важно понимать, что на продакшене вы можете загружать только:

  1. Точки входа, определенные в entry
  2. Файлы из каталога assets/public/

Вы не можете загружать с помощью {asset} произвольные файлы из assets/ – только активы, на которые ссылаются файлы JavaScript или CSS. Если ваш файл нигде не ссылается, он не будет скомпилирован. Если вы хотите, чтобы Vite знал о других активах, вы можете переместить их в публичную папку.

Обратите внимание, что по умолчанию Vite будет встраивать все активы размером менее 4 КБ, поэтому вы не сможете ссылаться на эти файлы напрямую. (См. документацию Vite).

{* ✓ This works - it's an entry point *}
{asset 'app.js'}

{* ✓ This works - it's in assets/public/ *}
{asset 'favicon.ico'}

{* ✗ This won't work - random file in 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'}
{* In development: <script src="http://localhost:5173/app.js" type="module"></script> *}
{* In production: <script src="/assets/app-4a8f9c7.js" type="module"></script> *}

Никакой настройки не требуется – просто работает!

Работа на разных доменах

Если ваш сервер разработки работает на чем-то другом, кроме localhost (например, myapp.local), вы можете столкнуться с проблемами CORS (Cross-Origin Resource Sharing). CORS – это функция безопасности в веб-браузерах, которая по умолчанию блокирует запросы между разными доменами. Когда ваше PHP-приложение работает на myapp.local, а Vite – на localhost:5173, браузер видит их как разные домены и блокирует запросы.

У вас есть два варианта решения этой проблемы:

Вариант 1: Настройте CORS

Самое простое решение – разрешить кросс-доменные запросы из вашего PHP-приложения:

export default defineConfig({
	// ... other config ...

	server: {
		cors: {
			origin: 'http://myapp.local',  // your PHP app URL
		},
	},
});

Вариант 2: Запустите Vite на своем домене

Другое решение – запустить Vite на том же домене, что и ваше PHP-приложение.

export default defineConfig({
	// ... other config ...

	server: {
		host: 'myapp.local',  // same as your PHP app
	},
});

На самом деле, даже в этом случае вам нужно настроить 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({
	// ... other config ...

	plugins: [
		mkcert(),  // generates certificates automatically and enables https
		nette(),
	],
});

Обратите внимание, что если вы используете конфигурацию CORS (Вариант 1 выше), вам нужно обновить URL источника, чтобы использовать https:// вместо http://.

Производственные сборки

Создайте оптимизированные файлы для продакшена:

npm run build

Vite будет:

  • Минифицировать весь JavaScript и CSS
  • Разделять код на оптимальные чанки
  • Генерировать хэшированные имена файлов для обхода кэша
  • Создавать файл манифеста для Nette Assets

Пример вывода:

www/assets/
├── app-4f3a2b1c.js       # Your main JavaScript (minified)
├── app-7d8e9f2a.css      # Extracted CSS (minified)
├── vendor-8c4b5e6d.js    # Shared dependencies
└── .vite/
	└── manifest.json     # Mapping for Nette Assets

Хэшированные имена файлов гарантируют, что браузеры всегда загружают последнюю версию.

Публичная папка

Файлы в каталоге assets/public/ копируются в выходной каталог без обработки:

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

Ссылайтесь на них как обычно:

{* These files are copied as-is *}
<link rel="icon" href={asset 'favicon.ico'}>
<meta property="og:image" content={asset 'images/og-image.jpg'}>

Для публичных файлов вы можете использовать функции FilesystemMapper:

assets:
	mapping:
		default:
			type: vite
			path: assets
			extension: [webp, jpg, png]  # Try WebP first
			versioning: true             # Add cache-busting

В конфигурации vite.config.ts вы можете изменить публичную папку с помощью опции publicDir.

Динамические импорты

Vite автоматически разделяет код для оптимальной загрузки. Динамические импорты позволяют загружать код только тогда, когда он действительно нужен, уменьшая начальный размер бандла:

// Load heavy components on demand
button.addEventListener('click', async () => {
	let { Chart } = await import('./components/chart.js')
	new Chart(data)
})

Динамические импорты создают отдельные чанки, которые загружаются только при необходимости. Это называется “разделением кода”, и это одна из самых мощных функций Vite. Когда вы используете динамические импорты, Vite автоматически создает отдельные JavaScript-файлы для каждого динамически импортированного модуля.

Тег {asset 'app.js'} не автоматически предварительно загружает эти динамические чанки. Это преднамеренное поведение – мы не хотим загружать код, который может никогда не быть использован. Чанки загружаются только тогда, когда выполняется динамический импорт.

Однако, если вы знаете, что определенные динамические импорты критически важны и потребуются в ближайшее время, вы можете предварительно загрузить их:

{* Main entry point *}
{asset 'app.js'}

{* Preload critical dynamic imports *}
{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 directory containing source assets
	root: 'assets',

	// Folder whose contents are copied to output directory as-is
	// Default: 'public' (relative to 'root')
	publicDir: 'public',

	build: {
		// Where to put compiled files (relative to 'root')
		outDir: '../www/assets',

		// Empty output directory before building?
		// Useful to remove old files from previous builds
		emptyOutDir: true,

		// Subdirectory within outDir for generated chunks and assets
		// This helps organize the output structure
		assetsDir: 'static',

		rollupOptions: {
			// Entry point(s) - can be a single file or array of files
			// Each entry point becomes a separate bundle
			input: [
				'app.js',      // main application
				'admin.js',    // admin panel
			],
		},
	},

	server: {
		// Host to bind the dev server to
		// Use '0.0.0.0' to expose to network
		host: 'localhost',

		// Port for the dev server
		port: 5173,

		// CORS configuration for cross-origin requests
		cors: {
			origin: 'http://myapp.local',
		},
	},

	css: {
		// Enable CSS source maps in development
		devSourcemap: true,
	},

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

Вот и все! Теперь у вас есть современная система сборки, интегрированная с Nette Assets.

версия: 1.0