Laravel 5.1 Beauty - Using Bower

Managing assets with bower and gulp

Posted on April 11, 2015 in L5 Beauty
Note: this is the seventh step in the tutorial.

In this chapter we’ll work on some of the supporting software the administration area will be built on. Namely, how the assets are pulled in and which assets are used. The build system will use bower and gulp to automatically download and combine jQuery, Bootstrap, Font Awesome, and DataTables from the Internet.

Chapter Contents

Stealing Code

One of the fastest ways to develop web applications is to leverage the work of others. In other words, stealing their code.

No, you’re not really stealing.

For instance, look at Twitter Bootstrap’s license. It states anyone is allowed to use, free of charge, the Bootstrap framework.

You can’t steal something that’s free.

Always look at the license of any library you use.

Point is, today’s web sites consist of many things: frameworks, utilities, libraries, assets, and so forth. It’d take forever to create a decent application if every component had to be created from scratch.

We’ll use bower to manage fetching and installing many of the packages we’ll steal.

Installing Bower

Where Should Bower Run?

Bower’s one of those utilities you can run either from your Host OS or from the Homestead VM. In this book I’ll use the Host OS, but if you have any issues just use the Homestead VM.

Decide where you’ll run bower and consistently only run it from there.

Since bower runs with NodeJS, you need to install it globally first. If you haven’t already installed bower globally, follow the instructions below.

Installing Bower Globally

~% npm install -g bower
/usr/local/bin/bower -> /usr/local/lib/node_modules/bower/bin/bower
bower@1.4.1 /usr/local/lib/node_modules/bower
├── is-root@1.0.0
[snip]

(Note you may need to use sudo or run the above command from a Windows Command Prompt with Administration privileges.)

Next create a .bowerrc file in the root of the l5beauty project. This is optional. What we’re doing here is telling bower to stash anything it downloads into the vendor directory. If you skip this step then bower will create a directory named bower_dl in your root directory and store items there.

Contents of .bowerrc

{
  "directory": "vendor/bower_dl"
}

Then install bower locally within the l5project

Installing Bower Locally

~% cd Code/l5beauty
~/Code/l5beauty% npm install bower
bower@1.4.1 node_modules/bower
├── is-root@1.0.0
├── junk@1.0.1
[snip]

Finally, create the bower.json file in the project root. This is will be where bower keeps track of packages to maintain. It’s like composer.json, but for bower.

Contents bower.json file

{
  "name": "l5beauty",
  "description": "My awesome blog",
  "ignore": [
    "**/.*",
    "node_modules",
    "vendor/bower_dl",
    "test",
    "tests"
  ]
}

Pulling in Bootstrap

Now that bower’s set up to use, let’s use it to pull some assets off from the web which we want to be part of the administration area of l5beauty.

Since we’re currently using Bootstrap, we’ll start with that (and jquery).

Installing Jquery and Bootstrap

~/Code/l5beauty% bower install jquery bootstrap --save
bower jquery#*              not-cached git://github.com/jquery/jquery.git#*
bower jquery#*                 resolve git://github.com/jquery/jquery.git#*
bower bootstrap#*           not-cached git://github.com/twbs/bootstrap.git#*
bower bootstrap#*              resolve git://github.com/twbs/bootstrap.git#*
bower jquery#*                download https://github.com/.../2.1.4.tar.gz
bower bootstrap#*             download https://github.com/.../v3.3.5.tar.gz
bower jquery#*                 extract archive.tar.gz
bower bootstrap#*              extract archive.tar.gz
bower jquery#*                resolved git://github.com/jquery/jquery.git#2.1.4
bower bootstrap#*             resolved git://github.com/....git#3.3.5
bower jquery#>= 1.9.1          install jquery#2.1.4
bower bootstrap#~3.3.5         install bootstrap#3.3.5

jquery#2.1.4 vendor/bower_dl/jquery

bootstrap#3.3.5 vendor/bower_dl/bootstrap
└── jquery#2.1.4

(Your output may vary slightly.)

Now if you look at bower.json you’ll notice two dependencies were added. One for jquery and one for bootstrap.

New dependencies in bower.json

{
  ...
  "dependencies": {
    "jquery": "~2.1.4",
    "bootstrap": "~3.3.5"
  }
}

These two packages were downloaded into the vendor/bower_dl directory.

The bower update command

To get the latest versions of any of your bower dependencies, simply run the bower update command from the root directory of the l5beauty project.

Creating admin.less

We’ll use gulp to compile Bootstrap’s less file for the administration pages. Create admin.less in the resources/assets/less directory with the following content.

Content of admin.less

@import "bootstrap/bootstrap";
@import "//fonts.googleapis.com/css?family=Roboto:400,300";

@btn-font-weight: 300;
@font-family-sans-serif: "Roboto", Helvetica, Arial, sans-serif;

