Configuring JS and SASS for a Single Page App

Part 4 of 48 in API Driven Development With Laravel and VueJS
Dan Pastori avatar
Dan Pastori September 28th, 2017
⚡️ Updated content is available We learned a lot since we originally wrote this article. We now have this updated for Laravel 10, Vue 3/NuxtJS 3, and Capacitor 3.

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:

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:

{
  "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 devDependancies. 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 devDependancies 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:

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:

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:

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:

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

    require('bootstrap-sass');
} 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:

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:

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:

@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.

Keep Reading
View the course View the Course API Driven Development With Laravel and VueJS
Up Next → Structuring Vue 2, Vue Router, Vuex for a Single Page Application

Support future content

The Ultimate Guide to Building APIs and Single-Page Applications with Laravel + VueJS + Capacitor book cover.

Psst... any earnings that we make off of our book is being reinvested to bringing you more content. If you like what you read, consider getting our book or get sweet perks by becoming a sponsor.

Written By Dan

Dan Pastori avatar Dan Pastori

Builder, creator, and maker. Dan Pastori is a Laravel certified developer with over 10 years experience in full stack development. When you aren't finding Dan exploring new techniques in programming, catch him at the beach or hiking in the National Parks.

Like this? Subscribe

We're privacy advocates. We will never spam you and we only want to send you emails that you actually want to receive. One-click unsubscribes are instantly honored.