Webpack configuration can be overwhelming. Laravel Mix provides a fluent, expressive API that makes asset compilation delightful. At ZIRA Software, Mix has simplified our frontend builds across dozens of projects, replacing complex Webpack configs with clean, readable code.
Why Laravel Mix?
Raw Webpack config:
// webpack.config.js - 200+ lines of complexity
module.exports = {
entry: './resources/js/app.js',
output: {
path: path.resolve(__dirname, 'public/js'),
filename: '[name].[contenthash].js'
},
module: {
rules: [
{ test: /\.js$/, loader: 'babel-loader' },
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
// ... many more rules
]
},
// ... many more options
};
With Laravel Mix:
// webpack.mix.js - 5 lines
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.version();
Installation
Laravel 5.4+ includes Mix:
npm install
Basic webpack.mix.js:
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css');
Run Mix:
npm run dev # Development build
npm run watch # Watch files for changes
npm run hot # Hot module replacement
npm run production # Production build (minified)
JavaScript Compilation
Basic ES6 bundling:
mix.js('resources/js/app.js', 'public/js');
Multiple entry points:
mix.js('resources/js/app.js', 'public/js')
.js('resources/js/admin.js', 'public/js')
.js('resources/js/public.js', 'public/js');
Vue.js components:
mix.js('resources/js/app.js', 'public/js')
.vue(); // Enable Vue support
React components:
mix.react('resources/js/app.js', 'public/js');
TypeScript:
mix.ts('resources/js/app.ts', 'public/js');
CSS/Sass Compilation
Sass:
mix.sass('resources/sass/app.scss', 'public/css');
Less:
mix.less('resources/less/app.less', 'public/css');
Stylus:
mix.stylus('resources/stylus/app.styl', 'public/css');
PostCSS:
mix.postCss('resources/css/app.css', 'public/css');
Tailwind CSS:
mix.js('resources/js/app.js', 'public/js')
.postCss('resources/css/app.css', 'public/css', [
require('tailwindcss'),
]);
Versioning (Cache Busting)
mix.js('resources/js/app.js', 'public/js')
.version();
Generates:
public/js/app.js?id=abc123public/mix-manifest.json
Use in Blade:
<script src="{{ mix('js/app.js') }}"></script>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
Output:
<script src="/js/app.js?id=abc123"></script>
<link rel="stylesheet" href="/css/app.css?id=def456">
BrowserSync
Auto-reload browser:
mix.js('resources/js/app.js', 'public/js')
.browserSync('myapp.test');
Advanced options:
mix.browserSync({
proxy: 'myapp.test',
files: [
'app/**/*.php',
'resources/views/**/*.blade.php',
'public/js/**/*.js',
'public/css/**/*.css'
]
});
Source Maps
Enable in development:
mix.js('resources/js/app.js', 'public/js')
.sourceMaps(); // Development only
Custom type:
mix.sourceMaps(true, 'source-map'); // Full source maps
mix.sourceMaps(true, 'eval-source-map'); // Fast rebuild
Combine & Minify
Combine files:
mix.scripts([
'public/js/jquery.js',
'public/js/bootstrap.js',
'public/js/app.js'
], 'public/js/all.js');
mix.styles([
'public/css/bootstrap.css',
'public/css/app.css'
], 'public/css/all.css');
Minify:
mix.minify('public/js/app.js');
Copy & Move Files
// Copy file
mix.copy('node_modules/bootstrap/dist/css/bootstrap.min.css', 'public/css');
// Copy directory
mix.copyDirectory('resources/images', 'public/images');
Extract Vendor Libraries
Separate vendor code:
mix.js('resources/js/app.js', 'public/js')
.extract(['vue', 'axios', 'lodash']);
Generates:
public/js/app.js- Your codepublic/js/vendor.js- Extracted librariespublic/js/manifest.js- Webpack runtime
Use in Blade:
<script src="{{ mix('js/manifest.js') }}"></script>
<script src="{{ mix('js/vendor.js') }}"></script>
<script src="{{ mix('js/app.js') }}"></script>
Notifications
Desktop notifications:
mix.js('resources/js/app.js', 'public/js')
.disableNotifications(); // Disable if annoying
Custom Webpack Config
Extend configuration:
mix.webpackConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'resources/js'),
'~': path.resolve(__dirname, 'resources/sass'),
}
}
});
Now use aliases:
import MyComponent from '@/components/MyComponent.vue';
@import '~/variables';
Add plugins:
const webpack = require('webpack');
mix.webpackConfig({
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
});
Environment Variables
Access in JavaScript:
// .env
MIX_API_URL=https://api.example.com
// app.js
console.log(process.env.MIX_API_URL);
Must prefix with MIX_!
Hot Module Replacement
Instant updates without reload:
npm run hot
Configure in Blade:
@if (app()->environment('local'))
<script src="{{ mix('js/app.js') }}"></script>
@else
<script src="{{ mix('js/app.js') }}"></script>
@endif
Vue HMR:
if (module.hot) {
module.hot.accept();
}
Autoprefixer
Auto-add vendor prefixes:
mix.sass('resources/sass/app.scss', 'public/css')
.options({
postCss: [
require('autoprefixer')({
browsers: ['last 2 versions']
})
]
});
Babel Configuration
.babelrc:
{
"presets": [
["@babel/preset-env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions"]
}
}]
]
}
Production Optimization
Automatic in production:
npm run production
What happens:
- JavaScript minified
- CSS minified
- Source maps removed
- Assets versioned
- Code split
- Tree shaking
Manual optimization:
mix.js('resources/js/app.js', 'public/js')
.minify('public/js/app.js') // Force minification
.version(); // Force versioning
Custom Mix Tasks
webpack.mix.js:
mix.extend('compress', function(webpackConfig, ...args) {
webpackConfig.plugins.push(
new CompressionPlugin(args)
);
});
// Use custom task
mix.js('resources/js/app.js', 'public/js')
.compress();
Troubleshooting
Clear cache:
rm -rf node_modules
rm package-lock.json
npm install
Increase Node memory:
{
"scripts": {
"dev": "NODE_OPTIONS=--max_old_space_size=4096 npm run development"
}
}
Debug Webpack config:
node node_modules/webpack/bin/webpack.js --config=node_modules/laravel-mix/setup/webpack.config.js
Best Practices
- Separate vendor libraries - Use extract()
- Enable versioning - In production
- Use source maps - In development
- Leverage HMR - For Vue/React
- Configure BrowserSync - Auto-reload
- Split by route - Code splitting for SPAs
- Optimize images - Use imagemin
- Monitor build time - Keep under 10 seconds
Common Patterns
Multi-page app:
mix.js('resources/js/pages/home.js', 'public/js/pages')
.js('resources/js/pages/about.js', 'public/js/pages')
.js('resources/js/pages/contact.js', 'public/js/pages')
.sass('resources/sass/app.scss', 'public/css')
.version();
Admin panel:
mix.js('resources/js/app.js', 'public/js')
.js('resources/js/admin.js', 'public/js/admin')
.sass('resources/sass/app.scss', 'public/css')
.sass('resources/sass/admin.scss', 'public/css/admin')
.extract(['vue', 'axios'], 'public/js/vendor.js')
.version();
Conclusion
Laravel Mix makes asset compilation simple and enjoyable. Complex Webpack configurations become fluent, expressive code. At ZIRA Software, Mix has standardized our frontend builds, making projects consistent and maintainable.
Start with basic JS and Sass compilation. Add versioning, then BrowserSync. You'll wonder how you lived without it.
Building modern web applications with complex frontend requirements? Contact ZIRA Software to discuss asset pipeline optimization, build automation, and frontend architecture.