Skip to content

Commit 692de3b

Browse files
committed
readme: rewrote as a full feature overview
Documents every plugin option (entry, refresh, host, appUrl, infoFile), the Vite defaults the plugin injects, dev-mode detection via the info file, and the CORS/Docker/proxy/network recipes.
1 parent a14a3cc commit 692de3b

1 file changed

Lines changed: 277 additions & 11 deletions

File tree

readme.md

Lines changed: 277 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,290 @@
1-
# Vite Plugin for Nette
1+
Vite Plugin for Nette
2+
=====================
23

3-
A Vite plugin that integrates [Vite](https://vite.dev) with [Nette](https://nette.org) & [Latte](https://latte.nette.org) for seamless asset management and development workflow.
4+
[![npm version](https://img.shields.io/npm/v/@nette/vite-plugin.svg)](https://www.npmjs.com/package/@nette/vite-plugin)
5+
[![Downloads this Month](https://img.shields.io/npm/dm/@nette/vite-plugin.svg)](https://www.npmjs.com/package/@nette/vite-plugin)
6+
[![Tests](https://github.com/nette/vite-plugin/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/vite-plugin/actions)
7+
![License](https://img.shields.io/npm/l/@nette/vite-plugin.svg)
48

5-
For detailed setup instructions and configuration options, see the [official Nette documentation](https://doc.nette.org/en/assets/vite).
9+
The missing link between [Vite](https://vite.dev) and [Nette](https://nette.org). Write `{asset 'app.js'}` in your Latte template and forget about the rest: in development the browser gets the file straight from the Vite dev server with Hot Module Replacement, in production it gets the hashed, minified, code-split bundle. Same template, no `if` statements, no manual URLs.
610

7-
## Installation
11+
```latte
12+
{asset 'app.js'}
813
9-
```bash
10-
npm install -D @nette/vite-plugin
14+
{* dev: <script src="http://localhost:5173/@vite/client" type="module"></script>
15+
<script src="http://localhost:5173/app.js" type="module"></script> *}
16+
{* prod: <script src="/assets/app-4f3a2b1c.js" type="module" crossorigin></script> *}
1117
```
1218

13-
## Usage
19+
Why you want it
20+
---------------
1421

15-
Add the plugin to your `vite.config.js`:
22+
- **Sensible defaults**: the standard Nette project layout is assumed, so there is almost nothing left to configure.
23+
- **Automatic dev-mode detection**: start `npm run dev` and PHP picks it up by itself. Stop it, and templates fall back to the production build. Nothing to switch, nothing to remember.
24+
- **Hot Module Replacement**: instant CSS and JavaScript updates without losing application state.
25+
- **Full reload for Latte and PHP**: templates live outside Vite's module graph, so the plugin watches them for you and reloads the page on change.
26+
- **CORS that just works**: the PHP app and the dev server always differ in port, often in scheme and host too. The plugin figures out the right allowed origins so the browser never blocks your assets.
27+
- **Ready for Docker, reverse proxies, HTTPS and your phone**: the awkward setups are covered, usually by a single option.
28+
- **Glob entry points**: `entry: 'entries/*.ts'` instead of a hand-maintained list.
29+
- **Clean shutdown**: the dev-server marker file is removed on Ctrl+C, on kill, and even before a production build, so PHP is never fooled by a stale one.
30+
31+
32+
Installation
33+
------------
34+
35+
```shell
36+
npm install -D vite @nette/vite-plugin
37+
```
38+
39+
Works with Vite 6.2+, 7 and 8, on whichever Node.js version your Vite requires (glob patterns in `entry` additionally need Node.js 22+). On the PHP side you need [nette/assets](https://github.com/nette/assets).
40+
41+
42+
Quick Start
43+
-----------
44+
45+
**1.** Put your source files in `assets/` and let them compile into `www/assets/`:
46+
47+
```
48+
web-project/
49+
├── assets/ ← source files (SCSS, TypeScript, images)
50+
│ ├── public/ ← static files, copied as-is
51+
│ ├── app.js ← entry point
52+
│ └── style.css
53+
└── www/ ← document root
54+
├── assets/ ← compiled output lands here
55+
└── index.php
56+
```
57+
58+
**2.** Create `vite.config.ts` in the project root:
59+
60+
```js
61+
import { defineConfig } from 'vite';
62+
import nette from '@nette/vite-plugin';
63+
64+
export default defineConfig({
65+
plugins: [
66+
nette({
67+
entry: 'app.js',
68+
}),
69+
],
70+
});
71+
```
72+
73+
**3.** Tell Nette Assets to use the Vite mapper in `common.neon`:
74+
75+
```neon
76+
assets:
77+
mapping:
78+
default:
79+
type: vite
80+
path: assets
81+
```
82+
83+
**4.** Add the scripts to `package.json`:
84+
85+
```json
86+
{
87+
"scripts": {
88+
"dev": "vite",
89+
"build": "vite build"
90+
}
91+
}
92+
```
93+
94+
Now `npm run dev` gives you HMR and `npm run build` gives you an optimized production bundle. In your templates just write `{asset 'app.js'}` and Nette Assets generates every tag needed: JavaScript, extracted CSS, preloads and all.
95+
96+
97+
What the plugin configures for you
98+
----------------------------------
99+
100+
You can override any of these in your own Vite config; the plugin only fills in what you did not set.
101+
102+
| Option | Value | Why |
103+
|---|---|---|
104+
| `root` | `assets` | source files live outside the document root |
105+
| `build.outDir` | `www/assets` | compiled files must be publicly reachable |
106+
| `build.assetsDir` | `''` | output lands directly in `outDir`, no `static/` subfolder |
107+
| `build.manifest` | `true` | Nette Assets maps hashed filenames through it |
108+
| `base` | `''` | assets are served straight from the document root |
109+
| `server.cors` | app origin allowed | the browser would otherwise refuse dev assets |
110+
| `server.allowedHosts` | the configured host, when it isn't `localhost` | works behind a proxy out of the box |
111+
| `server.origin` | the dev server URL | Vite rewrites asset URLs to itself, not to the backend |
112+
113+
The default `outDir` requires an existing `www/` directory. If it is missing, the plugin stops with a clear error instead of quietly building into the wrong place.
114+
115+
116+
Configuration
117+
-------------
118+
119+
All options are optional.
120+
121+
| Option | Type | Default | Description |
122+
|---|---|---|---|
123+
| `entry` | `string \| string[]` || entry point(s), relative to `root`, glob patterns allowed |
124+
| `refresh` | `string \| string[]` || globs that trigger a full page reload (Latte, PHP) |
125+
| `host` | `string` || host advertised to the browser, or `'network'` for the LAN IP |
126+
| `appUrl` | `string` || URL of your PHP application, used for CORS |
127+
| `infoFile` | `string` | `.vite/nette.json` | dev-server marker file, relative to `outDir` |
128+
129+
130+
### Entry Points
131+
132+
An entry point is where your application starts; Vite follows its imports and bundles everything it finds.
133+
134+
```js
135+
nette({
136+
entry: [
137+
'app.js', // public pages
138+
'admin.js', // admin panel
139+
],
140+
})
141+
```
142+
143+
Insert them in the templates that need them: `{asset 'app.js'}` in the layout, `{asset 'admin.js'}` in the admin one.
144+
145+
When every entry point lives in its own directory, use a glob instead of a hand-written list. It is expanded relative to `root` and needs Node.js 22+:
146+
147+
```js
148+
nette({
149+
entry: 'entries/*.ts', // all .ts files in assets/entries/
150+
})
151+
```
152+
153+
Unlike raw `rollupOptions.input`, paths in `entry` are resolved against `root`, so a plain `'app.js'` means `assets/app.js`, which is what you would expect.
154+
155+
156+
### Auto-Reloading on Template Changes
157+
158+
Vite's HMR only sees files in its own module graph. Latte templates and PHP files are not in it, so editing them does nothing in the browser until you reload by hand. Give the `refresh` option a glob and the plugin reloads the page for you:
159+
160+
```js
161+
nette({
162+
entry: 'app.js',
163+
refresh: ['app/**/*.latte', 'app/**/*.php'],
164+
})
165+
```
166+
167+
Patterns are matched against the whole project, not just `root`, and additions, changes and deletions all count.
168+
169+
170+
### Development Mode Detection
171+
172+
While the dev server runs, the plugin writes a small JSON file `www/assets/.vite/nette.json` containing its URL. Nette Assets reads it and switches to the dev server whenever both the file exists **and** the application is in debug mode. No environment variables, no flags in your config.
173+
174+
The file is deleted when the server stops (Ctrl+C, `SIGTERM`, on Windows also Ctrl+Break), and a leftover one from a crashed process is removed before every production build, so a build is never shadowed by a stale "dev server is running" marker. It also carries the pid and a timestamp, so a consumer can recognize a file left behind by a crashed dev server.
175+
176+
If the location clashes with something in your project, rename it with the `infoFile` option.
177+
178+
179+
### Working on Different Domains
180+
181+
If your PHP application is served from `https://myapp.local` while Vite runs on `localhost:5173`, the browser treats them as different origins and blocks the requests. Tell the plugin where the application lives and it allows that origin over http or https on any port:
16182

17183
```js
18-
import { defineConfig } from 'vite'
19-
import nette from '@nette/vite-plugin'
184+
nette({
185+
entry: 'app.js',
186+
appUrl: 'https://myapp.local',
187+
})
188+
```
189+
190+
If you prefer to run Vite on the very same hostname as your app, set `host` instead. CORS for the differing port is then configured automatically, and the host is whitelisted in `allowedHosts` too:
191+
192+
```js
193+
nette({ host: 'myapp.local' })
194+
```
20195

196+
197+
### Docker
198+
199+
Publish the Vite port from the container and bind the dev server to all interfaces:
200+
201+
```js
21202
export default defineConfig({
22-
plugins: [nette()]
203+
plugins: [nette({ entry: 'app.js' })],
204+
server: {
205+
host: '0.0.0.0',
206+
port: 5173,
207+
strictPort: true,
208+
watch: {
209+
usePolling: true, // if changes on mounted volumes go unnoticed
210+
},
211+
},
212+
});
213+
```
214+
215+
`0.0.0.0` is not an address a browser can use, so the plugin rewrites it to `localhost` in the published URL and assets keep loading. Opening the app on a custom domain? Add `nette({ host: 'myapp.local' })` and the host is used for the URL, the CORS origins and `allowedHosts` at once.
216+
217+
For a reverse proxy where the public host, port and protocol all differ from the internal socket, set Vite's `server.origin` to the full public URL. The plugin respects it and publishes it as-is:
218+
219+
```js
220+
server: {
221+
origin: 'https://myapp.local:8443',
222+
}
223+
```
224+
225+
226+
### Testing on Other Devices
227+
228+
Set `host` to the `'network'` sentinel. The plugin binds Vite to all interfaces and advertises your machine's LAN IP instead of `localhost`, so assets and HMR work when you open the app from a phone or tablet on the same network:
229+
230+
```js
231+
nette({
232+
entry: 'app.js',
233+
host: 'network',
23234
})
24235
```
236+
237+
If no external address is found, it falls back to `localhost`.
238+
239+
240+
### HTTPS
241+
242+
Generate certificates automatically with `vite-plugin-mkcert`. The plugin notices `server.https` and publishes an `https://` URL:
243+
244+
```js
245+
import mkcert from 'vite-plugin-mkcert';
246+
247+
export default defineConfig({
248+
plugins: [
249+
mkcert(),
250+
nette({ entry: 'app.js' }),
251+
],
252+
});
253+
```
254+
255+
256+
Production Builds
257+
-----------------
258+
259+
```shell
260+
npm run build
261+
```
262+
263+
Vite minifies JavaScript and CSS, splits the code into optimal chunks, hashes filenames for cache busting and writes the manifest that Nette Assets reads:
264+
265+
```
266+
www/assets/
267+
├── app-4f3a2b1c.js # your JavaScript, minified
268+
├── app-7d8e9f2a.css # extracted CSS
269+
├── vendor-8c4b5e6d.js # shared dependencies
270+
└── .vite/
271+
└── manifest.json # mapping for Nette Assets
272+
```
273+
274+
Files placed in `assets/public/` are copied over untouched and remain reachable by `{asset 'favicon.ico'}` through a filesystem fallback.
275+
276+
277+
Documentation
278+
-------------
279+
280+
The complete guide (project structure, `{asset}` and `{preload}` in templates, the public folder, dynamic imports, TypeScript) lives at **[doc.nette.org/en/assets/vite](https://doc.nette.org/en/assets/vite)**.
281+
282+
283+
Support Me
284+
----------
285+
286+
Do you like the Nette Vite plugin? Are you looking forward to the new features?
287+
288+
[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
289+
290+
Thank you!

0 commit comments

Comments
 (0)