Mixing Assets
- Configuration
- Watching Changes and Auto Reloading
- Cache Busting with Asset Fingerprinting
- Setting Environment Variables
If you have any experience with frontend development and especially with bundling your assets — vanilla JS, stylesheets, images, frontend libraries such as VueJS, etc. — you know that mixing them is not a trivial task and needs a lot of wiring and juggling. Webpack is currently the de-facto standard for bundling assets. However, it is complex and has a huge learning curve.
Thankfully, there exists a JS library, called Laravel Mix, that wraps the complex Webpack APIs in a much simpler fluent APIs. To make it easier for you to get going with your web app, Alpas comes set up with asset handling through Mix.
/info/ Alpas uses Mix because it is simple to configure, it is fast, and it just works! However, Alpas is not really tied to Mix. Feel free to use any bundler of your choice such as Grunt, Gulp, Rollup, etc.
Configuration
When a new project is scaffolded, Alpas creates a webpack.mix.js
file for you in the root of your project.
This file is where you would configure your assets bundling pipeline. Alpas also creates a package.json
file for you that lists some very basic npm packages to get you going. Feel free to add and remove
dependencies as per your project requirements.
To install the packages listed in the package.json
file, make sure you have the latest version of
nodejs and npm installed and then simply run
npm install
from your terminal.
/tip/ Instead of
npm
we highly recommend using yarn, which is an ultra fast alternative tonpm
for managing nodejs packages.
When you open the webpack.mix.js
file you will notice that publicPath
is set to src/main/resources/web
.
This location is where your final bundled assets will be put. On the other hand, resources
is set to
src/main/resources
folder, which is where your source files will be loaded from. Feel free to
change these values as you wish.
After you finish configuring your webpack.mix.js
file, you can run one of the following commands to bundle
your assets. All these commands come from the package.json
file.
npm run dev
Bundles all the assets without minifying the output. Use this in dev mode. Since the symbols are not mingled, it is much easier to debug your scripts and your styles.
npm run prod
Bundles all the assets and minifies the output. Use this before deploying or creating a fat jar for deployment. Since the generated files are minified, the files are usually much smaller than the original source files but aren't easy to debug.
npm run watch
Watches the asset files and automatically re-compiles them whenever a change is detected. This comes in very handy during development, especially when you are tweaking your assets.
/alert/ If you are serving your app, the recompilation of assets are not automatically reflected in your browser. You have to recompile and reserve your app again.
Watching Changes and Auto Reloading
Frontend Asset Changes
When you are tweaking the design of your app or making the interactive aspect of the app just right, you may want your assets to recompile and the browser to reload automatically as soon as you save your changes. Alpas comes wired with everything to facilitate this rapid prototyping so that you can iterate on your design faster without having to recompile everything and refreshing your browser for every small change.
This works by linking storage/src/main/web
folder to the actual src/main/resources/web
folder.
This should be done automatically when you initialized the project. But in case it isn't,
you can use the link:web
Alpas command to do this for you.
$ alpas link:web
Once the link has been created, you need to follow 2 easy steps:
- Run the app on app's default port, preferably from IntelliJ or by using the
alpas serve
command. - Open the terminal and from the root of the project run the
yarn watch
command. Keep note of the port address.
Your "auto-syncing" app should now be available at a new port, the port from Step 2 above, which is by default port 3000 i.e. the app is accessible at
To try it out, make some changes in one of your frontend assets like app.less, app.js, Welcome.vue, etc. and you will notice that after a few seconds the browser will auto-refresh with the new changes.
Template Changes
Similar to auto reloading of assets, you can also auto reload changes made to
templates without recompiling your code. Also, since this is not really
frontend asset changes, you actually don't even have to run yarn watch
in the background
to see the new changes. Although, the combined experience is more rapid.
This works by linking storage/src/main/templates
folder to the actual src/main/resources/templates
folder. This should be done automatically when you initialized the project. But in case it isn't,
you can use the link:templates
Alpas command to do this for you.
$ alpas link:templates
Code Changes
Unfortunately, Kotlin being a compiled language, your code changes won't be loaded immediately and automatically. You may have to recompile and re-serve your app for the changes to load, especially for big changes.
However, most of the time, if you are running your app from IntelliJ IDEA, you can just reload your changed classes
using Run > Reload Changed Classes
menu. If you have yarn watch
running in the background, then it can detect
the code reload changes and automatically refresh the browser for you as well. Our recommendation is to set a
shortcut for Run > Reload Changed Classes
and trigger it using the shortcut. We have set this to CMD+R
.
Cache Busting with Asset Fingerprinting
Browsers usually cache assets for performance reasons. This is all good until you change the assets. Browsers might
not know about the new changes and continue to serve the old cached assets. To force browsers to load a
fresh copy of your assets, you can append a version number to each of your asset URLs for every new version,
which is like fingerprinting your assets. This looks something like app.css?ver=1.0
.
Doing this manually is cumbersome and error prone. Luckily, Mix will append a random hash to the
filenames of all your compiled asset when you use version()
method.
let mix = require('laravel-mix')
const publicPath = 'src/main/resources/web'
const resources = 'src/main/resources'
mix.setPublicPath(publicPath)
.js([`${resources}/js/app.js`, `${resources}/js/main.js`], 'js/app.js')
.less(`${resources}/css/app.less`, 'css/app.css')
// apply versioning only in production
if(mix.inProduction()) {
mix.version()
}
Applying versioning means, to simplify, renaming your assets to some random strings. Which means
you need a consistent way to refer to these assets from your templates so that you don't have
to manually change the referenced filenames every time. For this you need to use Alpas's
mix()
function. So instead of referring assets like this:
<script src="/js/app.js"></script>
<link rel="stylesheet" href="/css/app.css">
you need refer them like so:
<script src="{{ mix('js/app.js') }}"></script>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
Setting Environment Variables
Mix will automatically read any environment variables that start with a MIX_
prefix in your .env
file and make it available on process.env
object.
Say you have a MIX_APP_PORT=8060
variable defined in your .env file, this will be
later available as process.env.MIX_APP_PORT
in your JS files.