API Driven Development With Laravel and VueJS (Part 4 of 38)

Configuring JS and SASS for a Single Page App

Dan Pastori

September 28th, 2017

So far we haven't made any front end changes. Our app so far is simply just a bunch of back end tools and configuration. We installed Laravel (https://serversideup.net/installing-configuring-laravel-spa/), configured Laravel Socialite (Installing And Configuring Laravel Socialite - Server Side Up), and configured Laravel Passport (https://serversideup.net/installing-configuring-laravel-passport/). Now we will begin structuring our front end for our app.

Once again Laravel comes in clutch with Laravel Mix Compiling Assets (Laravel Mix) - Laravel - The PHP Framework For Web Artisans. You don't have to worry much about any of the complex Webpack configurations, sass configurations, or any of the build tools. We will still be using NPM, but Laravel mix will handle all of the building and compiling. Developers can even use mix outside of Laravel which is awesome!

Step 1: Inspect /webpack.mix.js

Laravel ships with a default configuration for Laravel Mix. If you visit webpack.mix.js in your root directory you will see a file that looks like:

Default Laravel Mix Configuration

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

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css');

For our app this will solve our needs. What this is doing is requiring the 'laravel-mix' NPM module in the first line.

The next group of code is the magic of Laravel Mix. It simply chains together a mix method. In mix.js, the first parameter is the location of your app.js file and the second is where that will compile and export to which will be the public/js directory. What Laravel Mix will do is use the resources/assets/js/app.js file as the entry point and build out a file named app.js and dump it in the public/js directory.

The sass command operates the exactly same way as the .js method. It takes the entry point from resources/assets/sass/app.scss and dumps a compiled css file to named app.scss to the public/css directory.

These we will keep the same since it will be easy to maintain. More complex apps can run multiple mix commands or change the directory, file names, etc.

Step 2: Inspect package.json

First we will inspect the package.json file in the root directory of the app. You should see something like this:

Default package.json Configuration

