As of Laravel version 9.19, the framework has chosen to replace its front-end asset management tool Mix with the very popular tool Vite.
Getting started
This guide will explain how to upgrade an existing application with Mix to use Vite. Brand new installations of a Laravel app will have this already in place — no work required.
Remove Mix
First, remove Mix as it will now no longer be needed.
1npm remove laravel-mix
Then remove the webpack.mix.js
file from your root.
Install Vite and the Laravel plugin
Now install Vite, along with the new Laravel plugin for it. Save them as dev dependencies.
1npm install --save-dev vite laravel-vite-plugin
Configuring the plugin
Create a new file in the root called vite.config.js
and add this code to it
1import { defineConfig } from 'vite'; 2import laravel from 'laravel-vite-plugin'; 3 4export default defineConfig({ 5 plugins: [ 6 laravel([ 7 'resources/css/app.css', 8 'resources/js/app.js' 9 ]),10});
Update scripts
The build scripts have changed with Vite and need to be replaced in the package.json
file.
1"scripts": { - "dev": "yarn run development", - "development": "mix", - "watch": "mix watch", - "watch-poll": "mix watch -- --watch-options-poll=1000", - "hot": "mix watch --hot", - "prod": "yarn run production", - "production": "mix --production" + "dev": "vite", + "build": "vite build" 11},
Compatibility with ES Modules
Vite can only support ES Modules, so any cases where you’re using the require()
method in your Javascript now needs to be replaced with an import. Within a Laravel app, here is where these changes can be made
resources/js/app.js
-require('./bootstrap'); +import './bootstrap';
resources/js/bootstrap.js
-window._ = require('lodash'); +import _ from 'lodash'; +window._ = _;
-window.axios = require('axios'); +import axios from 'axios'; +window.axios = axios;
-// window.Pusher = require('pusher-js'); // +// import Pusher from 'pusher-js'; // +// window.Pusher = Pusher; //
Update Environment files
Your .env
and the .env.example
files must be updated too
-MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" // -MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" // +VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" // +VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" //
The PUSHER_APP_*
variables are also mentioned within the resources/js/bootstrap.js
file, so it would be worth updating these too
-key: process.env.MIX_PUSHER_APP_KEY, -cluster: process.env.MIX_PUSHER_APP_CLUSTER, +key: import.meta.env.VITE_PUSHER_APP_KEY, +cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
Using the new Vite directive
This version of Laravel comes with a handy new Blade directive which is to be used to replace your existing links to your app.css
and app.js
files.
Remove any mention of these files and replace them with the new directive
1@vite(['resources/css/app.css', 'resources/js/app.js'])
Optional extras: Tailwind; Gitignore
If you’re using Tailwind CSS, a postcss.config.js
file is required for the utility classes to be generated correctly with Vite. Run this command to add this file to your root with the necessary code
1npx tailwindcss init -p
Or you can add this manually by creating a new file called postcss.config.js
and adding the below code
1module.exports = {2 plugins: {3 tailwindcss: {},4 autoprefixer: {},5 },6}
When you generate the assets with Vite, it stores the files within a build
folder within the public
directory. If you don’t want these files to be in your VCS then ignore the folder in the root .gitignore
file
1/public/build
Running locally
Now everything is set up, you can run the scripts as you’re used to and reap the benefits of faster build times
1npm run dev
You’ll see some differences from when running this with Mix installed. This will boot up a dev server running on port 3000 and will start listening for changes immediately, similar to running mix watch
and you’ll see it runs a lot quicker.
Deployment
When deploying your app, be sure to update your deployment script (or however you do it) to use the new build script, replacing npm run prod
1npm run build
This compiles your assets into a public/build
folder and the @vite()
blade directive will inject it into your code. You can do this locally too if you wish.
🔥 Hot Module Reloading (HMR)
A cool feature of Vite is Hot Module Reloading, which means when you save a file, the browser will inject that code into the browser without reloading. This works out of the box when running the dev server.
Tip: Using Laravel Valet with HTTPS
If you’re using Laravel Valet with secured sites, it is advised to add this to your vite.config.js
file
1import { defineConfig } from 'vite'; 2import laravel from 'laravel-vite-plugin'; 3 4export default defineConfig({ 5 plugins: [ 6 laravel([ 7 'resources/css/app.css', 8 'resources/js/app.js' 9 ]),10 server: { 11 https: true,12 host: 'localhost'13 } 14});
⚠️ You may run into issues with your browser connecting to Vite — if so, visit the URL to the Vite server (usually https://localhost:3000
) and accept the certificate pop-up warnings you’ll get. You should only need to do this once. Always restart the dev server when making any config changes.
Tip: Auto-reload Blade Files
⛔️ Update as of v0.3.0
The plugin now supports Blade reloading out of the box. The syntax is slightly different, as shown below
1import { defineConfig } from 'vite'; 2import laravel from 'laravel-vite-plugin'; 3 4export default defineConfig({ 5 plugins: [ - laravel([ - 'resources/css/app.css', - 'resources/js/app.js' - ]), + laravel({ + input: [ + 'resources/css/app.css', + 'resources/js/app.js' + ], + refresh: true + }), - { - name: 'blade', - handleHotUpdate ({ file, server }) { - if (file.endsWith('.blade.php')) { - server.ws.send({ - type: 'full-reload', - path: '*' - }); - } - } - } 28 ],29 server: {30 https: true,31 host: 'localhost'32 }33});
The below is no longer relevant
One thing Vite cannot do is use HMR to inject code into Blade files, but there is a workaround that involves listening for changes to Blade files and doing a full page reload, but automatically. Add this snippet of code to your vite.config.js
file.
1import { defineConfig } from 'vite'; 2import laravel from 'laravel-vite-plugin'; 3 4export default defineConfig({ 5 plugins: [ 6 laravel([ 7 'resources/css/app.css', 8 'resources/js/app.js' 9 ]),10 { 11 name: 'blade',12 handleHotUpdate ({ file, server }) {13 if (file.endsWith('.blade.php')) {14 server.ws.send({15 type: 'full-reload',16 path: '*'17 });18 }19 }20 } 21 ],22 server: {23 https: true,24 host: 'localhost'25 }26});
Now when you update a Blade file, you should see the page reload automatically.
Using React and Vue
This guide is very basic and only explains how to upgrade a standard Laravel app that only uses Blade files. You can use this with React and Vue but that goes beyond the scope of this guide. If you want to know more about how to use Vite with React and Vue and SSR, check out the official upgrade guide on the Vite plugin repository — https://github.com/laravel/vite-plugin/blob/main/UPGRADE.md
Wrapping up…
- Check out Laravel’s own documentation on using Vite
- Thanks to @freekmurze for the information on using HMR with Blade files
- Here is a PR I did for this website which shows all the changes I made to replace Mix with Vite - https://github.com/cjmellor/mellor.pizza/pull/35/files