JS architecture (v3.7.0+)
Status: Decision locked 2026-05-13 in Phase 5 of plan_v3.7.0.md (issue #390). First consumer (toast notifications) shipped in v3.7.0.
Decision
JS modules are authored in simple-wp-helpdesk/assets/src/ and built via @wordpress/scripts to simple-wp-helpdesk/assets/dist/. Dist files are committed so WordPress.org ZIP users do not need Node.
Rationale
@wordpress/components ships Modal, Notice, Button, ComboboxControl, Popover — directly covers v4.0’s modal/drawer/command-bar/tabs gaps without a second component library. The .asset.php files auto-generated by wp-scripts auto-generate the wp_enqueue_script dependency array. WordPress 6.0 (the v4.0 minimum) already loads wp-element (React) for the block editor, so declaring it as an external dependency adds ~0 KB to the plugin bundle. Webpack rebuild speed (1–3s) is fine for this plugin’s JS surface area.
Source / build layout
simple-wp-helpdesk/assets/
├── src/ # ES modules (authored)
│ └── toast/index.js # v3.7.0 PoC consumer
└── dist/ # webpack output (committed)
├── toast.js
└── toast.asset.php # auto-generated deps + version hash
Entrypoints are declared in package.json build scripts as <name>=<path> pairs passed to wp-scripts build. Example: toast=toast/index.js emits toast.js and toast.asset.php in assets/dist/.
Bundle-size budget
≤40 KB gzip per entrypoint, excluding WP-shipped externals (wp-element, wp-components, wp-i18n, wp-data).
Initial measurement (v3.7.0, toast entrypoint): 512 bytes gzip (1,021 bytes uncompressed). The toast module imports no externals.
PHP-side enqueue pattern
$asset_file = SWH_PLUGIN_DIR . 'assets/dist/<name>.asset.php';
if ( file_exists( $asset_file ) ) {
$asset = include $asset_file;
wp_enqueue_script(
'swh-<name>',
SWH_PLUGIN_URL . 'assets/dist/<name>.js',
$asset['dependencies'],
$asset['version'],
true
);
}
The swh_enqueue_toast_script() helper in includes/helpers.php encapsulates this for the v3.7.0 toast entrypoint.
Component primitives planned on top of @wordpress/components
The v4.x roadmap will add these custom primitives where @wordpress/components does not provide an out-of-the-box equivalent:
Drawer(quick-reply panel)VirtualList(inbox)CommandBar(Ctrl/Cmd+K palette)
Modal, Notice, Button, ComboboxControl, Popover come from @wordpress/components directly.
Migration path
simple-wp-helpdesk/assets/swh-admin.js is the legacy unbuilt admin JS bundle. It stays in place for now; new functionality goes through the build, and existing pieces migrate piece-by-piece across v4.x. In v3.7 only the toast renderer was extracted — settings tabs, canned responses, and the rest of swh-admin.js are unchanged.
The legacy bundle keeps working because assets/src/toast/index.js assigns the renderer to window.swhToast — the existing call site in swh-admin.js still resolves the function as before.
CI integration
make e2e-docker depends on make js-build, which runs npm install (one-time) and npm run build. PHP-only gates (make test-docker) do not require Node — they validate the committed assets/dist/ directly.
Release ZIPs are built by release.yml via zip -r ... simple-wp-helpdesk/, which includes assets/dist/ automatically. No workflow changes were required.