body, label, .checkbox label {
  font-weight: 300;
}

First we import the bootstrap.less file (which doesn’t exist yet, we’ll copy it to the correct location with gulp shortly.) Then we import the font we’ll be using and add a few small tweaks to the CSS.

Gulping Bootstrap

Now that bower is pulling in the latest jquery and bootstrap, gulp can be used to merge it into your project.

Update gulpfile.js to match what’s below.

New gulpfile.js

var gulp = require('gulp');
var elixir = require('laravel-elixir');

/**
 * Copy any needed files.
 *
 * Do a 'gulp copyfiles' after bower updates
 */
gulp.task("copyfiles", function() {

  gulp.src("vendor/bower_dl/jquery/dist/jquery.js")
    .pipe(gulp.dest("resources/assets/js/"));

  gulp.src("vendor/bower_dl/bootstrap/less/**")
    .pipe(gulp.dest("resources/assets/less/bootstrap"));

  gulp.src("vendor/bower_dl/bootstrap/dist/js/bootstrap.js")
    .pipe(gulp.dest("resources/assets/js/"));

  gulp.src("vendor/bower_dl/bootstrap/dist/fonts/**")
    .pipe(gulp.dest("public/assets/fonts"));

});

/**
 * Default gulp is to run this elixir stuff
 */
elixir(function(mix) {

  // Combine scripts
  mix.scripts([
      'js/jquery.js',
      'js/bootstrap.js'
    ],
    'public/assets/js/admin.js',
    'resources/assets'
  );

  // Compile Less
  mix.less('admin.less', 'public/assets/css/admin.css');
});

This file changed quite a bit.

First of all we added a copyfiles gulp task. The reason we’re doing this is twofold:

  1. Gulp runs asynchronously. When files are copied they may still be being copied when they’re combined with mix.less() or mix.scripts().
  2. Copying the files only needs to occur after a bower update.

The scripts() function will combine jquery.js and bootstrap.js into one file, which we’re naming public/assets/js/admin.js. And the less() function will process the admin.less file we just created, pulling in bootstrap.

phpUnit() was removed from gulpfile.js because we’re not worried about testing in this book.

Running gulp

Since bower has been updated, run gulp copyfiles followed by gulp without any argument.

Running gulp twice

~/Code/l5beauty% gulp copyfiles
[11:54:39] Using gulpfile ~/Projects/l5beauty/gulpfile.js
[11:54:39] Starting 'copyfiles'...
[11:54:39] Finished 'copyfiles' after 19 ms

~/Code/l5beauty% gulp
[11:55:33] Using gulpfile ~/Projects/l5beauty/gulpfile.js
[11:55:33] Starting 'default'...
[11:55:33] Starting 'scripts'...
[11:55:33] Merging: resources/assets/js/jquery.js,
  resources/assets/js/bootstrap.js
[11:55:34] Finished 'default' after 106 ms
[11:55:34] Finished 'scripts' after 228 ms
[11:55:34] Starting 'less'...
[11:55:34] Running Less: resources/assets/less/admin.less
[11:55:35] gulp-notify: [Laravel Elixir] Less Compiled!
[11:55:35] Finished 'less' after 829 ms

Everything should copy, combine, and compile as expected. Examine the public/assets directory to double-check what’s expected there exists. You should have the following:

  • The directory public/assets/fonts
  • The file public/assets/css/admin.css
  • The file public/assets/js/admin.js

Updating the admin layout

Since we’re loading jQuery and Bootstrap locally now from the combined files, the administration layout can be updated. Update layout.blade.php in the resources/views/admin directory to match what’s below.

New admin layout

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>{{ config('blog.title') }} Admin</title>

  <link href="/assets/css/admin.css" rel="stylesheet">
  @yield('styles')

  <!--[if lt IE 9]>
    <script src="//oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="//oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  <![endif]-->
</head>
<body>

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed"
              data-toggle="collapse" data-target="#navbar-menu">
        <span class="sr-only">Toggle Navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">{{ config('blog.title') }} Admin</a>
    </div>
    <div class="collapse navbar-collapse" id=navbar-menu">
      @include('admin.partials.navbar')
    </div>
  </div>
</nav>

@yield('content')

<script src="/assets/js/admin.js"></script>

@yield('scripts')

</body>
</html>

The only changes were the CSS link in the header and replacing the two script lines at the bottom with the new, combined admin.js.

Go to http://l5beauty.app/admin in your browser. The administration area (and logon form) should look exactly the same as it did before.

Adding FontAwesome and DataTables

Now that bower and gulp are set up to handle our assets correctly, let’s add two more packages: Font Awesome and DataTables.

Follow the instructions below to add these packages as bower dependancies.

Adding FontAwesome and DataTables to bower

