June 15, 2017

Laravel Mix in a non-Laravel project

Recently, I've been looking to make a Craft CMS powered site a full single page app using Vue JS. Typically for these kind of SPAs there are generators like Vue Cli (or Create React App for React) that will scaffold the app for you and configure things like Vue Router etc. However, I needed to use Craft's templating language for some parts in lieu of a fully restful API.

I've had good mileage with Vue Cli myself but as soon as I've wanted my tooling to do something (like integrate BrowserSync for instance) then I've quickly become bogged down in understanding the Webpack configuration.

Laravel Mix makes things much simpler.

Have a quick watch of the video below to get an idea of what Mix is and what it can do.

Jeffrey Way introduces Laravel Mix to Laravel 5.4

So, how am I using this with Craft and what for?

Previously, I had a set of Gulp tasks that would compile Sass, JavaScript and watch for changes in Twig templates and refresh via BrowserSync. A pretty common scenario. However, starting to write ES6 (or ECMAScript 2015 Language) JavaScript meant that I needed to transpile for browsers that didn't support it. Enter Mix.

First steps

If you don't already have one defined, initialise an npm project. You will need to have Node and NPM installed globally for this.

cd myCraftSite
npm init -y
npm i laravel-mix --save-dev
cp -r node_modules/laravel-mix/setup/** ./

That should then give you

  • node_modules/
  • package.json
  • webpack.config.js
  • webpack.mix.js

Next, I need to configure some actual npm build scripts. Inside my package.json - amend your scripts object

"scripts": {
  "dev": "cross-env NODE_ENV=development webpack --progress --hide-modules",
  "watch": "cross-env NODE_ENV=development webpack --watch --progress --hide-modules",
  "hot": "cross-env NODE_ENV=development webpack-dev-server --inline --hot",
  "production": "cross-env NODE_ENV=production webpack --progress --hide-modules
}

All of this info (and more) can be found on the Github install options for Mix.

The tasks above mean I can do npm run dev to get a dev version of CSS & JS, npm run watch listens for changes in my source Sass and JS and builds them, npm run hot give me Hot Module Reloading which I'll touch on later and npm run production compiles a production build of assets.

From here I don't need to change anything other than my webpack.mix.js file. That looks like:

let mix = require('laravel-mix);

let buildPath = 'build/'

mix.setPublicPath('public')
  .js('src/js/app.js', buildPath + 'js/')
  .sass('src/sass/app.sass', buildPath + 'css/')
  .browserSync({
    proxy: 'mycraftapp.dev',
    files: [
      'craft/templates/**/*.twig'
    ]
  })

So what does this actually do? let buildPath = 'build/' sets the output path relative to our public path in my case public - the default webroot for Craft that we then define on line 6.

From there, I set my JS task to transpile app.js to the same filename in my build directory and our app.sass to the same place (inside respective js and css directories).

I've then added BrowserSync telling it to listen to my virtualhost and refresh on changes to any Twig templates.

Of course, I still haven't let Craft know about my new JS and CSS. I wanted to use Webpack's Hot Module Reloading that watches changes and injects them into the page without a refresh and so I got a little stuck at this point.

For this to work, I had to define my _master.twig Craft layout file like so:

{% if craft.config.devMode %}
<script src="http://localhost:8080/js/app.js"></script>
{% else %}
<script src="/build/js/app.js"></script>
{% endif %}

http://localhost:8080 is the Webpack dev server instance that runs during npm run hot but the way that works means that your JS and CSS don't actually exist in your build directories until you either npm run dev or npm run production.

That's all there is to it. I find much simpler than having a bunch of Gulp tasks defined.

I will have some other posts coming up that focus on writing a single page app with VueJS and Craft, so stay tuned for those.

Leave Your Comments