25
Using Vite with Inertia — Laravel, Vue & Tailwind
TLDR; 5800ms (Laravel Mix) to 224ms (Vite⚡️) on hot-reload!
We’ve been using Laravel-Mix for years and it’s been doing pretty good. However, recently we decided to build a project using Inertia.js (which was an awesome decision).
As the project started to grow, the development became a pain to wait for the webpack compiling.
Then, we decided to give Vite (from Vue’s creator Evan You) and the results were… ASTONISHING! I’ve been seeing Vite around in Twitter, but to be honest with you, I was not expecting THIS MUCH OF SPEED! 🚀
Benchmark Test on Hot Reloading (with 16" MBP 64gb ram, 2.4 GHz 8-Core Intel Core i9)
| Compilation | Laravel Mix | Vite |
|--------------------|-------------|-------|
| Initial Compile | 13257ms | 636ms |
| Change Reflection | 5848ms | 224ms |
That’s like ‘20x for initial compilation’ and ‘25x when code change’ 😲
We are fascinated by results, so let me tell you how to set it up, so you can try it out too.
- First, you’ll need to install Vite:
npm install vite
- Then, install Tailwind
npm i tailwindcss postcss autoprefixer -D
- Create “vite.config.js” and “postcss.config.js” in your project base
const { resolve } = require('path');
import vue from '@vitejs/plugin-vue';
export default ({ command }) => ({
base: command === 'serve' ? '' : '/dist/',
publicDir: 'fake_dir_so_nothing_gets_copied',
build: {
manifest: true,
outDir: resolve(__dirname, 'public/dist'),
rollupOptions: {
input: 'resources/js/app.js',
},
},
plugins: [vue()],
resolve: {
alias: {
'@': resolve('./resources/js'),
},
},
});
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
For the sake of completeness, here is Tailwind config (JIT is amazing as well!)
module.exports = {
mode: "jit",
purge: ['./resources/**/*.{js,jsx,ts,tsx,vue,blade.php}'],
theme: {},
variants: {},
plugins: [],
}
- And finally, you need to configure your app.js for Vite to work with Inertia.js. (The production compiling part kept me in the dark for a few hours)
import 'vite/dynamic-import-polyfill';
import '../css/app.css';
import { createApp, h } from 'vue'
import { App, plugin } from '@inertiajs/inertia-vue3'
let asyncViews = () => {
return import.meta.glob('./Pages/**/*.vue');
}
const app = createApp({
render: () => h(App, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: async name => {
if (import.meta.env.DEV) {
return (await import(`./Pages/${name}.vue`)).default;
} else {
let pages = asyncViews();
const importPage = pages[`./Pages/${name}.vue`];
return importPage().then(module => module.default);
}
}
})
})
You can’t use
require("file")
syntax, so you always need to useimport * from file.js
You need to specify file extensions when importing Vue components, like
import FormInput from "@/Shared/Form/FormInput.vue"
"app.js" is the only point of entry for your app, so you need to import your app.css file in your app.js.
…and your front-end is ready 🎉
I wanted to run “hot reloading” as well as “production” environment interchangeably in my local, so I came up with the below solution. (If you figure out a better way, I’d be happy to hear)
Vite in 'dev mode' creates a local server in https://localhost:3000 (which can be configured in vite.config.js) whereas in ‘production mode’, it creates files in 'public/dist'.
- Edit your ‘package.json’ file accordingly:
"scripts": {
"predev": "printf \"dev\" > public/hot",
"dev": "vite",
"preprod": "printf \"prod\" > public/hot",
"prod": "vite build"
},
npm run vite
is hot reloading itself and npm run dev is just for alias. The “pre” hooks are used to create a file in public directory so that the backend can figure out which mode is running.
Finally, you need to create a helper to resolve the path in your blade
— just like Laravel Mix’s {{ mix('/js/app.js') }}
helper.
You can create this php file in 'app/Helpers/vite.php' (or anywhere you like)
<?php
use Illuminate\Support\HtmlString;
if (! function_exists('vite_assets')) {
/**
* @return HtmlString
* @throws Exception
*/
function vite_assets(): HtmlString
{
$devServerIsRunning = false;
if (app()->environment('local')) {
try {
$devServerIsRunning = file_get_contents(public_path('hot')) == 'dev';
} catch (Exception) {}
}
if ($devServerIsRunning) {
return new HtmlString(<<<HTML
<script type="module" src="http://localhost:3000/@vite/client"></script>
<script type="module" src="http://localhost:3000/resources/js/app.js"></script>
HTML);
}
$manifest = json_decode(file_get_contents(
public_path('dist/manifest.json')
), true);
return new HtmlString(<<<HTML
<script type="module" src="/dist/{$manifest['resources/js/app.js']['file']}"></script>
<link rel="stylesheet" href="/dist/{$manifest['resources/js/app.js']['css'][0]}">
HTML);
}
}
- And include it to your
composer.json
"autoload": {
"psr-4": {...},
"files": [
"app/Helpers/vite.php"
]
},
[make sure to run:composer dump-autoload
]
And finally add it to your master.blade.php
<!DOCTYPE html>
<html>
<head>
<!-- Stuff -->
{{ vite_assets() }}
<!-- More Stuff -->
</head>
I believe this will change your development experience as drastic as it did to me! 🚀
I’m really curious about your compiling speeds, please leave a comment. 💬
25