Pass to content
Laravel Mix, minus the Laravel ?

Laravel Mix, minus the Laravel ?

Frontend toolkits are exhausing!


I've been working with different front end toolkit setups for many years, switching build tools and interpreters from project to project trying to find the right fit of simplicity, ease of configuration and sustainability.  When I first started web development, we were just using straight CSS and JavaScript. But I got frustrated that CSS didn't have (at that time anyway) variables, repeatable functions or other programming structures that I had come to know with PHP, JavaScript, Java, C# etc.  So I started looking for a better solution.

I soon came across LESS, which answered pretty much most of my CSS issues entirely.  I was configuring file watchers in my IDE to compile the LESS to CSS and everything was great.  Until again I got frustrated and found that this required a decent amount of configuration in my IDE for each project which was somewhat time consuming.  I started to research a better solution again.

I discovered the everchaning world of NodeJS based build tools and dependency managers and spent the last few years playing around with, configuring and trying to optimize my tool kit with tools such as Grunt, Bower, Gulp, NPM, Sass, Webpack etc. The list really goes on and on.  All of this to render some CSS and JS that can be consumed by a browser. It seemed to be somewhat overkill to me. And for a primarily backend developer somewhat out of scope for what I like to do.

Lately I have been trying to nail down a Webpack config that works well for me. While researching a solution to an issue with my config, I rememberd that Laravel comes with Laravel Mix, it uses Webpack and it works really well, so I wanted to go take alook at the Webpack configuration it uses.  Finally the lightbulb in my head turned on and I realized I don't need to replicate what Laravel Mix is doing, I can just use Laravel Mix for the front end integration for my Perch CMS web sites.  Why reinvent the wheel when Mix is doing absolutely everything I want.  So a little research later and very little time spent, I have Laravel Mix installed and configured to integrate my site frontend CSS and JS. Its very portable between projects basically just requiring a simple Yarn or NPM install and a configuration file.

Although I mainly use Perch CMS, its not really Perch CMS dependent. You can clearly do this for pretty much any site.  The last bit will show you how to hook into the Perch CMS Feathers which is their frontend asset management system. Rembember though its completely optional and actually turned off by default in Perch CMS. I normally use the layout method to include static assets into the head or footer of the site.

Get to know Yarn and your package.json

If you're not already working with NPM or Yarn to install and mange your frontend assets stop here and go an read up about it. Its a very easy way to manage what you need for your project and keep compiled assets out of your GIT repository.  What's GIT?  Google that one too. Familiar with NPM and the package.json file? Then skip to the next section.  Not sure what Yarn is? Basically does the same thing as NPM just faster in my opinion for my limited usage needs. Plus it has nice little emoji in the terminal too.

Yarn and NPM both use the package.json file to manage development and production dependencies for your web projects.  They also have a handy scripts section where you can define named command scripts that can be run with a simple Yarn run or NPM run terminal command.  This makes integrating your site frontend a breeze if you're scripting a deployment pipeline and you're like me and don't like to keep compiled assets in your projects repository.

I really only use Yarn these days, its just so much faster, I've seen build scripts for large projects that take 30 seconds to 2 min or more to compile with NPM that take a fraction of the time with Yarn.  So any further commands in this post will be using Yarn but you can easly find the NPM equivalent.

Laravel Mix Installation

To do the base Laravel Mix install all you need to do to add the dependency to your project using Yarn:

$ yarn add -D laravel-mix

This will update the package.json file and install laravel-mix to the node_modules directory in your project.  Now you need a laravel mix configuration file.  In the same directory as your package.json, create a new file webpack.mix.js.

I'll share my mix configuration here:


let mix = require('laravel-mix');
mix.setPublicPath('public');
mix.setResourceRoot('/');
mix.js('src/javascript/main.js', 'dist/')
   .sass('src/sass/main.scss', 'dist/')
   .sourceMaps()
   .version();

Lets go over it line by line:

1. Require laravel-mix from node_modules so you can use the mix object.


let mix = require('laravel-mix');

2. Configure the path to the web accessible public folder.  This is where your index.php file or .htaccess (if using Perch Runway) is.


mix.setPublicPath('public');

3. Tell Mix to use '/' instead of '/public' as the resource root path for assets like images, fonts during compilation.


mix.setResourceRoot('/');


4. Define the source JavaScript entry point and the destination relative to the resource root you just configured. So here Mix will look for a main.js file in src/javascript then compile to  public/dist/main.js


mix.js('src/javascript/main.js', 'dist/')

5. Same thing for your Sass.  Define the Sass entry point and destination.


   .sass('src/sass/main.scss', 'dist/')

6. Enable source maps for the development build. They don't get created for production.


   .sourceMaps()

7. Produce a mix-manifest.json file. This is for long term cache busting so that you can configure your server to cache CSS and JS for a long period but still deliver new assets when they arrive.  


   .version();

Here is an example of a mix-manifest.json file:


{    
    "/dist/main.js": "/dist/main.js?id=ecfe06d840525bff34b2",
    "/dist/main.css": "/dist/main.css?id=5b13608ecbc9f614ba25"
}

To use the mix-manifest.json, your php reads the file into an array and you use the array value in the CSS link tag href attribute and JS script tag src attribute.   As your implement changes to your source files, the id hash changes in the json triggering the browser to request a new file and not use the cached version. This ensures that you can cache your assets longterm but deliver new ones as needed.

