| 1 |
# vp-wp |
| 2 |
|
| 3 |
[](https://github.com/nabasa-dev/vp-wp/actions/workflows/ci.yml](https://github.com/nabasa-dev/vp-wp/actions/workflows/ci.yml](https://github.com/nabasa-dev/vp-wp/actions/workflows/ci.yml) |
| 4 |
[](https://www.npmjs.com/package/@nabasa/vp-wp](https://www.npmjs.com/package/@nabasa/vp-wp](https://www.npmjs.com/package/@nabasa/vp-wp) |
| 5 |
[](https://www.npmjs.com/package/@nabasa/vp-wp](https://www.npmjs.com/package/@nabasa/vp-wp](https://www.npmjs.com/package/@nabasa/vp-wp) |
| 6 |
[](https://packagist.org/packages/nabasa/vp-wp](https://packagist.org/packages/nabasa/vp-wp](https://packagist.org/packages/nabasa/vp-wp) |
| 7 |
[](https://packagist.org/packages/nabasa/vp-wp](https://packagist.org/packages/nabasa/vp-wp](https://packagist.org/packages/nabasa/vp-wp) |
| 8 |
[](https://pkg.pr.new/~/nabasa-dev/vp-wp](https://pkg.pr.new/~/nabasa-dev/vp-wp](https://pkg.pr.new/~/nabasa-dev/vp-wp) |
| 9 |
[](https://github.com/nabasa-dev/vp-wp/blob/main/LICENSE](https://github.com/nabasa-dev/vp-wp/blob/main/LICENSE](https://github.com/nabasa-dev/vp-wp/blob/main/LICENSE) |
| 10 |
|
| 11 |
`vp-wp` brings a modern Vite+ workflow to WordPress plugins and themes. |
| 12 |
|
| 13 |
Use it to build and serve frontend assets with WordPress-friendly defaults, a compact TypeScript API, and a lightweight PHP runtime. |
| 14 |
|
| 15 |
## Install |
| 16 |
|
| 17 |
Install the JavaScript package with Vite+: |
| 18 |
|
| 19 |
```sh |
| 20 |
vp add -D vite-plus @nabasa/vp-wp |
| 21 |
``` |
| 22 |
|
| 23 |
If you also want the PHP runtime helpers through Composer: |
| 24 |
|
| 25 |
```sh |
| 26 |
composer require nabasa/vp-wp |
| 27 |
``` |
| 28 |
|
| 29 |
If you are not using Composer, copy `vp-wp.php` into your plugin or theme and require it manually. |
| 30 |
|
| 31 |
## Migration |
| 32 |
|
| 33 |
Moving from `@kucrut/vite-for-wp`? See [](docs/migrating-from-vite-for-wp.md`docs/migrating-from-vite-for-wp.md`](docs/migrating-from-vite-for-wp.md](docs/migrating-from-vite-for-wp.md). |
| 34 |
|
| 35 |
## Vite+ config |
| 36 |
|
| 37 |
A minimal Vite+ config looks like this: |
| 38 |
|
| 39 |
```ts |
| 40 |
import { defineConfig } from "vite-plus"; |
| 41 |
import { wordpress, wordpressExternals } from "@nabasa/vp-wp"; |
| 42 |
|
| 43 |
export default defineConfig({ |
| 44 |
plugins: [ |
| 45 |
wordpress({ |
| 46 |
entry: { |
| 47 |
app: "resources/app.ts", |
| 48 |
}, |
| 49 |
outDir: "assets/dist", |
| 50 |
}), |
| 51 |
wordpressExternals(), |
| 52 |
], |
| 53 |
}); |
| 54 |
``` |
| 55 |
|
| 56 |
Then run the usual Vite+ commands: |
| 57 |
|
| 58 |
```sh |
| 59 |
vp dev |
| 60 |
vp build |
| 61 |
``` |
| 62 |
|
| 63 |
`wordpress()` applies WordPress-friendly defaults: |
| 64 |
|
| 65 |
- `base: './'` |
| 66 |
- `build.manifest: 'manifest.json'` |
| 67 |
- `build.modulePreload: false` |
| 68 |
- `css.devSourcemap: true` |
| 69 |
- a development manifest at `vite-dev-server.json` |
| 70 |
|
| 71 |
These defaults keep asset URLs, manifests, and CSS handling aligned with WordPress expectations. |
| 72 |
|
| 73 |
`wordpressExternals()` keeps common WordPress globals out of your bundle and treats React as external by default. |
| 74 |
|
| 75 |
## PHP runtime |
| 76 |
|
| 77 |
A typical enqueue setup looks like this: |
| 78 |
|
| 79 |
```php |
| 80 |
<?php |
| 81 |
|
| 82 |
use function Nabasa\VitePlus\assets; |
| 83 |
|
| 84 |
$vite = assets( __DIR__ . '/assets/dist' ); |
| 85 |
|
| 86 |
add_action( 'wp_enqueue_scripts', function () use ( $vite ): void { |
| 87 |
$vite->enqueue( |
| 88 |
'resources/app.ts', |
| 89 |
[ |
| 90 |
'handle' => 'my-plugin-app', |
| 91 |
'dependencies' => [ 'react', 'react-dom' ], |
| 92 |
'in_footer' => true, |
| 93 |
] |
| 94 |
); |
| 95 |
} ); |
| 96 |
``` |
| 97 |
|
| 98 |
Exposed PHP runtime API: |
| 99 |
|
| 100 |
Supported public API: |
| 101 |
|
| 102 |
- `Nabasa\VitePlus\assets()` creates a reusable `Assets` helper. |
| 103 |
- `Nabasa\VitePlus\register_asset()` registers an entry and extracted CSS. |
| 104 |
- `Nabasa\VitePlus\enqueue_asset()` registers and enqueues an entry. |
| 105 |
- `Nabasa\VitePlus\asset_url()` resolves a public asset URL. |
| 106 |
- `Nabasa\VitePlus\Assets::__construct()` creates the helper directly. |
| 107 |
- `Nabasa\VitePlus\Assets::manifest_dir()` gets the bound manifest directory. |
| 108 |
- `Nabasa\VitePlus\Assets::scope()` gets the normalized scope. |
| 109 |
- `Nabasa\VitePlus\Assets::register()` registers an entry. |
| 110 |
- `Nabasa\VitePlus\Assets::enqueue()` registers and enqueues an entry. |
| 111 |
- `Nabasa\VitePlus\Assets::url()` resolves an asset URL. |
| 112 |
|
| 113 |
Advanced callable helpers: |
| 114 |
|
| 115 |
- `Nabasa\VitePlus\filter_value()` applies shared and scoped filters. |
| 116 |
- `Nabasa\VitePlus\normalize_scope()` sanitizes a hook scope. |
| 117 |
- `Nabasa\VitePlus\get_manifest()` loads and caches manifest data. |
| 118 |
- `Nabasa\VitePlus\parse_options()` merges options with defaults. |
| 119 |
- `Nabasa\VitePlus\default_asset_handle()` generates a default handle. |
| 120 |
- `Nabasa\VitePlus\stylesheet_handle()` generates a deterministic style handle. |
| 121 |
- `Nabasa\VitePlus\prepare_asset_url()` builds a manifest base URL. |
| 122 |
- `Nabasa\VitePlus\join_asset_url()` joins a base URL and asset path. |
| 123 |
|
| 124 |
Internal and compatibility helpers: |
| 125 |
|
| 126 |
- `Nabasa\VitePlus\load_development_asset()` |
| 127 |
- `Nabasa\VitePlus\load_production_asset()` |
| 128 |
- `Nabasa\VitePlus\register_stylesheets()` |
| 129 |
- `Nabasa\VitePlus\register_vite_client_script()` |
| 130 |
- `Nabasa\VitePlus\inject_react_refresh_preamble()` |
| 131 |
- `Nabasa\VitePlus\development_asset_src()` |
| 132 |
- `Nabasa\VitePlus\filter_script_tag()` |
| 133 |
- `Nabasa\VitePlus\set_script_type_attribute()` |
| 134 |
- `Nabasa\VitePlus\should_inject_react_refresh()` |
| 135 |
- `Nabasa\VitePlus\string_ends_with()` |
| 136 |
|
| 137 |
Core PHP filters: |
| 138 |
|
| 139 |
- `nabasa_vite_plus/manifest_data` |
| 140 |
- `nabasa_vite_plus/development_assets` |
| 141 |
- `nabasa_vite_plus/production_assets` |
| 142 |
- `nabasa_vite_plus/{scope}/manifest_data` |
| 143 |
- `nabasa_vite_plus/{scope}/development_assets` |
| 144 |
- `nabasa_vite_plus/{scope}/production_assets` |
| 145 |
|
| 146 |
Use `assets()` when you want to bind a manifest directory once and reuse it across hooks or callbacks: |
| 147 |
|
| 148 |
```php |
| 149 |
<?php |
| 150 |
|
| 151 |
use function Nabasa\VitePlus\assets; |
| 152 |
|
| 153 |
$vite = assets( __DIR__ . '/assets/dist' ); |
| 154 |
|
| 155 |
add_action( 'wp_enqueue_scripts', function () use ( $vite ): void { |
| 156 |
$vite->enqueue( 'resources/app.ts', [ |
| 157 |
'handle' => 'theme-app', |
| 158 |
] ); |
| 159 |
} ); |
| 160 |
``` |
| 161 |
|
| 162 |
Pass a second argument to `assets()` when you want a plugin- or theme-specific hook namespace: |
| 163 |
|
| 164 |
```php |
| 165 |
<?php |
| 166 |
|
| 167 |
use function Nabasa\VitePlus\assets; |
| 168 |
|
| 169 |
$vite = assets( __DIR__ . '/assets/dist', 'windpress' ); |
| 170 |
|
| 171 |
add_filter( 'nabasa_vite_plus/windpress/production_assets', function ( array $assets ) { |
| 172 |
return $assets; |
| 173 |
} ); |
| 174 |
``` |
| 175 |
|
| 176 |
Scoped helpers still trigger the shared `nabasa_vite_plus/*` hooks as well as the scoped `nabasa_vite_plus/{scope}/*` hooks. The scope is normalized with `sanitize_key()`. |
| 177 |
|
| 178 |
If you prefer standalone functions, `register_asset()` and `enqueue_asset()` accept the same scope as a fourth argument. |
| 179 |
|
| 180 |
Supported PHP options include: |
| 181 |
|
| 182 |
- `handle` |
| 183 |
- `dependencies` |
| 184 |
- `css_dependencies` |
| 185 |
- `css_media` |
| 186 |
- `css_only` |
| 187 |
- `in_footer` |
| 188 |
|
| 189 |
During `vp dev`, `vp-wp` reads `vite-dev-server.json` and serves assets from the active dev server. During `vp build`, it reads `manifest.json` and registers the compiled JavaScript and extracted CSS assets. |
| 190 |
|
| 191 |
Use `asset_url()` when you need the public URL for a file in the built assets directory without looking it up in the manifest: |
| 192 |
|
| 193 |
```php |
| 194 |
<?php |
| 195 |
|
| 196 |
use function Nabasa\VitePlus\asset_url; |
| 197 |
|
| 198 |
$logo_url = asset_url( __DIR__ . '/assets/dist', 'images/logo.svg' ); |
| 199 |
``` |
| 200 |
|
| 201 |
## Externals presets |
| 202 |
|
| 203 |
Pick a preset when you want tighter control over which globals stay external: |
| 204 |
|
| 205 |
```ts |
| 206 |
wordpressExternals({ preset: "wordpress" }); |
| 207 |
``` |
| 208 |
|
| 209 |
Built-in presets: |
| 210 |
|
| 211 |
- `wordpress` |
| 212 |
- `wordpress+react` |
| 213 |
|
| 214 |
You can also extend or trim the externals map to fit your project: |
| 215 |
|
| 216 |
```ts |
| 217 |
wordpressExternals({ |
| 218 |
include: { |
| 219 |
"@acme/ui": "AcmeUI", |
| 220 |
}, |
| 221 |
exclude: ["lodash"], |
| 222 |
}); |
| 223 |
``` |
| 224 |
|
| 225 |
## Development |
| 226 |
|
| 227 |
```sh |
| 228 |
vp install |
| 229 |
vp check |
| 230 |
vp test |
| 231 |
vp pack |
| 232 |
``` |
| 233 |
|
| 234 |
## Credits |
| 235 |
|
| 236 |
`vp-wp` is a fork and rewrite inspired by [](https://github.com/kucrut/vite-for-wp`@kucrut/vite-for-wp`](https://github.com/kucrut/vite-for-wp](https://github.com/kucrut/vite-for-wp). |
| 237 |
|
| 238 |
## Examples |
| 239 |
|
| 240 |
Need a working reference? See [](examples/README.md`examples/README.md`](examples/README.md](examples/README.md) for React, Vue, Svelte, SolidJS, and vanilla JavaScript. Each example includes the full plugin structure, Vite config, PHP bootstrap, and frontend entry for its framework. |
| 241 |
|