Simplifying Asset Compilation with Laravel Mix
Laravel Mix provides a fluent API that lets you compile JavaScript and CSS assets without writing Webpack configuration from scratch.
Most people who try to learn Webpack hit the same wall: the config file. Loaders, plugins, resolve rules — everything is configurable, but the price of that flexibility can be a webpack.config.js that eats hours on every new project. Laravel Mix exists to make that complexity invisible.
Laravel Mix is a tool built on top of Webpack that exposes a fluent API. It was developed by Jeffrey Way for the Laravel ecosystem, but it has no hard Laravel dependency — you can use it in any Node.js project. In 2016 it became the default asset compilation tool shipped with Laravel 5.4.
Installation
If you are starting from a Laravel 5.4 project, Mix is already listed in package.json. Install everything with:
npm install
That is all. Webpack and all its dependencies come along for the ride.
webpack.mix.js
Configuration lives in webpack.mix.js. The minimal setup looks like this:
const mix = require('laravel-mix');
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css');
Those two lines do a lot: app.js gets bundled with Webpack and written to public/js/app.js; app.scss gets compiled through the Sass (SCSS) compiler and written to public/css/app.css. Vendor prefixes for both CSS and JavaScript are added automatically.
Development and production modes
package.json ships with ready-made scripts:
npm run dev # Compile for development (includes source maps)
npm run watch # Watch files and recompile on change
npm run production # Minified, production-ready build
Running npm run production minifies the output files and appends a content hash to each filename. Mix handles cache busting on its own — no manual versioning required.
npm run watch is invaluable during the development loop. Save a SCSS file and Mix recompiles immediately, sparing you the chore of triggering Webpack by hand on every change.
Versioning
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css')
.version();
In your Blade templates, the mix() helper resolves the correct versioned URL:
<script src="{{ mix('js/app.js') }}"></script>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
With this in place, browsers always fetch the latest file on each deployment — stale-cache problems disappear.
Behind the scenes, mix() reads public/mix-manifest.json, a file Mix regenerates on every build. It maps each logical asset path to its hashed filename. You always write mix('js/app.js') in your templates; Mix figures out the real URL.
Vue single-file components
Compiling .vue components requires no extra configuration — Mix supports them out of the box:
mix.js('resources/assets/js/app.js', 'public/js');
// .vue components can be imported inside app.js
Vue loader setup, Babel transpiling, source maps — all handled behind the scenes.
This is where Mix genuinely shines. Compiling .vue files with raw Webpack would require configuring vue-loader, vue-template-compiler, and Babel. Mix collapses all of that into a single line. When I decide to use Vue in a new project, I no longer need to touch any configuration.
Multiple output files
Mix is not limited to a single entry point. You can produce separate bundles for different pages:
mix.js('resources/assets/js/app.js', 'public/js')
.js('resources/assets/js/admin.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css')
.sass('resources/assets/sass/admin.scss', 'public/css');
Keeping the admin panel JavaScript separate from the public-facing bundle means regular users never download admin code they will never use. Mix makes this split easy; there was no need to write separate Webpack configurations.
Browsersync
To auto-refresh the browser during development:
mix.browserSync('myapp.test');
This reloads the browser whenever a file changes. Paired with Laravel Homestead, it noticeably tightens the development loop.
Direct comparison with raw Webpack
Because Mix abstracts everything, you rarely need to open webpack.config.js. When you do need to reach through the abstraction, mix.webpackConfig({}) lets you merge directly into the underlying Webpack configuration. Full control is available whenever you need it.
In practice, I have never needed to go beyond “compile SCSS and bundle JS” on any project I have worked on. Mix handles that scenario with room to spare, and the time I would have spent reading Webpack documentation goes toward the actual work instead.
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.