{
  "private": true,
  "scripts": {
    "dev": "npm run development",
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch-poll": "npm run watch -- --watch-poll",
    "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "prod": "npm run production",
    "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  },
  "devDependencies": {
    "axios": "^0.16.2",
    "bootstrap-sass": "^3.3.7",
    "cross-env": "^5.0.1",
    "jquery": "^3.1.1",
    "laravel-mix": "^1.0",
    "lodash": "^4.17.4",
    "vue": "^2.1.10"
  }
}

This is preconfigured from your Laravel install and contains a few scripts and devDependencies. When building your app on your development machine, you will want to run either: npm run dev or npm run watch. I prefer to open a terminal window and start npm run watch. This will watch your JS/SCSS files and whenever you save a change it will re-compile your changes to the appropriate file. When you want to run production, simply run npm run production and your assets will be minified and ready for production use.

As for some of the packages, we will use all of what is in the devDependencies object except "bootstrap-sass". We will be removing Twitter Bootstrap in favor of Zurb Foundation The most advanced responsive front-end framework in the world. | Foundation

Axios is an awesome HTTP client for JS and works seamlessly with Vue. It's documentation can be found here: https://github.com/mzabriskie/axios.

jQuery will be used by foundation, and of course vue will be the center point of our SPA.

Step 3: Remove Bootstrap (optional)

If you want to follow along completely with our tutorial, run the following commands first to remove bootstrap: 1. npm remove bootstrap --save-dev 2. npm remove bootstrap-sass --save-dev

These will remove all of the Twitter Bootstrap functionality.

Next go to your /resources/assets/js/app.js file and change the remove the following line:

Bootstrap Import to Remove

require('./bootstrap');

This will remove the reference the file: /resources/assets/js/bootstrap.js. We will be merging what that file contains into our app.js file.

Next go to your terminal window and run npm install foundation-sites --save-dev. This will make sure foundation is included in your project.

Update 10/12/2017 I found a bug transpiling es5 with foundation and found the solution:https://github.com/JeffreyWay/laravel-mix/issues/949#issuecomment-314406812. The bug happens when running a production build. The solution is below and what your webpack.mix.js file should look like:

Updated Webpack Mix Configuration with Foundation Support

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

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/assets/js/app.js', 'public/js')
    .webpackConfig({
         module: {
             rules: [
                 {
                     test: /\.jsx?$/,
                     exclude: /node_modules(?!\/foundation-sites)|bower_components/,
                     use: [
                         {
                             loader: 'babel-loader',
                             options: Config.babel()
                         }
                     ]
                 }
             ]
         }
     })
   .sass('resources/assets/sass/app.scss', 'public/css');

Step 4: Configure app.js

We've got a little bit of work to do to structure our app for scalability. Laravel ships some of the default functionality for starting an SPA in the /resources/assets/js/bootstrap.js file. I don't like this file, and since we will be structuring our app in a way to organize Vue components, pages, Vuex modules, I say we will remove this file and merge it into /resources/assets/js/app.js

Navigate to your resources/assets/js/bootstrap.js file and grab the following line from the top:

Lodash Import

window._ = require('lodash');

and add that right away to the top of your /resources/assets/js/app.js file.

Next we will grab the following try, catch block and move it right under the last line copied on top of the app.js file:

jQuery and Foundation Setup

try {
    window.$ = window.jQuery = require('jquery');

    require('foundation-sites');
} catch (e) {}

Then change the following line from:

require('bootstrap-sass')

to

require('foundation-sites')

if you are removing Twitter Bootstrap.

Last, grab the next chunk of code that configures Axios and add that to your app.js file.

Your file will now look like this:

Complete app.js Configuration

window._ = require('lodash');

try {
    window.$ = window.jQuery = require('jquery');

    require('foundation-sites');
} catch (e) {}

window.Vue = require('vue');

/**
 * We'll load the axios HTTP library which allows us to easily issue requests
 * to our Laravel back-end. This library automatically handles sending the
 * CSRF token as a header based on the value of the "XSRF" token cookie.
 */

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
 * Next we will register the CSRF Token as a common header with Axios so that
 * all outgoing HTTP requests automatically have it attached. This is just
 * a simple convenience so we don't have to attach every token manually.
 */

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

Vue.component('example', require('./components/Example.vue'));

const app = new Vue({
    el: '#app'
});

What the axios configuration does is include the X-CSRF-TOKEN to the the headers for each request sent. This will automatically allow access to the API and proper CSRF protection.

Lastly, remove the following lines: window.Vue = require('vue'); and

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */

Vue.component('example', require('./components/Example.vue'));

The first line removes Vue which you may be wondering why. Don't worry, in the next tutorial we will add it back in when we install the Vue ecosystem.

The second chunk of lines removes the default Vue component. This we just don't need.

Our /resources/assets/js/app.js file should look like:

Final app.js Configuration

window._ = require('lodash');

try {
    window.$ = window.jQuery = require('jquery');

    require('foundation-sites');
} catch (e) {}

/**
 * We'll load the axios HTTP library which allows us to easily issue requests
 * to our Laravel back-end. This library automatically handles sending the
 * CSRF token as a header based on the value of the "XSRF" token cookie.
 */

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
 * Next we will register the CSRF Token as a common header with Axios so that
 * all outgoing HTTP requests automatically have it attached. This is just
 * a simple convenience so we don't have to attach every token manually.
 */

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

const app = new Vue({
    el: '#app'
});

Notice that Vue is binding to an el: '#app'? That is an element referenced in our app.blade.php file that we created in Installing and Configuring Laravel SPA. Vue will bind to this element and work it's magic with the Vue Router!

Step 5: Remove Unnecessary JS

Now we remove the unnecessary javascript.

  1. Remove: /resources/assets/js/bootstrap.js since we merged this into our app.js.
  2. Remove: /resources/assets/js/components directory. We will re-add some of these directories in the next tutorial

Step 6: Configure SASS

There are 2 things we need to do to configure SASS for our project.

First, if you are using Foundation, open up /resources/assets/sass/app.scss and clear out the contents. Then add the following line: @import "node_modules/foundation-sites/assets/foundation.scss";

Your entire app.scss file should look like:

Foundation SASS Import

@import "node_modules/foundation-sites/assets/foundation.scss";

Next remove: /resources/assets/sass/_variables.scss . We will use a variables.scss file but not the one loaded with Laravel. We will be using a variables file, but we will place it in a different directory.

Step 7: Set up SASS directories

SASS makes CSS so much easier, but structuring it by a standard is the icing on the cake. When building an app I follow the 7-1 Pattern for structuring SASS: Sass Guidelines

The only difference is I keep app.scss instead of their recommended main.scss file.

To configure the app for the 7-1 Pattern build the following directories: 1. /resources/assets/sass/base 2. /resources/assets/sass/components 3. /resources/assets/sass/layouts 4. /resources/assets/sass/pages 5. /resources/assets/sass/themes 6. /resources/assets/sass/abstracts 7. /resources/assets/sass/vendors

In the Sass Guidelines: Sass Guidelines it runs through what should be in each directory. This is super helpful when laying out your app. We will be heavily utilizing the components directory to style our web components.

Conclusion

In the next tutorial we will be focusing on VueJS and all of the sweet Vue ecosystem (Vue-Router and Vuex) extensions. We will build some more folders and get that section structured behind the scenes as well. I also promise that Roast will start becoming more useful in more tutorials. We are just building the foundation for our Single Page App right now, but soon we will be adding routes, displaying data, implementing components, etc.

Want to work together?

Professional developers choose Server Side Up to ship quality applications without surrendering control. Explore our tools and resources or work directly with us.

Join our community

We're a community of 3,000+ members help each other level up our development skills.

Platinum Sponsors

Active Discord Members

We help each other through the challenges and share our knowledge when we learn something cool.

Stars on GitHub

Our community is active and growing.

Newsletter Subscribers

We send periodic updates what we're learning and what new tools are available. No spam. No BS.

Sign up for our newsletter

Be the first to know about our latest releases and product updates.

    Privacy first. No spam. No sharing. Just updates.