I was playing around with a React project locally and I wanted a way to share it within the context of my own website.
In this particular case, I'm configuring React, but you could use Vite to configure any other frontend framework.
This website has a bit of an unconventional setup, so I thought I'd share how I added a React application within the site. The concepts in this article could be applied to most PHP-based websites, where you handle the routing and rendering of the page on the server side.
First, we'll need Vite. I was already using TailwindCSS on the project, but using the Tailwind CLI, so let's replace that with Vite. We'll also use the new Tailwind v4 beta. Let's install these new dependencies.
npm i vite tailwindcss@next @tailwindcss/vite@next
We'll need to create a vite.config.ts
file in the root of the project to handle the build process.
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
build: {
// we'll need the manifest so that we can load the assets into the PHP template
manifest: true,
rollupOptions: {
input: {
// handle the styles for the whole website
style: resolve(__dirname, 'src/style.css'),
// handle the styles for the playground
playground: resolve(__dirname, 'src/playground/index.tsx'),
},
},
outDir: 'dist',
emptyOutDir: false,
},
server: {
origin: 'http://localhost:5173',
},
})
Vite's documentation for this is very good, but I just thought I'd get into a specific PHP example.
I'm going to assume you already have a React application created. Put that application in the src/playground
directory, where index.tsx
is the entry point for the application. If you're moving an existing application into this project, you'll need to update the index.tsx
file with the module preload polyfill.
import 'vite/modulepreload-polyfill'
// ...existing react application code
We're going to create a PHP function that loads the Vite server and returns the HTML for the application in development mode.
<?php
function dev_load_vite_module($path) {
$vite_host = 'http://localhost:5173';
$response = @file_get_contents($vite_host . $path);
if ($response === false) {
http_response_code(404);
return;
}
if (str_contains($path, '.css')) {
header('Content-Type: text/css');
} else {
header('Content-Type: application/javascript');
}
foreach ($http_response_header as $header) {
if (str_contains(strtolower($header), 'access-control-')) {
header($header);
}
}
echo $response;
}
Hook this function into our router, perhaps with something like this:
<?php
if (isset($_ENV['DEV'])) {
dev_load_vite_module($_SERVER['REQUEST_URI']);
}
// ...existing template code
This will load the Vite server and return the HTML for the application in development mode.
Now we'll need to create a function to handle the assets in production mode.
<?php
function vite_assets() {
$isDev = isset($_ENV['DEV']);
if ($isDev) {
return [
'css' => 'http://localhost:5173/src/style.css',
'js' => 'http://localhost:5173/src/playground/index.tsx'
];
}
$manifest = json_decode(file_get_contents(__DIR__ . '/../dist/.vite/manifest.json'), true);
return [
'css' => '/dist/' . $manifest['src/style.css']['file'],
'js' => '/dist/' . $manifest['src/playground/index.tsx']['file']
];
}
Update your root template to include the Vite assets in the <head>
tag. You'll also need to add a root element for the React application to mount into.
<?php $assets = vite_assets(); ?>
<head>
<?php $isDev = isset($_ENV['DEV']); ?>
<?php if ($isDev): ?>
<script type="module" src="http://localhost:5173/@vite/client"></script>
<?php endif; ?>
<link rel="stylesheet" href="<?= $assets['css'] ?>" />
</head>
<body>
<div id="root"></div>
<?php if ($isDev): ?>
<!-- since it's a react application, we need to load the react refresh runtime for development. -->
<script type="module">
import RefreshRuntime from 'http://localhost:5173/@react-refresh'
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>
<script type="module" src="http://localhost:5173/@vite/client"></script>
<script type="module" src="http://localhost:5173/src/playground/index.tsx"></script>
<?php else: ?>
<script type="module" src="<?= $assets['js'] ?>"></script>
<?php endif; ?>
</body>
Since TailwindCSS v4 uses CSS for configuration, you'll want to update your root src/style.css
file to use the new directives. You'll also want to add the @source
directive to include the PHP files and the React application files.
@import 'tailwindcss';
@source '../**/*.php';
@source './playground/**/*.tsx';
Now, simply update your package.json
to use Vite.
"scripts": {
"dev": "vite",
"build": "vite build"
}
Now you can run npm run dev
to start the Vite server and npm run build
to build the application. You should see the playground running on your site.
That's it! You can see my React application in action here: Last.fm Listening Stats
The great thing about using Vite is that you could easily swap out the React application for another frontend framework. For example, you could use Solid or Vue instead of React and the same setup would work.