I am running twenty-twentythreetheme of WordPress at the moment I have created a default vite Vue project inside my themes folder. I have not found much tutorials online that match my use case.
I want to run the vite frontend on my WordPress website. The following is my enqueue script and functions.php
Functions.php
<?php
/**
* Vue Twenty Seventeen Child Theme Functions and Definitions.
* Requires Twenty Seventeen and only works in WordPress 4.7 or later.
*
* @package WordPress
*/
// includes for the callbacks.
include_once( get_stylesheet_directory() . '/enqueue-scripts.php' );
/* hooks and filters */
?>
enqueue-scripts.php
function enqueue_vue_assets() {
wp_enqueue_script( 'app', get_template_directory_uri() . '/example/dist/assets/index-ec461b82.js', array(), '1.0', true );
wp_enqueue_style( 'app', get_template_directory_uri() . '/example/dist/assets/index-fc5f319f.css', array(), '1.0' );
}
add_action( 'wp_enqueue_scripts', 'enqueue_vue_assets' );
?>
These files are inside my twenty-twentythreetheme folder. The example is my vite project. I have not made any configurations in vite. Do I need to make any? What changes do I need to make in my enqueue script and functions script.
Also the twentytwentythree theme has mostly .html files on its frontend which I have wiped and added div id=app that should come from the app.vue.
If you want Vite to compile assets and automatically render the browser via the hot
file method in any local Wordpress theme build. Here is a working method of doing this using Chris Page's custom php class to handle Vite in Wordpress.
Follow steps below to get Vite running properly in Wordpress theme...
(example below for twentytwentythree
theme but this will work in any wordpress theme)
See Vite php class Vite.lib.php
code below...
<?php
class Vite {
/**
* Flag to determine whether hot server is active.
* Calculated when Vite::initialise() is called.
*
* @var bool
*/
private static bool $isHot = false;
/**
* The URI to the hot server. Calculated when
* Vite::initialise() is called.
*
* @var string
*/
private static string $server;
/**
* The path where compiled assets will go.
*
* @var string
*/
private static string $buildPath = 'build';
/**
* Manifest file contents. Initialised
* when Vite::initialise() is called.
*
* @var array
*/
private static array $manifest = [];
/**
* To be run in the header.php file, will check for the presence of a hot file.
*
* @param string|null $buildPath
* @param bool $output Whether to output the Vite client.
*
* @return string|null
* @throws Exception
*/
public static function init(string $buildPath = null, bool $output = true): string|null
{
static::$isHot = file_exists(static::hotFilePath());
// have we got a build path override?
if ($buildPath) {
static::$buildPath = $buildPath;
}
// are we running hot?
if (static::$isHot) {
static::$server = file_get_contents(static::hotFilePath());
$client = static::$server . '/@vite/client';
// if output
if ($output) {
printf(/** @lang text */ '<script type="module" src="%s"></script>', $client);
}
return $client;
}
// we must have a manifest file...
if (!file_exists($manifestPath = static::buildPath() . '/manifest.json')) {
throw new Exception('No Vite Manifest exists. Should hot server be running?');
}
// store our manifest contents.
static::$manifest = json_decode(file_get_contents($manifestPath), true);
return null;
}
/**
* Enqueue the module
*
* @param string|null $buildPath
*
* @return void
* @throws Exception
*/
public static function enqueue_module(string $buildPath = null): void
{
// we only want to continue if we have a client.
if (!$client = Vite::init($buildPath, false)) {
return;
}
// enqueue our client script
wp_enqueue_script('vite-client',$client,[],null);
// update html script type to module wp hack
Vite::script_type_module('vite-client');
}
/**
* Return URI path to an asset.
*
* @param $asset
*
* @return string
* @throws Exception
*/
public static function asset($asset): string
{
if (static::$isHot) {
return static::$server . '/' . ltrim($asset, '/');
}
if (!array_key_exists($asset, static::$manifest)) {
throw new Exception('Unknown Vite build asset: ' . $asset);
}
return implode('/', [ get_stylesheet_directory_uri(), static::$buildPath, static::$manifest[$asset]['file'] ]);
}
/**
* Internal method to determine hotFilePath.
*
* @return string
*/
private static function hotFilePath(): string
{
return implode('/', [static::buildPath(), 'hot']);
}
/**
* Internal method to determine buildPath.
*
* @return string
*/
private static function buildPath(): string
{
return implode('/', [get_stylesheet_directory(), static::$buildPath]);
}
/**
* Return URI path to an image.
*
* @param $img
*
* @return string|null
* @throws Exception
*/
public static function img($img): ?string
{
try {
// set the asset path to the image.
$asset = 'resources/img/' . ltrim($img, '/');
// if we're not running hot, return the asset.
return static::asset($asset);
} catch (Exception $e) {
// handle the exception here or log it if needed.
// you can also return a default image or null in case of an error.
return $e->getMessage(); // optionally, you can retrieve the error message
}
}
/**
* Update html script type to module wp hack.
*
* @param $scriptHandle bool|string
* @return mixed
*/
public static function script_type_module(bool|string $scriptHandle = false): string
{
// change the script type to module
add_filter('script_loader_tag', function ($tag, $handle, $src) use ($scriptHandle) {
if ($scriptHandle !== $handle) {
return $tag;
}
// return the new script module type tag
return '<script type="module" src="' . esc_url($src) . '" id="' . $handle . '-js"></script>';
}, 10, 3);
// return false
return false;
}
}
Place this Vite.lib.php
class file inside a lib
folder in your local twentytwentythree
theme directory, then require Vite.lib.php
in your functions.php
.
You then want to create a Theme php class Theme.lib.php
to handle enqueuing your scripts and css to work with Vite...
<?php
class Theme {
public function __construct()
{
// enqueue admin styles scripts
add_action('wp_enqueue_scripts', [ $this, 'enqueue_styles_scripts' ], 20);
}
/**
* @return void
* @throws Exception
*/
public function enqueue_styles_scripts(): void
{
// enqueue the Vite module
Vite::enqueue_module();
// register theme-style-css
$filename = Vite::asset('resources/scss/theme.scss');
// enqueue theme-style-css into our head
wp_enqueue_style('theme-style', $filename, [], null, 'screen');
// register theme-script-js
$filename = Vite::asset('resources/js/theme.js');
// enqueue theme-script-js into our head (change false to true for footer)
wp_enqueue_script('theme-script', $filename, [], null, false);
// update html script type to module wp hack
Vite::script_type_module('theme-script');
}
}
new Theme();
Then in your function.php
, require Theme.lib.php
after Vite.lib.php
like this...
<?php
// require libs
require_once(__DIR__ . '/lib/Vite.lib.php');
require_once(__DIR__ . '/lib/Theme.lib.php');
Once you've implemented the above php, let's start a fresh package.json
in your local theme directory.
When you get Vite running, you can re-add Vue and other dependencies later 👍🏼
Here is the basic package.json
boilerplate to get your project started with Vite in Wordpress...
{
"private": true,
"scripts": {
"dev": "vite",
"watch": "npm run dev",
"build": "vite build",
"production": "vite build"
},
"devDependencies": {
"sass": "^1.63.6",
"vite": "^4.4.3",
"laravel-vite-plugin": "^0.7.8"
},
"dependencies": {
}
}
You will notice we are using laravel-vite-plugin
in our package.json
, this Laravel Vite plugin makes it super easy to configure the resources and build directory in our vite.config.js
, and watches for php file changes in your entire theme!
See working vite.config.js
below for compiling our theme.css
and theme.js
resources to the build folder. This vite.config.js
file also goes in your local theme directory, the same as your package.json
...
import {defineConfig} from "vite";
import laravel from 'laravel-vite-plugin';
export default defineConfig(() => ({
base: '',
build: {
emptyOutDir: true,
manifest: true,
outDir: 'build',
assetsDir: 'assets'
},
plugins: [
laravel({
publicDirectory: 'build',
input: [
'resources/js/theme.js',
'resources/scss/theme.scss'
],
refresh: [
'**.php'
]
})
],
resolve: {
alias: [
{
find: /~(.+)/,
replacement: process.cwd() + '/node_modules/$1'
},
]
}
}));
Before we install NPM and install Vite build, you need to create a resources
folder in your local theme directory. Then inside the resources
folder, create these img, scss, js
directories and then create empty theme.scss, theme.js
files, structured like this...
Now we are ready to run NPM install on our package.json
configuration.
Open terminal in your theme directory and run this command...
npm install
This command install's our dev dependencies and creates our node_modules
library root vendor files, plus creates a package-lock.json
file, so our theme directory now looks like this...
Now Vite is installed, we are ready to build our Vite project.
Before we run Vite build, if you visit your site locally you will notice you get a fatal error. This is because we have not generated a Vite manifest json file yet. The Vite
manifest.json
handles linking between ourresources
files and our cache bustedbuild/assets
files.
OK, let's build our resources with Vite so you can start making some magic!
In your local theme directory, run this command first...
npm run build
Command should return this log...
You only need to initially run npm run build
once if you are starting a brand new Vite project. This command initially creates your build
folder, build/manifest.json
and build/assets/..
cache busted files.
Please note you will need to use npm run build
again every time you want to build production minified build assets and production manifest.json
.
Your theme directory will look like this after initially running npm run build
for the first time...
If you visit your local site you will notice the fatal error has gone and the production build
theme.css
andtheme.js
will be working!
If your local theme is working with no errors, you can inspect the source code and you will see the theme.css
and theme.js
are enqueued like this in the html...
<link href="http://localhost/wp-content/themes/vite-wordpress/build/assets/theme-716126ae.css" rel="stylesheet" id="theme-style-css" type="text/css" media="screen">
<script src="http://localhost/wp-content/themes/vite-wordpress/build/assets/theme-13161a16.js" type="module" id="theme-script-js"></script>
The above enqueued output is exactly how you want this to look on your staging
and production
environments. This is the expected output when our Vite local development hot
file does not exist!
Finally, we are ready to start the epic Vite local js server and hot
file for super fast dev compiling and automatic browser asset rendering without refreshing the browser!
Provided you've initially built your Vite build
files, you can now run this command below to start your local Vite js server and hot
file to watch for any save changes in your theme.
npm run dev
This command should return a log like this, and shows you that the Vite dev local js server is running...
And you will notice a hot
file now exists in your build
directory...
If you now refresh your local Wordpress site, will notice our enqueued theme.css
and theme.js
html has changed to this...
<link href="http://127.0.0.1:5173/resources/scss/theme.scss" rel="stylesheet" id="theme-style-css" type="text/css" media="screen">
<script src="http://127.0.0.1:5173/resources/js/theme.js" type="module" id="theme-script-js"></script>
And you will also notice an additional script loaded in the <head>
which is our Vite client js module. This script is handling the hot
file watcher for any changes made to files in your theme.
<script src="http://127.0.0.1:5173/@vite/client" type="module" id="vite-client-js"></script>
So now we are running Vite dev server, you can start adding code to your theme.css
and theme.js
resource files.
Every time you hit save on your resource files, Vite will compile your project and changes will automatically run/update in your browser without refreshing! The same will happen if you edit and save PHP.
While your local Vite dev js server is still running, you can install Vue and other packages via a new terminal window without having to stop the current Vite dev js server watcher.
Once you are ready to build for production, make sure you've exited the Vite dev js server and is no longer running...
Then re-run npm run build
in your theme directory to build cache busted production files in your build
directory. The sync build
directory to staging
or production
environments.
Make sure functions.php
, Vite.lib.php
and Theme.lib.php
are also deployed to your staging
or production
environments for the build/assets
to work in your theme.
resources/img
To use images from the theme build
folder which are images compiled from the resources/img
directory to the build/assets
directory.
The php
usage is...
<img src="<?=Vite::img('example.png')?>" alt="Example" />
And the scss
usage is...
BODY {
background-image: url(../img/example.png);
}