Wp Vite Starter
Lightweight starter kit to use ViteJS 4 for WordPress plugin and theme development. Includes frontend and backend (PHP) utilities
Install / Use
npx skills add brandonkramer/wp-vite-starterInstalls into whichever agent you are using.
README
You can read more about ViteJS on vitejs.dev
</p> </div>📚 Table of contents
🏁 Quick start
Install packages and autoloader.
yarn install
composer install
Build our assets into the 'build' folder.
yarn build
💻 Other commands
Build assets in development mode.
yarn build-dev
Builds assets in real-time and watches over files.
yarn watch
yarn watch-dev
Start ViteJS dev server.
yarn start
📦 What's inside
The idea is to keep the starter kit simple so additional things can be added for different projects, and so it can be integrated into different theme and plugin structures and maintained through node/composer packages.
ViteJS Config
The config is extending a base config from the @wp-strap/vite package through a plugin which is opinionated and configured for WordPress development which can be overwritten. It ensures the following:
- Updates/refreshes the dev server (HMR/Hot Module Replacement) when a change is made inside PHP files
- Encapsulates JS bundles to prevent mix-up of global variables (with other plugins/themes) after minification
- Collects images, SVG and font files from folders and emits them to make them transformable by plugins
- Esbuild is configured to make ReactJS code work inside
.jsfiles instead of the default.jsx - Esbuild for minification which is turned off for
developmentmode - Esbuild sourcemaps are added for
developmentmode - JS entries are automatically included from first-level folders inside the
srcfolder using fast-glob (e.g., js/my-script.js, blocks/my-block.js). - CSS entries are also automatically included in the same way, bundled and compiled without importing them into JS files which is more suitable for WordPress projects.
- Vite Plugin Image Optimizer is included that optimizes images and SVG files that we emit
PostCSS config
PostCSS is added through the Vite base config file and is currently configured with the following:
- TailwindCSS to add a utility-first CSS framework that scans all of our files, and only generate styles and classes that we use.
- TailwindCSS nesting to unwrap nested rules similar to SASS.
- PostCSS import that can consume local files, node modules or web_modules using the
@importrule. - Autoprefixer to parse CSS and add vendor prefixes to CSS rules using values from Can I Use.
- PostCSS combine duplicated selectors that detects and combines duplicated CSS selectors.
TailwindCSS config
TailwindCSS is added through the PostCSS config file and is currently only configured with the following:
- Paths to find TailwindCSS classes for optimization. This will make sure it only generates styles that are needed.
- A prefix that will be added to all of Tailwind’s generated utility classes. This can be really useful to prevent naming conflicts with other themes and plugins.
Read here more about all the cool stuff you can configure with Tailwind.
PHP / Composer
Composer includes the wp-strap/vite package that exposes some classes that helps you generate asset URLs from the manifest.json that you can register or enqueue. It also enables you to use HMR (hot module replacement) when the ViteJS dev server is running.
The classes follow PSR practices with interfaces, so it can be included trough OOP with dependency injection and IoC containers. It also provides a Facade class that allows you to use static methods anywhere you like if that's your jam.
Example with using the facade:
use WPStrap\Vite\Assets;
// Resolves instance and registers project configurations
Assets::register([
'dir' => plugin_dir_path(__FILE__), // or get_stylesheet_directory() for themes
'url' => plugins_url(\basename(__DIR__)) // or get_stylesheet_directory_uri() for themes
'version' => '1.0.2', // Set a global version (optional)
'deps' => [ 'scripts' => [], 'styles' => [] ] // Set global dependencies (optional)
]);
// Listens to ViteJS dev server and makes adjustment to make HMR work
Assets::devServer()->start();
// returns: https://your-site.com/wp-content/plugins/your-plugin/build/js/main.oi4h32d.js
Assets::get('js/main.js')
// Alternatively you can use these as well which will be more targeted to specific folders
// and for some of the methods you don't need to write the file extension
Assets::js('main')
Assets::css('main')
Assets::image('bird-on-black.jpg')
Assets::svg('instagram')
Assets::font('SourceSerif4Variable-Italic.ttf.woff2')
// Example of enqueuing the scripts
add_action('wp_enqueue_scripts', function () {
// You can enqueue & register the tradtional way using global data
wp_enqueue_script('my-handle', Assets::js('main'), Assets::deps('scripts'), Assets::version());
wp_enqueue_style('my-handle', Assets::css('main'), Assets::deps('styles'), Assets::version());
// Or use a more simple method that includes the global deps & version
Assets::enqueueStyle('my-handle', 'main');
// Which also comes with some handy chained methods
Assets::enqueueScript('my-handle', 'main', ['another-dep'])
->useAsync()
->useAttribute('key', 'value')
->localize('object_name', ['data' => 'data'])
->appendInline('<script>console.log("hello");</script>');
});
Example with using instances
use WPStrap\Vite\Assets;
use WPStrap\Vite\AssetsService;
use WPStrap\Vite\DevServer;
// Instantiates the Asset service and registers project configurations
$assets = new AssetsService();
$assets->register([
'dir' => plugin_dir_path(__FILE__), // or get_stylesheet_directory() for themes
'url' => plugins_url(\basename(__DIR__)) // or get_stylesheet_directory_uri() for themes
]);
// Listens to ViteJS dev server and makes adjustment to make HMR work
(new DevServer($assets))->start();
$assets->get('js/main.js');
$assets->js('main')
$assets->css('main')
$assets->image('bird-on-black.jpg')
$assets->svg('instagram')
$assets->font('SourceSerif4Variable-Italic.ttf.woff2')
// Traditional
wp_enqueue_script('my-handle', $this->assets->js('main'), $this->assets->deps('scripts'), $this->assets->version());
wp_enqueue_style('my-handle', $this->assets->css('main'), $this->assets->deps('styles'), $this->assets->version());
// Custom methods
$this->assets->enqueueStyle('my-handle', 'main');
$this->assets->enqueueScript('my-handle', 'main', ['another-dep'])
->useAsync()
->useAttribute('key', 'value')
->localize('object_name', ['data' => 'data'])
->appendInline('<script>console.log("hello");</script>');
// You can also use the facade based on this instance.
Assets::setFacade($assets);
Assets::get('css/main.css');
Example with using instances wih functions
use WPStrap\Vite\AssetsInterface;
use WPStrap\Vite\AssetsService;
use WPStrap\Vite\DevServer;
function assets(): AssetsInterface {
static $assets;
if(!isset($assets)) {
$assets = (new AssetsService())->register([
'dir' => plugin_dir_path(__FILE__),
'url' => plugins_url(\basename(__DIR__)),
'version' => '1.0.0'
]);
}
return $assets;
}
(new DevServer(assets()))->start();
add_action('wp_enqueue_scripts', function () {
// Traditional
wp_enqueue_script('my-handle', assets()->js('main'), assets()->deps('scripts'), assets()->version());
wp_enqueue_style('my-handle', assets()->css('main'), assets()->deps('styles'), assets()->version());
// Using custom methods
assets()->enqueueStyle('my-handle', 'main');
assets()->enqueueScript('my-handle', ['Main', 'main'], ['another-dep'])
->useAsync()
->useAttribute('key', 'value')
->localize('object_name', ['data' => 'data'])
->appendInline('<script>console.log("hello");</script>');
});
Example with using the League Container
use League\Container\Container;
use WPStrap\Vite\Assets;
use WPStrap\Vite\AssetsInterface;
use WPStrap\Vite\AssetsService;
use WPStrap\Vite\DevServer;
use WPStrap\Vite\DevServerInterface;
$container = new Container();
$container->add(AssetsInterface::class)->setConcrete(AssetsService::class)->addMethodCall('register', [
'dir' => plugin_dir_path(__FILE__),
'url' => plugins_url(\basename(__DIR__))
]);
$container->add(DevServerInterface::class)->setConcrete(DevServer::class)->addArgument(AssetsInterface::class);
$assets = $container->get(AssetsInterface::class);
$devServer = $container->get(DevServerInterface::class);
$devServer->start();
$assets->get('main/main.css');
// You can also set a PSR container as a facade accessor
Assets::setFacadeAccessor($container);
Assets::get('main/main.css')
DevServer
Assets::devServer()->start(3000'); OR (new DevServer($assets))->start('3000');
The dev server class is responsible for listening to the ViteJS dev server using C
Related Skills
node-connect
385.5kDiagnose OpenClaw Android, iOS, or macOS node pairing, QR/setup code, route, auth, and connection failures.
blender-python-addon
40.5kBlender Python add-on rules for operators, panels, properties, registration, testing, and API-safe scripting
flutter-development-guidelines-cursorrules-prompt-file
40.5kCursor rules for Flutter development with MVVM architecture, Riverpod state management, Material widgets, and Dart style guidelines.
nextjs15-react19-vercelai-tailwind-cursorrules-prompt-file
40.5kCursor rules for Next.js development with React 19, Vercel AI, and Tailwind CSS integration.
