SkillAgentSearch skills...

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-starter

Installs into whichever agent you are using.

README

<div align="center"> <a href="https://vitejs.dev/"> <img width="200" height="200" hspace="10" src="https://vitejs.dev/logo.svg" alt="vite logo" /> </a> <h1>WP ViteJS 4 starter kit</h1> <p> Simple lightweight starter kit to make use of Vite's blazing fast and efficient frontend build tool for WordPress plugin and theme development. Comes with packages that provide front-end & back-end (PHP) utilities. The "src" folder includes JS, PostCSS, images, fonts, SVG and a gutenberg block as examples.

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 .js files instead of the default .jsx
  • Esbuild for minification which is turned off for development mode
  • Esbuild sourcemaps are added for development mode
  • JS entries are automatically included from first-level folders inside the src folder 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 @import rule.
  • 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

View on GitHub
GitHub Stars32
CategoryDevelopment
Updated4mo ago
Forks4

Languages

JavaScript

Security Score

77/100

Audited on Mar 25, 2026

No findings