~/Code/l5beauty% bower install fontawesome --save
~/Code/l5beauty% bower install datatables --save
~/Code/l5beauty% bower install datatables-plugins --save

(We’re adding datatables-plugins in order to use bootstrap specific styles in DataTables.)

Next edit gulpfile.js to copy the needed assets into our project.

Updated gulpfile.js

var gulp = require('gulp');
var rename = require('gulp-rename');
var elixir = require('laravel-elixir');

/**
 * Copy any needed files.
 *
 * Do a 'gulp copyfiles' after bower updates
 */
gulp.task("copyfiles", function() {

  // Copy jQuery, Bootstrap, and FontAwesome
  gulp.src("vendor/bower_dl/jquery/dist/jquery.js")
      .pipe(gulp.dest("resources/assets/js/"));

  gulp.src("vendor/bower_dl/bootstrap/less/**")
      .pipe(gulp.dest("resources/assets/less/bootstrap"));

  gulp.src("vendor/bower_dl/bootstrap/dist/js/bootstrap.js")
      .pipe(gulp.dest("resources/assets/js/"));

  gulp.src("vendor/bower_dl/bootstrap/dist/fonts/**")
      .pipe(gulp.dest("public/assets/fonts"));

  gulp.src("vendor/bower_dl/fontawesome/less/**")
      .pipe(gulp.dest("resources/assets/less/fontawesome"));

  gulp.src("vendor/bower_dl/fontawesome/fonts/**")
      .pipe(gulp.dest("public/assets/fonts"));

  // Copy datatables
  var dtDir = 'vendor/bower_dl/datatables-plugins/integration/';

  gulp.src("vendor/bower_dl/datatables/media/js/jquery.dataTables.js")
      .pipe(gulp.dest('resources/assets/js/'));

  gulp.src(dtDir + 'bootstrap/3/dataTables.bootstrap.css')
      .pipe(rename('dataTables.bootstrap.less'))
      .pipe(gulp.dest('resources/assets/less/others/'));

  gulp.src(dtDir + 'bootstrap/3/dataTables.bootstrap.js')
      .pipe(gulp.dest('resources/assets/js/'));

});

/**
 * Default gulp is to run this elixir stuff
 */
elixir(function(mix) {

  // Combine scripts
  mix.scripts([
      'js/jquery.js',
      'js/bootstrap.js',
      'js/jquery.dataTables.js',
      'js/dataTables.bootstrap.js'
    ],
    'public/assets/js/admin.js',
    'resources/assets'
);

  // Compile Less
  mix.less('admin.less', 'public/assets/css/admin.css');
});

Now edit the admin.less file in resources/assets/less to match what’s below.

Content of admin.less

@import "bootstrap/bootstrap";
@import "//fonts.googleapis.com/css?family=Roboto:400,300";

@btn-font-weight: 300;
@font-family-sans-serif: "Roboto", Helvetica, Arial, sans-serif;

body, label, .checkbox label {
  font-weight: 300;
}

@import "fontawesome/font-awesome";
@import "others/dataTables.bootstrap.less";

Since we’re renaming a file using gulp instead of elixir (for that copyfiles task), we need to pull in the gulp-rename module.

Pulling in gulp-rename

%/Code/l5beauty% npm install gulp-rename --save
gulp-rename@1.2.2 node_modules/gulp-rename

Now run gulp twice. (Once to copy the files because we added bower assets and once to process and combine the assets.)

Running gulp twice

~/Code/l5beauty% gulp copyfiles
[12:52:02] Using gulpfile ~/Projects/l5beauty/gulpfile.js
[12:52:02] Starting 'copyfiles'...
[12:52:02] Finished 'copyfiles' after 31 ms

~/Code/l5beauty% gulp
[12:52:26] Using gulpfile ~/Projects/l5beauty/gulpfile.js
[12:52:26] Starting 'default'...
[12:52:26] Starting 'scripts'...
[12:52:26] Merging: resources/assets/js/jquery.js,
  resources/assets/js/bootstrap.js, resources/assets/js/jquery.dataTables.js,
  resources/assets/js/dataTables.bootstrap.js
[12:52:26] Finished 'default' after 107 ms
[12:52:26] Finished 'scripts' after 401 ms
[12:52:26] Starting 'less'...
[12:52:26] Running Less: resources/assets/less/admin.less
[12:52:30] gulp-notify: [Laravel Elixir] Less Compiled!
[12:52:30] Finished 'less' after 4.19 s

Recap

In this chapter we used bower to download jQuery, Bootstrap, Font Awesome, and Datatables from the Internet. Then gulp was used to combine everything into a single CSS file (admin.css) and a single Javascript file (admin.js).

These pieces will come together in the next chapter when we implement a tagging system for the l5beauty project.

comments powered by Disqus