Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

 

Solving build tool woes with Laravel Mix

Setting up build tools can be frustrating. Enter Laravel Mix – with this tool, your build chain is managed almost completely for you, and you can use all the latest and greatest JS libraries and syntax with practically zero configuration.

Read post

One of the most time-consuming and frustrating parts of modern front-end web development is setting up build tooling. As an industry, we've been through a lot of different tools in recent history – some easier to work with than others – and one popular option in 2017 is Webpack. While incredibly powerful, unfortunately at first glance many Webpack configuration files make very little sense, and even with some help from Tanya at nz.js(con), I've personally found myself struggling to produce the output I need in a timely manner.

Enter Laravel Mix. With this tool, your build chain is managed almost completely for you, and you can use all the latest and greatest JS libraries and syntax with practically zero configuration. Bespoke teams at SilverStripe are starting to adopt this quite widely, and are seeing extremely positive results. Let's walk through the basics!

Ignore the 'Laravel' part

Before we start, some clarification. Mix can be used in any project – even one without any PHP at all! Laravel Mix (previously Laravel Elixir) was originally developed to be used in tandem with the Laravel framework and is named as such, but has no dependency on it, and works perfectly in SilverStripe projects or anything else you might need it for.

Getting started

First off, you'll need to add Mix to your project, along with cross-env to allow building in different environments:

# Yarn
> yarn add laravel-mix cross-env --dev

# NPM
> npm install laravel-mix cross-env --save-dev

Then you'll want to copy the default Mix configuration into your project root:

> cp node_modules/laravel-mix/setup/webpack.mix.js .

Now you can open this new configuration file and start pointing Mix at your source code using the mix object. There are several methods, but your go-tos will generally be js() and scss(). To compile the scripts and styles for a basic SilverStripe theme, your configuration would look something like this (assuming your source files are in the correct place):

let mix = require('laravel-mix')

const themepath = 'themes/demo'
const distpath = themepath + '/dist/'

mix.js(`${themepath}/js/app.js`, distpath)
   .sass(`${themepath}/scss/app.scss`, distpath)
   .sass(`${themepath}/scss/editor.scss`, distpath)

Time to compile! The full commands are pretty long and annoying to remember, so we'll add some shortcuts to package.json that are more memorable:

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

Now we can run our first build:

# Yarn
> yarn run once

# NPM
> npm run once

You should see a 'Compiled successfully' message, along with a list of files that have been generated. Congratulations, your app is now ready to go! (You might need to actually finish writing it first, of course.)

During development, you can use yarn run dev to start Mix in watch mode, so it will continuously rebuild your app as you change files. For a production release, call yarn run production – this will build with minification and other optimisations.

What it's actually doing

Mix runs Babel with the ES2015 preset across your Javascript, and the PostCSS autoprefixer plugin across your SASS – meaning you can use the latest and greatest features of both languages, and backwards compatibility with older browsers will generally be maintained. There are exceptions – for example, some recent ES features won't have polyfills applied, such as Object.assign(). In these cases, you'll need to add additional Babel/PostCSS plugins to your dependency list and either write your own .babelrc config, similar to the following example:

{
  "plugins": [
    "transform-object-assign",
  ],
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 2%"],
        "uglify": true
      }
    }]
  ]
}

...or add the new PostCSS plugin to your Mix config:

...
mix.config({ postCss: [require('cssnext')] })

Other fancy stuff

Of course, there are a few more features you might find useful.

Building React apps

Thanks to its unique syntax, React applications containing JSX won't build using the normal js() mix method. You'll want to use react() instead:

mix.react(`${themepath}/js/react-app.js`, distpath)

Extracting and autoloading libraries

It can be wasteful to have your users redownload the JS libraries you depend on when making minor changes to application code, so you can extract these into a separate file:

mix.extract(['axios'], `${distpath}vendor.js`)

You can also set up global references to libraries – useful for situations where a legacy dependency doesn't use imports (e.g. most jQuery plugins):

mix.autoload({ jquery: ['$', 'window.jQuery'] })

Adding ESLint

Automatically linting code during builds is a great way to ensure teams produce consistently formatted output. ESLint is a good choice for checking your JavaScript, and it's quite simple to add to a Mix-based project. First, install ESLint:

> yarn add eslint eslint-config-airbnb

Next, add an ESLint rule to Webpack via the mix.webpackConfig() method (notice we're only applying this in development builds):

if (process.env.NODE_ENV === 'development') {
  mix.webpackConfig({
    module: {
      rules: [
        {
          test: /\\.(js)$/,
          exclude: /node_modules/,
          loader: 'eslint-loader',
        },
      ],
    },
  });
}

To make the most of ESLint, you'll need a .eslintrc file for it. Here's a simple AirBnB-based config to get you started:

{
  "extends": "airbnb",
  "env": {
    "browser": true,
    "commonjs": true,
    "es6": true,
    "node": true
  }
}

Modifying Mix's Webpack configuration

If you find yourself adding a large amount of custom configuration, you can also copy the base configuration file Mix uses into your root directory and edit that directly:

> cp node_modules/laravel-mix/setup/webpack.config.js .

You'll also need to update the paths in your package.json methods to use your local version of the file:

...
  "scripts": {
    "once": "node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=webpack.config.js",
    "dev": "node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=webpack.config.js",
    "production": "node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=webpack.config.js"
  },
...

Putting it all together

SilverStripe developer Ben Manu is putting together an excellent SilverStripe skeleton project that utilises Laravel Mix and provides a great base for starting any size or type of SilverStripe-based application.

Summary

Mix provides a wide enough API that it should cover most uses, but in the case that you find any edge-cases, take a look at the project on GitHub and consider contributing an improvement.

Next time you're getting started on any project that requires front-end asset compilation, be sure to take Mix for a test drive!

About the author
Garion Herman

Garion is a bespoke developer in the Silver Sabers team at SilverStripe, previously forming a part of the Operations team.

He has a broad interest in Web Development, from great user interfaces to strong infrastructure, and is currently focussed on front-end development using Vue and other libraries.

Away from the office, Garion enjoys a few drinks with good company and causing mayhem in a variety of video games.

Post your comment

Comments

  • Had a hard time getting laravel mix running under Windows 10. After some time of debugging, reinstalling using npm, rebuilding etc. I finally found out to add "node" to the npm scripts. Like:

    "once": "node node_modules/cross-env/dist/bin/cross-env.js ..."

    Posted by Werner Krauß, 14/06/2017 1:20am (5 months ago)

RSS feed for comments on this page | RSS feed for all comments

Like what you have read?

Sign up for our weekly blog digest sent to your inbox.

Subscribe