Compiling your Frontend with Laravel Mix

So great, we have Laravel Mix installed, now what?  We want our sass and js compiled to usable assets for your browers right ? You need to know a couple terminal commands to use Laravel Mix first.  Luckily they are well documented and easily copied and pasted.   First you'll need to create a scripts section if it doesn't already exist in your package.json file.  Then add the following so you have something like:


"scripts": {
  "dev": "NODE_ENV=development webpack --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
  "watch": "NODE_ENV=development webpack --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
  "production": "NODE_ENV=production webpack --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
}

These scripts are run using the Yarn run command and specifying the script name such as:


$ yarn run dev

or


$ yarn run watch

or


$ yarn run production


The first time you run Laravel Mix, it will install a couple of extra dependencies it needs to do its job.  It will then ask you to run Laravel Mix again and then you're good to go.

For production builds, use "production", clearly... it will not include source maps and everything will be nicely bundeled up ready for prod. I use this in my build pipeline when deploying on the stage or production server.

For one-off development builds, use "dev", it will include source maps making the inspection nice and easy in your browser dev tools mapping the css properties back to your scss files. Same for your javascript includes and requires.

For active development, use the "watch" command. It will continue to run the basic dev build unattended in the terminal and watch for changes in your src files, then recompile and notify you through a system notification when the build is ready.  Hit refresh and your changes are there.

There are other scripts like "hot" which starts up a server and serves the application automatically refeshing the browser when ready, but that may require more configuration and would be for another post.

Consuming your assets in Perch CMS - Layout Method

This is my preferred method. Create a new global layout that gets added to each page with some code similar to include :


$manifestFile = __DIR__ . '/path/to/mix-manifest.json';
$cssAsset = '/dist/main.css';
$jsAsset = '/dist/main.js';
if (file_exists($manifestFile)) {
    $manifest = json_decode(file_get_contents($manifestFile), true);
    if (is_array($manifest)) { 
         if (array_key_exists($cssAsset, $manifest)) {
            echo '<link type="text/css" rel="stylesheet" media="all" href="' . $manifest[$cssAsset] . '" />';
         }
        
         if (array_key_exists($jsAsset, $manifest)) {
            echo '<script defer src="' . $manifest[$jsAsset] . '"></script>';
         }
    }
}

Consuming your assets in Perch CMS - Feathers Method

First you need to enable feathers through your config.php file.  You can read the official documentation for Perch Feathers here.  There isn't much to change to use feathers, all you really need to do is to use the similar php code in the PerchFeather_MyFeather object as the above but change the path to the mix.manifest.json file to add a few '/../../' to bring the relative back back to the public root where the mix-manifest.json file is compiled.  Then rather than building the link and script tags, register the links and scripts as documented in the Pearch Feathers official documentation.


A feather class similar to the following should work :


<?php
PerchSystem::register_feather('MyFeather');
class PerchFeather_MyFeather extends PerchFeather
{  
    private $manifestFile = __DIR__ . '/../back-to-public/../path/to/mix-manifest.json';
    private $cssAsset = '/dist/main.css';
    private $jsAsset = '/dist/main.js';
    private function get_manifest() {
        if (file_exists($this->manifestFile)) {
            return json_decode(file_get_contents($this->manifestFile), true);
        }
        return [];
    }
    public function get_css($opts, $index, $count)    {
        $manifest = $this->get_manifest();
        if (is_array($manifest) && array_key_exists($this->cssAsset, $manifest)) { 
            return $this->_link_tag([
                'rel'  => 'stylesheet',
                'href' => $manifest[$this->cssAsset],
                'type' => 'text/css',
            ]);
        }
        return true;      
    }
    public function get_javascript($opts, $index, $count)    {
        $manifest = $this->get_manifest();
        if (is_array($manifest) && array_key_exists($this->jsAsset, $manifest)) { 
            return $this->_script_tag('link', [
                'src' => $manifest[$this->jsAsset],
            ]);
        }
        return true;      
    }
}

Finishing things up

And there you go using Laravel Mix to compile your front end assets for Perch CMS.  Clearly its not limited to Perch, but integrates very nicely and so simple to setup its become my go-to toolkit.  I don't have to think about any of the configuration and has a huge online community so if you're looking for something specific, chances are someones already done it and documented it.

Thanks fo reading!

Categories: Web Development PHP HTML / CSS JavaScript SASS Perch CMS Laravel

Leave a comment

Comments and responses

  • 18 Dec 2019 06:58:00

    Hello Jordin,
    Thanks for the great post, very concise.
    I’m attempting to implement Laravel Mix rather than my Gulp implementation.
    Adding the code to my head section, I had an echo error, which was I believe was a missing closing bracket around ‘if (array_key_exists($cssAsset, $manifest)’. Adding the closing bracket means I get no errors, but I also see no .
    I am creating the mix-manifest.json and the css/js files.
    As I’m not really a PHP person could you possibly point me to where I may be going wrong?

  • 23 Jan 2020 11:23:47

    Hi Will,

    Thanks for catching the typo in with the array_key_exists. I’ve updated the post to fix.
    For your issue, you’ll need to ensure that your asset is in the manifest array. You can do that by doing a var_dump($mainfest) to validate that its being properly loaded.