@10up/wp-vite-plugins 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,263 @@
1
+ # @10up/wp-vite-plugins
2
+
3
+ Vite plugins for building modern WordPress projects the 10up way.
4
+
5
+ A focused set of Vite plugins that handle what WordPress projects actually need: `block.json` discovery, `@wordpress/*` externals with `.asset.php` emission, per-block style entries, and static asset copying.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install --save-dev @10up/wp-vite-plugins
11
+ ```
12
+
13
+ Requires Node ≥ 20.11 and Vite ^8 (Rolldown-powered).
14
+
15
+ ### Vite+ / Rolldown compatibility
16
+
17
+ The plugins use only Rolldown-implemented plugin APIs, so they work unchanged with [Vite+](https://viteplus.dev) — `vp dev`, `vp build`, and `vp build --mode modules` read the same `vite.config.ts` and produce identical output to plain `vite` commands. The test suite runs under `vp test` (Vitest) as well.
18
+
19
+ ## Quick start
20
+
21
+ The `wp()` composer covers the common case. Point it at your block directory and you're done:
22
+
23
+ ```ts
24
+ import { defineConfig } from 'vite';
25
+ import { wp } from '@10up/wp-vite-plugins';
26
+
27
+ export default defineConfig({
28
+ plugins: [
29
+ wp({
30
+ blocksDir: './includes/blocks',
31
+ blocksStylesDir: './assets/css/blocks',
32
+ copyAssetsDir: './assets',
33
+ }),
34
+ ],
35
+ });
36
+ ```
37
+
38
+ That single call wires up:
39
+
40
+ - **`wpBlocks`** — discovers every `block.json`, turns `file:` references into Rollup entries, copies `block.json` + sibling PHP into `dist/`, and emits `blocks-manifest.php` (WP 6.7+).
41
+ - **`wpBlockStyles`** — emits each stylesheet under `blocksStylesDir` as its own CSS entry for selective PHP enqueueing.
42
+ - **`wpCopyAssets`** — copies images / fonts / SVG from `copyAssetsDir` to `dist/`.
43
+ - **`wpAdminPages`** — builds `@wordpress/boot` admin pages from `adminPagesDir` in the module pass (`content` / `route` entries, `loader.js` anchor, per-page `content.css`), and optionally generates the whole `@wordpress/build`-style PHP registration layer.
44
+ - **`wpExternals`** — rewrites `@wordpress/*` imports against `window.wp.*` (or preserves them as ESM in module mode) and emits `<entry>.asset.php` dependency sidecars.
45
+ - **`wpScriptIife`** _(auto)_ — wraps script-mode entries in an IIFE so they enqueue cleanly as classic `<script>` tags.
46
+ - **`wpCleanCssChunks`** _(auto)_ — deletes the empty JS shims Vite leaves next to CSS-only entries.
47
+
48
+ ## Wrapper options
49
+
50
+ ```ts
51
+ wp({
52
+ // Build mode for all sub-plugins. Default: 'script'.
53
+ buildType: 'script', // or 'module'
54
+
55
+ // Top-level shortcuts — pass a directory to enable the plugin.
56
+ blocksDir: './includes/blocks',
57
+ blocksStylesDir: './assets/css/blocks',
58
+ copyAssetsDir: './assets',
59
+ adminPagesDir: './assets/js/admin-pages',
60
+
61
+ // Per-plugin escape hatches. Nested wins on conflict. Pass `false` to disable entirely.
62
+ blocks: { skip: ['legacy-block'] },
63
+ blockStyles: { /* extra WpBlockStylesOptions */ },
64
+ copyAssets: { pattern: '**/*.{png,svg}' },
65
+ adminPages: { php: {} }, // `php` turns on PHP generation; see docs/wp-admin-pages.md
66
+ externals: {
67
+ scriptModuleNamespaces: ['ignite-*'],
68
+ additionalExternals: { myLib: { global: 'MyLib', handle: 'my-lib' } },
69
+ },
70
+
71
+ // Helper opt-outs.
72
+ iife: false, // disable wpScriptIife (script mode only)
73
+ cleanCssChunks: false, // disable wpCleanCssChunks (always on by default)
74
+ });
75
+ ```
76
+
77
+ `externals` is always included unless you pass `externals: false`. The other four are included only when their directory option is provided (top-level or nested). See [docs/wp.md](./docs/wp.md) for the full inclusion and option-merging rules.
78
+
79
+ ## Dual-pass builds (script + module)
80
+
81
+ For projects that ship both classic scripts and Script Modules, dispatch on Vite's `mode`:
82
+
83
+ ```ts
84
+ export default defineConfig(({ mode }) => ({
85
+ plugins: [
86
+ wp({
87
+ buildType: mode === 'modules' ? 'module' : 'script',
88
+ blocksDir: './includes/blocks',
89
+ }),
90
+ ],
91
+ }));
92
+ ```
93
+
94
+ Run the two passes separately: `vite build` (default script mode) and `vite build --mode modules`. The module pass is safe to run unconditionally — when no block declares a `scriptModule` / `viewScriptModule` (and no other module entries are configured), `wpBlocks` turns it into a no-op build instead of letting Rollup error on empty input.
95
+
96
+ ## Using plugins individually
97
+
98
+ The wrapper is just sugar. Every plugin is exported on its own for finer control:
99
+
100
+ ```ts
101
+ import { defineConfig } from 'vite';
102
+ import {
103
+ wpBlocks,
104
+ wpBlockStyles,
105
+ wpCopyAssets,
106
+ wpAdminPages,
107
+ wpExternals,
108
+ wpScriptIife,
109
+ wpCleanCssChunks,
110
+ } from '@10up/wp-vite-plugins';
111
+
112
+ export default defineConfig({
113
+ plugins: [
114
+ wpBlocks({ blocksDir: './includes/blocks', buildType: 'script' }),
115
+ wpBlockStyles({ blocksStylesDir: './assets/css/blocks' }),
116
+ wpCopyAssets({ copyAssetsDir: './assets' }),
117
+ // Module pass only — a no-op with buildType: 'script'. Composed by hand,
118
+ // it needs a matching `wpBuildAssetMatchers` entry on wpExternals.
119
+ wpAdminPages({ adminPagesDir: './assets/js/admin-pages', buildType: 'module' }),
120
+ wpExternals({ buildType: 'script' }),
121
+ wpScriptIife(),
122
+ wpCleanCssChunks(),
123
+ ],
124
+ });
125
+ ```
126
+
127
+ ## Examples
128
+
129
+ Two runnable consumer projects live under [`examples/`](./examples/README.md), each with a WordPress Playground blueprint for end-to-end verification:
130
+
131
+ - [`examples/minimal-block-plugin`](./examples/minimal-block-plugin) — one plugin, one block, single-pass build.
132
+ - [`examples/scaffold-monorepo`](./examples/scaffold-monorepo) — a full [10up/wp-scaffold](https://github.com/10up/wp-scaffold)-style monorepo (classic theme, block theme, mu-plugin) building through npm workspaces, including a dual-pass Script Module build.
133
+
134
+ ## Plugins
135
+
136
+ The sections below are the quick reference. Each plugin also has an in-depth page under [`docs/`](./docs/README.md) covering internals, output formats, and caveats.
137
+
138
+ ### `wpBlocks(options)`
139
+
140
+ → [Full documentation](./docs/wp-blocks.md)
141
+
142
+ Scans `blocksDir` for `block.json` files. For each one:
143
+
144
+ - Discovers `file:`-prefixed assets and registers them as Rollup entries.
145
+ - Copies `block.json` (with `file:` references rewritten to `.js` / `.css`) and any sibling PHP files into `dist/blocks/<block-name>/`.
146
+ - Stamps a SHA-256 `version` hash on the block when no explicit version is set (hashes the source style content, not the built output).
147
+ - Emits `blocks-manifest.php` for `wp_register_block_types_from_metadata_collection` (WP 6.7+).
148
+
149
+ **Options**
150
+
151
+ | Option | Type | Default | Notes |
152
+ | --- | --- | --- | --- |
153
+ | `blocksDir` | `string` | (required) | Root directory containing `block.json` files. |
154
+ | `buildType` | `'script' \| 'module'` | `'script'` | Which `block.json` fields to discover as entries. |
155
+ | `emitManifest` | `boolean` | `true` | Emit `blocks-manifest.php`. |
156
+ | `skip` | `string[]` | `[]` | Block directory names (relative to `blocksDir`) to skip entirely. |
157
+
158
+ ### `wpExternals(options)`
159
+
160
+ → [Full documentation](./docs/wp-externals.md)
161
+
162
+ Decides which imports to externalize and emits `<entry>.asset.php` sidecars.
163
+
164
+ For `@wordpress/*` packages, the decision reads each package's *own* `package.json`:
165
+
166
+ - `wpScript: true` → classic script externalization (rewrites `import { foo } from '@wordpress/x'` to `const { foo } = window.wp.x` and lists `wp-x` as a dependency handle).
167
+ - `wpScriptModuleExports` → Script Module externalization (preserves the ESM import for WP's import map; lists the specifier in the sidecar's `module_dependencies`).
168
+ - Neither → bundle into the consumer's output (no special handling).
169
+
170
+ The sidecar comes in two shapes, chosen per entry, because WordPress core and boot-page PHP want irreconcilable things from the `dependencies` key:
171
+
172
+ - **Default (core-compatible):** module-mode `dependencies` stays the Script Module dependency list core reads, and the classic handles a module reads off `window.*` are added under a new `script_dependencies` key.
173
+ - **`wpBuildAssetMatchers` entries** (wired automatically by `wp()` for `adminPagesDir`): the `@wordpress/build` shape — `dependencies` = classic handles, `module_dependencies` = `array( 'id' => …, 'import' => … )` entries, omitted when empty.
174
+
175
+ For every entry, `version` now hashes the chunk code *and* its extracted CSS, and dependencies are unioned across the entry chunk and every chunk it imports, so shared chunks don't lose deps. See the [sidecar reference](./docs/wp-externals.md#the-assetphp-sidecar) and its [breaking-change note](./docs/wp-externals.md#breaking-change-pre-10).
176
+
177
+ For non-`@wordpress/*` packages, a hardcoded vendor map covers `react`, `react-dom`, `jquery`, `lodash`, `moment`. Pass `additionalExternals` to extend or replace that map.
178
+
179
+ **Options**
180
+
181
+ | Option | Type | Default | Notes |
182
+ | --- | --- | --- | --- |
183
+ | `projectRoot` | `string` | `process.cwd()` | Resolution root for `@wordpress/*` package metadata. |
184
+ | `buildType` | `'script' \| 'module'` | `'script'` | Controls import rewriting strategy. |
185
+ | `externalNamespaces` | `Record<string, ExternalNamespace>` | `{}` | Add classic-script externals for namespaces like `@woo/*`. |
186
+ | `additionalExternals` | `Record<string, { global, handle }>` | (vendor map) | Override the non-scoped vendor externals. |
187
+ | `moduleEntryMatchers` | `string[]` | `[]` | File path substrings that should be treated as module-mode regardless of `buildType`. |
188
+ | `wpBuildAssetMatchers` | `string[]` | `[]` | Entry source-path substrings whose `.asset.php` uses the `@wordpress/build` shape. |
189
+ | `scriptModuleNamespaces` | `string[]` | `[]` | Plugin-local Script Module namespaces (exact or `prefix-*` glob). |
190
+
191
+ ### `wpAdminPages(options)`
192
+
193
+ → [Full documentation](./docs/wp-admin-pages.md)
194
+
195
+ Builds [`@wordpress/boot`](https://github.com/WordPress/gutenberg/tree/trunk/packages/boot)-powered admin pages (WP 6.9+ Script Module admin screens) as part of the **module pass**, replacing a separate esbuild pipeline. Every immediate subdirectory of `adminPagesDir` with a `content` entry is a page:
196
+
197
+ ```
198
+ dist/modules/<page>/
199
+ ├── content.js # ESM entry
200
+ ├── content.asset.php # classic handles + module_dependencies + version
201
+ ├── content.css # extracted CSS imported by content.js
202
+ ├── route.js # ESM entry (optional per page)
203
+ ├── route.asset.php
204
+ ├── loader.js # generated empty anchor module
205
+ └── routes/<name>/ # additional routes, same files
206
+ ```
207
+
208
+ Entries containing JSX must use `.jsx` / `.tsx` — Vite doesn't parse JSX out of `.js`.
209
+
210
+ Pass `php: {}` and the plugin also generates the `@wordpress/build`-style PHP layer next to the modules — `build.php`, `constants.php`, `pages.php`, `pages/<slug>/page{,-wp-admin}.php`, `routes.php`, `routes/registry.php` — so a consuming plugin needs no hand-written PHP beyond `require_once __DIR__ . '/dist/build.php';`. Per-page `page.json` covers titles, menu registration, init modules, modes and REST preload. See [the reference](./docs/wp-admin-pages.md#generated-php); `AbstractBootAdminPage` stays a supported alternative.
211
+
212
+ **Options**
213
+
214
+ | Option | Type | Default | Notes |
215
+ | --- | --- | --- | --- |
216
+ | `adminPagesDir` | `string` | (required) | Directory whose immediate subdirectories are pages. |
217
+ | `buildType` | `'script' \| 'module'` | `'script'` | No-op in script mode; pages are Script Modules. |
218
+ | `php` | `WpAdminPagesPhpOptions` | (off) | Presence enables PHP generation (`prefix`, `handlePrefix`, `baseUrl`, `textdomain`). |
219
+ | `projectRoot` | `string` | Vite's `root` | `package.json` supplying the generated version / prefix defaults. |
220
+
221
+ Via `wp({ adminPagesDir })` the pages directory is also fed to `wpExternals`' `wpBuildAssetMatchers` so page sidecars get the `@wordpress/build` shape; set that option yourself when composing the plugins by hand.
222
+
223
+ ### `wpBlockStyles(options)`
224
+
225
+ → [Full documentation](./docs/wp-block-styles.md)
226
+
227
+ Every stylesheet under `blocksStylesDir` becomes a dedicated CSS entry under `dist/autoenqueue/<block-name>/<file>.css`. Lets PHP selectively enqueue per-block stylesheets without bundling.
228
+
229
+ **Options**
230
+
231
+ | Option | Type | Default | Notes |
232
+ | --- | --- | --- | --- |
233
+ | `blocksStylesDir` | `string` | (required) | Directory of per-block stylesheets. |
234
+
235
+ ### `wpCopyAssets(options)`
236
+
237
+ → [Full documentation](./docs/wp-copy-assets.md)
238
+
239
+ Copies static assets (images, fonts, SVG) from `copyAssetsDir` to `dist/`, preserving the relative path. So `assets/images/logo.svg` → `dist/images/logo.svg`.
240
+
241
+ **Options**
242
+
243
+ | Option | Type | Default | Notes |
244
+ | --- | --- | --- | --- |
245
+ | `copyAssetsDir` | `string` | (required) | Source directory. |
246
+ | `pattern` | `string` | `**/*.{jpg,jpeg,png,gif,webp,avif,ico,svg,eot,ttf,woff,woff2,otf}` | Glob, relative to `copyAssetsDir`. |
247
+ | `buildType` | `'script' \| 'module'` | `'script'` | Only runs in script mode (to avoid double-emission on dual-pass builds). |
248
+
249
+ ### `wpScriptIife()`
250
+
251
+ → [Full documentation](./docs/wp-script-iife.md)
252
+
253
+ Wraps each script-mode entry chunk in an IIFE in `writeBundle`. Avoids global-scope leaks when WP enqueues bundles as classic `<script>` tags. No options.
254
+
255
+ ### `wpCleanCssChunks()`
256
+
257
+ → [Full documentation](./docs/wp-clean-css-chunks.md)
258
+
259
+ Deletes the empty `.js` shim Vite emits next to a CSS-only entry. No options.
260
+
261
+ ## License
262
+
263
+ GPL-2.0-or-later. See [LICENSE](./LICENSE).
@@ -0,0 +1,231 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ /**
4
+ * Enables generation of the `@wordpress/build`-style PHP layer next to the
5
+ * built modules — `build.php`, `constants.php`, `pages.php`,
6
+ * `pages/<slug>/page{,-wp-admin}.php`, `routes.php` and
7
+ * `routes/registry.php`. A consuming plugin then needs no hand-written PHP
8
+ * beyond `require_once __DIR__ . '/dist/build.php';`.
9
+ */
10
+ interface WpAdminPagesPhpOptions {
11
+ /**
12
+ * Identifier prefix for every generated function, global and hook.
13
+ * Default: `wpPlugin.name` from the consumer's package.json, else its
14
+ * (de-scoped) package name. Dashes are underscored for PHP identifiers;
15
+ * the result must be a valid PHP identifier fragment.
16
+ */
17
+ prefix?: string;
18
+ /**
19
+ * Script Module id prefix — route modules are registered as
20
+ * `<handlePrefix>/routes/<page>/<route>/{content,route}`.
21
+ * Default: `wpPlugin.handlePrefix`, else `prefix`.
22
+ */
23
+ handlePrefix?: string;
24
+ /**
25
+ * Raw PHP expression for the URL of the build directory, interpolated
26
+ * into `constants.php` verbatim. Default `plugin_dir_url( __FILE__ )`
27
+ * (`build.php` and friends live in the build directory itself).
28
+ */
29
+ baseUrl?: string;
30
+ /** Text domain for the generated `__()` calls. Default `'default'`. */
31
+ textdomain?: string;
32
+ }
33
+ interface WpAdminPagesOptions {
34
+ /**
35
+ * Directory whose immediate subdirectories are pages. A subdirectory is
36
+ * a page when it contains a `content.{tsx,ts,jsx,js}` entry; a sibling
37
+ * `route.{tsx,ts,jsx,js}` is picked up when present, as are additional
38
+ * routes under `<page>/routes/<name>/`.
39
+ */
40
+ adminPagesDir: string;
41
+ /**
42
+ * Admin pages are Script Modules, so they only build in the module pass.
43
+ * In `'script'` mode (the default, matching the other plugins) this
44
+ * plugin contributes nothing.
45
+ */
46
+ buildType?: 'script' | 'module';
47
+ /**
48
+ * Generate the PHP registration layer. Presence enables it; every key
49
+ * is optional.
50
+ */
51
+ php?: WpAdminPagesPhpOptions;
52
+ /**
53
+ * Root whose `package.json` supplies the generated `version` and the
54
+ * `wpPlugin.name` / `wpPlugin.handlePrefix` defaults. Defaults to Vite's
55
+ * `root`, else `process.cwd()`.
56
+ */
57
+ projectRoot?: string;
58
+ }
59
+ declare function wpAdminPages(options: WpAdminPagesOptions): Plugin;
60
+
61
+ interface WpBlocksOptions {
62
+ blocksDir: string;
63
+ buildType?: 'script' | 'module';
64
+ /**
65
+ * Emit `blocks-manifest.php` (returns one PHP array of all block.json
66
+ * contents). Lets PHP use `wp_register_block_types_from_metadata_collection`
67
+ * (WP 6.7+) instead of N filesystem reads + JSON parses on every request.
68
+ * Default: `true`.
69
+ */
70
+ emitManifest?: boolean;
71
+ /**
72
+ * Block directory names (relative to `blocksDir`) to skip entirely —
73
+ * neither discovered as entries nor included in the manifest.
74
+ */
75
+ skip?: string[];
76
+ }
77
+ declare function wpBlocks(options: WpBlocksOptions): Plugin;
78
+
79
+ interface WpBlockStylesOptions {
80
+ blocksStylesDir: string;
81
+ }
82
+ declare function wpBlockStyles(options: WpBlockStylesOptions): Plugin;
83
+
84
+ interface WpCopyAssetsOptions {
85
+ /** Source directory (default: `./assets`). */
86
+ copyAssetsDir: string;
87
+ /** Override the glob pattern (relative to `copyAssetsDir`). */
88
+ pattern?: string;
89
+ /** Only run during the script pass — module pass would emit duplicates. */
90
+ buildType?: 'script' | 'module';
91
+ }
92
+ declare function wpCopyAssets(options: WpCopyAssetsOptions): Plugin;
93
+
94
+ interface ExternalNamespace {
95
+ /** Window global path, e.g. `wp` for `@wordpress/*`, `woo` for `@woo/*`. */
96
+ global: string;
97
+ /** Script-handle prefix used in `.asset.php`. `wp` → `wp-block-editor`. */
98
+ handlePrefix: string;
99
+ }
100
+ interface WpExternalsOptions {
101
+ /**
102
+ * Project root used to resolve `@wordpress/*` (and other) package.jsons.
103
+ * Defaults to `process.cwd()`. Pass the absolute project root for
104
+ * deterministic resolution in monorepos / weird CWDs.
105
+ */
106
+ projectRoot?: string;
107
+ /**
108
+ * Additional namespaces to externalize. The metadata-driven path covers
109
+ * `@wordpress/*` automatically; this lets you add `woo`, `acme`, etc.
110
+ * as classic-script externals (no metadata read — global/handle config
111
+ * only).
112
+ */
113
+ externalNamespaces?: Record<string, ExternalNamespace>;
114
+ /**
115
+ * Non-scoped vendor externals (`react`, `jquery`, etc.). These don't
116
+ * carry WP metadata so we keep the hardcoded mapping. Pass `{}` to
117
+ * disable.
118
+ */
119
+ additionalExternals?: Record<string, {
120
+ global: string;
121
+ handle: string | null;
122
+ }>;
123
+ /**
124
+ * 'script' (default) rewrites `import { x } from '@wordpress/y'` into
125
+ * `const { x } = window.wp.y;` so the resulting bundle works as a
126
+ * classic <script>. `.asset.php` lists `wp-y`-style handles for
127
+ * `wp_register_script`.
128
+ *
129
+ * 'module' leaves ESM imports of Script-Module-eligible packages intact
130
+ * (resolved at runtime by WP's import map) for use with
131
+ * `wp_register_script_module` — required for the Interactivity API and
132
+ * Script Modules generally. `.asset.php` lists those specifiers under
133
+ * `module_dependencies` and includes `'type' => 'module'`. Script-only
134
+ * packages (`wpScript`, vendor globals) have no module form, so they're
135
+ * still rewritten to their `window.*` global with the classic handle
136
+ * recorded in `dependencies`.
137
+ */
138
+ buildType?: 'script' | 'module';
139
+ /**
140
+ * Substring matchers for file paths that should *always* be treated as
141
+ * `module`-mode regardless of the plugin-level `buildType`. Lets a
142
+ * single Vite dev server (which can only run one global mode at a time)
143
+ * still serve Script Module entries with their ESM imports intact.
144
+ *
145
+ * Example: `['/view.ts', '/view-module.ts', '/view-module.js']`
146
+ */
147
+ moduleEntryMatchers?: string[];
148
+ /**
149
+ * Substring matchers for entry *source* paths (the entry chunk's
150
+ * `facadeModuleId`) whose `.asset.php` should use the
151
+ * `@wordpress/build` shape:
152
+ *
153
+ * 'dependencies' => classic script handles
154
+ * 'module_dependencies' => array( 'id' => …, 'import' => 'static'|'dynamic' )
155
+ *
156
+ * Entries that don't match keep the shape WordPress core reads when it
157
+ * registers a Script Module from `block.json`
158
+ * (`register_block_script_module_id()` passes `dependencies` straight
159
+ * into `wp_register_script_module()`), so module specifiers stay in
160
+ * `dependencies` there.
161
+ *
162
+ * `wp()` wires this automatically for `adminPagesDir`. Set it yourself
163
+ * when composing plugins by hand.
164
+ *
165
+ * Example: `['/assets/js/admin-pages/']`
166
+ */
167
+ wpBuildAssetMatchers?: string[];
168
+ /**
169
+ * Plugin-local Script Module namespaces — exact names or `prefix-*` globs.
170
+ * Imports matching `@<ns>/<anything>` are externalized as Script Modules:
171
+ * the ESM import is preserved (no global rewrite) and the specifier is
172
+ * recorded in the `.asset.php` dependency list.
173
+ *
174
+ * Example: `['ignite-wp-navigation', 'ignite-*']`
175
+ */
176
+ scriptModuleNamespaces?: string[];
177
+ }
178
+ declare function wpExternals(options?: WpExternalsOptions): Plugin[];
179
+
180
+ interface WpOptions {
181
+ /** Build mode for sub-plugins. Default: `'script'`. */
182
+ buildType?: 'script' | 'module';
183
+ blocksDir?: string;
184
+ blocksStylesDir?: string;
185
+ copyAssetsDir?: string;
186
+ adminPagesDir?: string;
187
+ /**
188
+ * Per-plugin escape hatches. Pass `false` to disable; pass an object
189
+ * to merge extra options into the sub-plugin. Nested wins on conflict.
190
+ */
191
+ blocks?: Partial<WpBlocksOptions> | false;
192
+ blockStyles?: Partial<WpBlockStylesOptions> | false;
193
+ copyAssets?: Partial<WpCopyAssetsOptions> | false;
194
+ adminPages?: Partial<WpAdminPagesOptions> | false;
195
+ externals?: WpExternalsOptions | false;
196
+ /** Disable the auto-included script-IIFE helper. Default: enabled in script mode. */
197
+ iife?: false;
198
+ /** Disable the auto-included CSS-only-chunk cleanup. Default: always enabled. */
199
+ cleanCssChunks?: false;
200
+ }
201
+ declare function wp(options?: WpOptions): Plugin[];
202
+
203
+ /**
204
+ * vite-plugin-wp-script-iife
205
+ *
206
+ * Wraps each script-mode entry chunk in an IIFE post-write — esbuild/oxc's
207
+ * minifier would otherwise inline a plain intro/outro IIFE for var-heavy
208
+ * bodies, defeating the global-scope isolation needed when WP enqueues
209
+ * these as classic <script> tags.
210
+ *
211
+ * Only run this in script mode. Module-mode entries (`wp_register_script_module`)
212
+ * must stay as bare ESM for WP's import map to resolve them at runtime.
213
+ */
214
+
215
+ declare function wpScriptIife(): Plugin;
216
+
217
+ /**
218
+ * vite-plugin-wp-clean-css-chunks
219
+ *
220
+ * Deletes the empty `.js` shim Vite leaves next to a CSS-only entry.
221
+ *
222
+ * Vite's Rollup-driven model treats every entry as a JS module that may
223
+ * pull in CSS via side-effect imports. For an entry whose source IS a CSS
224
+ * file (e.g. each per-block stylesheet produced by wpBlockStyles), Vite
225
+ * still emits a tiny empty `.js` chunk that just imports the `.css`.
226
+ * Useless for WP enqueueing.
227
+ */
228
+
229
+ declare function wpCleanCssChunks(): Plugin;
230
+
231
+ export { type ExternalNamespace, type WpAdminPagesOptions, type WpAdminPagesPhpOptions, type WpBlockStylesOptions, type WpBlocksOptions, type WpCopyAssetsOptions, type WpExternalsOptions, type WpOptions, wp, wpAdminPages, wpBlockStyles, wpBlocks, wpCleanCssChunks, wpCopyAssets, wpExternals, wpScriptIife };