css injection – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Sat, 30 Nov 2019 21:47:27 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 css injection – CSS-Tricks https://css-tricks.com 32 32 45537868 Gulp for Beginners https://css-tricks.com/gulp-for-beginners/ https://css-tricks.com/gulp-for-beginners/#comments Tue, 01 Sep 2015 13:00:19 +0000 http://css-tricks.com/?p=207144 Gulp is a tool that helps you out with several tasks when it comes to web development. It’s often used to do front end tasks like:

  • Spinning up a web server
  • Reloading the browser automatically whenever a file is saved


Gulp for Beginners originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Gulp is a tool that helps you out with several tasks when it comes to web development. It’s often used to do front end tasks like:

  • Spinning up a web server
  • Reloading the browser automatically whenever a file is saved
  • Using preprocessors like Sass or LESS
  • Optimizing assets like CSS, JavaScript, and images

Important Note! This article was written for Gulp 3.x, but now Gulp 4.x is out and recommended. Like any major version change, APIs have breaking changes. If you install Gulp 4 and try to do some of the things in this article, they won’t work. We’ll make some notes of that sprinkled through here to remind you. This looks like a pretty good Gulp 4 starter.

This is not a comprehensive list of things Gulp can do. If you’re crazy enough, you can even build a static site generator with Gulp (I’ve done it!). So yes, Gulp is extremely powerful, but you’ll have to learn how to use Gulp if you want to create your own customized build processes.

So that’s what this article is for. It helps you get so good with the basics of Gulp that you can begin exploring everything else for yourself.

Before we dive into working with Gulp, let’s talk about why you may want to use Gulp as opposed to other similar tools.

Why Gulp?

Tools like Gulp are often referred to as “build tools” because they are tools for running the tasks for building a website. The two most popular build tools out there right now are Gulp and Grunt. (Chris has a post on getting started with Grunt here). But there are others of course. Broccoli focuses on asset compilation, one of the most common build tool tasks.

There are already multiple articles covering the difference between Grunt and Gulp and why you might use one over another. You can check out this article, this one, or this if you’re interested in finding out more. Brunch is similar in its focus on assets, and it bundles in some of the most common other tasks like a server and file watcher.

The main difference is how you configure a workflow with them. Gulp configurations tend to be much shorter and simpler when compared with Grunt. Gulp also tends to run faster.

Let’s now move on and find out how to setup a workflow with Gulp.

What we’re setting up

By the end of this article, you’ll have a workflow that does the tasks we outlined at the beginning of this article:

  • Spins up a web server
  • Compiles Sass to CSS
  • Refreshes the browser automatically whenever you save a file
  • Optimizes all assets (CSS, JS, fonts, and images) for production

You’ll also learn how to chain together different tasks into simple commands that are easy to understand and execute.

Let’s begin by installing Gulp onto your computer.

Installing Gulp

You need to have Node.js (Node) installed onto your computer before you can install Gulp.

If you do not have Node installed already, you can get it by downloading the package installer from Node’s website.

When you’re done with installing Node, you can install Gulp by using the following command in the command line:

$ sudo npm install gulp -g

Note: Only Mac users need the sudo keyword. (See the first comment by Pawel Grzybek if you don’t want to use sudo). And remember the “$” in the code above just symbolizes the command prompt. That’s not actually part of the command you run.

The npm install command we’ve used here is a command that uses Node Package Manager (npm) to install Gulp onto your computer.

The -g flag in this command tells npm to install Gulp globally onto your computer, which allows you to use the gulp command anywhere on your system.

Mac users need the extra sudo keyword in the command because they need administrator rights to install Gulp globally.

Now that you have Gulp installed, let’s make a project that uses Gulp.

Creating a Gulp Project

First, we’ll create a folder called project to server as our project root as we move through this tutorial. Run the npm init command from inside that directory:

# ... from within our project folder
$ npm init

The npm init command creates a package.json file for your project which stores information about the project, like the dependencies used in the project (Gulp is an example of a dependency).

npm init will prompt you:

Once the package.json file is created, we can install Gulp into the project by using the following command:

$ npm install gulp --save-dev

This time, we’re installing Gulp into project instead of installing it globally, which is why there are some differences in the command.

You’ll see that the sudo keyword isn’t required because we’re not installing Gulp globally, so -g is also not necessary. We’ve added --save-dev, which tells the computer to add gulp as a dev dependency in package.json.

If you check the project folder when the command has finished executing, you should see that Gulp has created a node_modules folder. You should also see a gulp folder within node_modules.

We’re almost ready to start working with Gulp. Before we do so, we have to be clear on how we’re going to use Gulp for the project, and part of that is deciding on a directory structure.

Determining Folder Structure

Gulp is flexible enough to work with any folder structure. You’ll just have to understand the inner workings before tweaking it for your project.

For this article, we will use the structure of a generic webapp:

  |- app/
      |- css/
      |- fonts/
      |- images/ 
      |- index.html
      |- js/ 
      |- scss/
  |- dist/
  |- gulpfile.js
  |- node_modules/
  |- package.json

In this structure, we’ll use the app folder for development purposes, while the dist (as in “distribution”) folder is used to contain optimized files for the production site.

Since app is used for development purposes, all our code will be placed in app.

We’ll have to keep this folder structure in mind when we work on our Gulp configurations. Now, let’s begin by creating your first Gulp task in gulpfile.js, which stores all Gulp configurations.

Writing Your First Gulp Task

The first step to using Gulp is to require it in the gulpfile.

var gulp = require('gulp');

The require statement tells Node to look into the node_modules folder for a package named gulp. Once the package is found, we assign its contents to the variable gulp.

We can now begin to write a gulp task with this gulp variable. The basic syntax of a gulp task is:

gulp.task('task-name', function() {
  // Stuff here
});

task-name refers to the name of the task, which would be used whenever you want to run a task in Gulp. You can also run the same task in the command line by writing gulp task-name.

To test it out, let’s create a hello task that says Hello Zell!.

gulp.task('hello', function() {
  console.log('Hello Zell');
});

We can run this task with gulp hello in the command line.

$ gulp hello

The command line will return a log that says Hello Zell!.

Gulp tasks are usually a bit more complex than this. It usually contains two additional Gulp methods, plus a variety of Gulp plugins.

Here’s what a real task may look like:

gulp.task('task-name', function () {
  return gulp.src('source-files') // Get source files with gulp.src
    .pipe(aGulpPlugin()) // Sends it through a gulp plugin
    .pipe(gulp.dest('destination')) // Outputs the file in the destination folder
})

As you can see, a real task takes in two additional gulp methods — gulp.src and gulp.dest.

gulp.src tells the Gulp task what files to use for the task, while gulp.dest tells Gulp where to output the files once the task is completed.

Let’s try building a real task where we compile Sass files into CSS files.

Preprocessing with Gulp

We can compile Sass to CSS in Gulp with the help of a plugin called gulp-sass. You can install gulp-sass into your project by using the npm install command like we did for gulp.

We’d also want to use the --save-dev flag to ensure that gulp-sass gets added to devDependencies in package.json.

$ npm install gulp-sass --save-dev

We have to require gulp-sass from the node_modules folder just like we did with gulp before we can use the plugin.

var gulp = require('gulp');
// Requires the gulp-sass plugin
var sass = require('gulp-sass');

We can use gulp-sass by replacing aGulpPlugin() with sass(). Since the task is meant to compile Sass into CSS, let’s name it sass.

gulp.task('sass', function(){
  return gulp.src('source-files')
    .pipe(sass()) // Using gulp-sass
    .pipe(gulp.dest('destination'))
});

We’ll need to provide the sass task with source files and a destination for the task to work, so let’s create a styles.scss file in the app/scss folder. This file will be added to the sass task in gulp.src.

We want to output the eventual styles.css file to the `app/css` folder, which would be the destination for gulp.dest.

gulp.task('sass', function(){
  return gulp.src('app/scss/styles.scss')
    .pipe(sass()) // Converts Sass to CSS with gulp-sass
    .pipe(gulp.dest('app/css'))
});

We’ll want to test that the sass task is working as we want it to. To do so, we can add a Sass function within styles.scss.

// styles.scss
.testing {
  width: percentage(5/7);
}

If you run gulp sass in the command line, you should now be able to see that a styles.css file was created in app/css. In addition, it has the code where percentage(5/7) was evaluted into 71.42857%.

/* styles.css */
.testing {
  width: 71.42857%; 
}

That’s how we know that the sass task works!

Sometimes we need the ability to compile more than one .scss file into CSS at the same. We can do so with the help of Node globs.

FYI: Gulp-sass uses LibSass to convert Sass into CSS. It’s much quicker than Ruby-based methods. If you want, you can still use Ruby methods with Gulp by using gulp-ruby-sass or gulp-compass instead.

Globbing in Node

Globs are matching patterns for files that allow you to add more than one file into gulp.src. It’s like regular expressions, but specifically for file paths.

When you use a glob, the computer checks file names and paths for the specified pattern. If the pattern exists, then a file is matched.

Most workflows with Gulp tend to only require 4 different globbing patterns:

  1. *.scss: The * pattern is a wildcard that matches any pattern in the current directory. In this case, we’re matching any files ending with .scss in the root folder (project).
  2. **/*.scss: This is a more extreme version of the * pattern that matches any file ending with .scss in the root folder and any child directories.
  3. !not-me.scss: The ! indicates that Gulp should exclude the pattern from its matches, which is useful if you had to exclude a file from a matched pattern. In this case, not-me.scss would be excluded from the match.
  4. *.+(scss|sass): The plus + and parentheses () allows Gulp to match multiple patterns, with different patterns separated by the pipe | character. In this case, Gulp will match any file ending with .scss or .sass in the root folder.

Since we know about globbing now, we can replace app/scss/styles.scss with a scss/**/*.scss pattern, which matches any file with a .scss extension in app/scss or a child directory.

gulp.task('sass', function() {
  return gulp.src('app/scss/**/*.scss') // Gets all files ending with .scss in app/scss and children dirs
    .pipe(sass())
    .pipe(gulp.dest('app/css'))
})

Any other Sass file that’s found within app/scss would automatically be included into the sass task with this change. If you add a print.scss file into the project, you’ll see that print.css will be generated in app/css.

We’ve now managed to compile all Sass files into CSS files with a single command. The question is, what good does it do if we have to run gulp sass manually every time we want to compile Sass into CSS?

Luckily, we can tell Gulp to automatically run the sass task whenever a file is saved through a process called “watching”.

Watching Sass files for changes

Note! Gulp Watch was one of the things that changed a lot from 3.x to 4.x. See the docs.

Gulp provides us with a watch method that checks to see if a file was saved. The syntax for the watch method is:

// Gulp 3.x watch syntax
gulp.watch('files-to-watch', ['tasks', 'to', 'run']);

// NOTE! Gulp 4.x watch syntax (all the rest of the examples would need to be like this for Gulp 4
gulp.watch('files-to-watch', gulp.series(['tasks', 'to', 'run']));

If we want to watch all Sass files and run the sass task whenever a Sass file is saved, we just have to replace files-to-watch with the app/scss/**/*.scss, and ['tasks', 'to', 'run'] with ['sass']:

// Gulp watch syntax
gulp.watch('app/scss/**/*.scss', ['sass']); 

More often though, we’ll want to watch more than one type of file at once. To do so, we can group together multiple watch processes into a watch task:

gulp.task('watch', function(){
  gulp.watch('app/scss/**/*.scss', ['sass']); 
  // Other watchers
})

If you ran the gulp watch command right now, you’ll see that Gulp starts watching immediately.

And that it automatically runs the sass task whenever you save a .scss file.

Let’s take it a step further and make Gulp reload the browser whenever we save a .scss file with the help of Browser Sync.

Live-reloading with Browser Sync

Browser Sync helps make web development easier by spinning up a web server that helps us do live-reloading easily. It has other features, like synchronizing actions across multiple devices, as well.

We’ll first have to install Browser Sync:

$ npm install browser-sync --save-dev

You may have noticed that there isn’t a gulp- prefix when we install Browser Sync. This is because Browser Sync works with Gulp, so we don’t have to use a plugin.

To use Browser Sync, we’ll have to require Browser Sync.

var browserSync = require('browser-sync').create();

We need to create a browserSync task to enable Gulp to spin up a server using Browser Sync. Since we’re running a server, we need to let Browser Sync know where the root of the server should be. In our case, it’s the `app` folder:

gulp.task('browserSync', function() {
  browserSync.init({
    server: {
      baseDir: 'app'
    },
  })
})

We also have to change our sass task slightly so Browser Sync can inject new CSS styles (update the CSS) into the browser whenever the sass task is ran.

gulp.task('sass', function() {
  return gulp.src('app/scss/**/*.scss') // Gets all files ending with .scss in app/scss
    .pipe(sass())
    .pipe(gulp.dest('app/css'))
    .pipe(browserSync.reload({
      stream: true
    }))
});

We’re done with configuring Browser Sync. Now, we have to run both the watch and browserSync tasks at the same time for live-reloading to occur.

It’ll be cumbersome to open up two command line windows and run gulp browserSync and gulp watch separately, so let’s get Gulp to run them together by telling the watch task that browserSync must be completed before watch is allowed to run.

We can do so by adding a second argument to the watch task. The syntax is:

gulp.task('watch', ['array', 'of', 'tasks', 'to', 'complete','before', 'watch'], function (){
  // ...
})

And in this case we’re adding the browserSync task.

gulp.task('watch', ['browserSync'], function (){
  gulp.watch('app/scss/**/*.scss', ['sass']); 
  // Other watchers
})

We’ll also want to make sure sass runs before watch so the CSS will already be the latest whenever we run a Gulp command.

gulp.task('watch', ['browserSync', 'sass'], function (){
  gulp.watch('app/scss/**/*.scss', ['sass']); 
  // Other watchers
});

Now, if you run gulp watch in the command line, Gulp should start both the sass and browserSync tasks concurrently. When both tasks are completed, watch will run.

At the same time, a browser window that points to app/index.html would also pop up. If you change the styles.scss file, you’ll see that the browser reloads automatically.

There’s one more thing before we end this live-reloading section. Since we’re already watching for .scss files to reload, why not go a step further and reload the browser if any HTML or JavaScript file gets saved?

We can do so by adding two more watch processes, and calling the browserSync.reload function when a file gets saved:

gulp.task('watch', ['browserSync', 'sass'], function (){
  gulp.watch('app/scss/**/*.scss', ['sass']); 
  // Reloads the browser whenever HTML or JS files change
  gulp.watch('app/*.html', browserSync.reload); 
  gulp.watch('app/js/**/*.js', browserSync.reload); 
});

So far in this tutorial we’ve taken care of three things:

  1. Spinning up a web server for development
  2. Using the Sass preprocessor
  3. Reloading the browser whenever a file is saved

Let’s cover the part on optimizing assets in the next section. We’ll start with optimizing CSS and JavaScript files.

Optimizing CSS and JavaScript files

Developers have two tasks to perform when we try to optimize CSS and JavaScript files for production: minification and concatenation.

One problem developers face when automating this process is that it’s difficult to concatenate your scripts in the correct order.

Say we have included 3 script tags in index.html.

<body>
  <!-- other stuff -->
  <script src="js/lib/a-library.js"></script>
  <script src="js/lib/another-library.js"></script>
  <script src="js/main.js"></script>
</body>

These scripts are located in two different directories. It’ll be difficult to concatenate them with traditional plugins like gulp-concatenate.

Thankfully, there’s a useful Gulp plugin, gulp-useref that solves this problem.

Gulp-useref concatenates any number of CSS and JavaScript files into a single file by looking for a comment that starts with “<!–build:” and ends with “<!–endbuild–>”. Its syntax is:

<!-- build:<type> <path> -->
... HTML Markup, list of script / link tags.
<!-- endbuild -->

<type> can either be js, css, or remove. It’s best to set type to the type of file that you’re trying to concatenate. If you set type to remove, Gulp will remove the entire build block without generating a file.

<path> here refers to the target path of the generated file.

We’ll want the final JavaScript file to be generated in the js folder, as main.min.js. Hence, the markup would be:

<!--build:js js/main.min.js -->
<script src="js/lib/a-library.js"></script>
<script src="js/lib/another-library.js"></script>
<script src="js/main.js"></script>
<!-- endbuild -->

Now let’s configure the gulp-useref plugin in the gulpfile. We’ll have to install the plugin and require it in the gulpfile.

$ npm install gulp-useref --save-dev
var useref = require('gulp-useref');

Setting up the useref task is similar to the other tasks we’ve done so far. Here’s the code:

gulp.task('useref', function(){
  return gulp.src('app/*.html')
    .pipe(useref())
    .pipe(gulp.dest('dist'))
});

Now if you run this useref task, Gulp will take run through the 3 script tags and concatenate them into dist/js/main.min.js.

The file however, isn’t minified right now. We’ll have to use the gulp-uglify plugin to help with minifying JavaScript files. We also need a second plugin called gulp-if to ensure that we only attempt to minify JavaScript files.

$ npm install gulp-uglify --save-dev 
// Other requires...
var uglify = require('gulp-uglify');
var gulpIf = require('gulp-if');

gulp.task('useref', function(){
  return gulp.src('app/*.html')
    .pipe(useref())
    // Minifies only if it's a JavaScript file
    .pipe(gulpIf('*.js', uglify()))
    .pipe(gulp.dest('dist'))
});

Gulp should now automatically minify the `main.min.js` file whenever you run the useref task.

One neat thing I’ve yet to reveal with Gulp-useref is that it automatically changes all the scripts within “<!–build:” and “<!–endbuild–>” into one single JavaScript file that points to `js/main.min.js`.

Wonderful, isn’t it?

We can use the same method to concatenate any CSS files (if you decided to add more than one) as well. We’ll follow the same process and add a build comment.

<!--build:css css/styles.min.css-->
<link rel="stylesheet" href="css/styles.css">
<link rel="stylesheet" href="css/another-stylesheet.css">
<!--endbuild-->

We can also minify the concatenated CSS file as well. We need to use a package called gulp-cssnano plugin to help us with minification.

$ npm install gulp-cssnano
var cssnano = require('gulp-cssnano');

gulp.task('useref', function(){
  return gulp.src('app/*.html')
    .pipe(useref())
    .pipe(gulpIf('*.js', uglify()))
    // Minifies only if it's a CSS file
    .pipe(gulpIf('*.css', cssnano()))
    .pipe(gulp.dest('dist'))
});

Now you’d get one optimized CSS file and one optimized JavaScript file whenever you run the useref task.

Let’s move on and optimize images next.

Optimizing Images

You’ve probably guessed it by now; we need to use gulp-imagemin to help us with optimizing images.

$ npm install gulp-imagemin --save-dev
var imagemin = require('gulp-imagemin');

We can minify png, jpg, gif and even svg with the help of gulp-imagemin. Let’s create an images task for this optimization process.

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|gif|svg)')
  .pipe(imagemin())
  .pipe(gulp.dest('dist/images'))
});

Since different file types can be optimized differently, you might want to add options to imagemin to customize how each file is optimized.

For example, you can create interlaced GIFs by setting the interlaced option key to true.

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')
  .pipe(imagemin({
      // Setting interlaced to true
      interlaced: true
    }))
  .pipe(gulp.dest('dist/images'))
});

You can play around with other options if you want to as well.

Optimizing images however, is an extremely slow process that you’d not want to repeat unless necessary. To do so, we can use the gulp-cache plugin.

$ npm install gulp-cache --save-dev
var cache = require('gulp-cache');

gulp.task('images', function(){
  return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)')
  // Caching images that ran through imagemin
  .pipe(cache(imagemin({
      interlaced: true
    })))
  .pipe(gulp.dest('dist/images'))
});

We’re almost done with the optimization process. There’s one more folder that we need to transfer from the `app` directory into `dist`, the fonts directory. Let’s do that now.

Copying Fonts to Dist

Since font files are already optimized, there’s nothing more we need to do. All we have to do is to copy the fonts into dist.

We can copy files with Gulp simply by specifying the gulp.src and gulp.dest without any plugins.

gulp.task('fonts', function() {
  return gulp.src('app/fonts/**/*')
  .pipe(gulp.dest('dist/fonts'))
})

Now Gulp will copy `fonts` from `app` to `dist` whenever you run gulp fonts.

We have 6 different tasks in the gulpfile now, and each of them has to be called individually with the command line, which is kinda cumbersome so we want to tie everything together into one command.

Before we do that though, let’s look at how to clean up generated files automatically.

Cleaning up generated files automatically

Since we’re generating files automatically, we’ll want to make sure that files that are no longer used don’t remain anywhere without us knowing.

This process is called cleaning (or in simpler terms, deleting files).

We’ll have to use del to help us with cleaning.

npm install del --save-dev
var del = require('del');

The del function takes in an array of node globs which tells it what folders to delete.

Setting it up with a Gulp task is almost like the first “hello” example we had.

gulp.task('clean:dist', function() {
  return del.sync('dist');
})

Now Gulp will delete the `dist` folder for you whenever gulp clean:dist is run.

Note: We don’t have to worry about deleting the dist/images folder because gulp-cache has already stored the caches of the images on your local system.

To clear the caches off your local system, you can create a separate task that’s named `cache:clear`

gulp.task(‘cache:clear’, function (callback) {
return cache.clearAll(callback)
})

Phew, that’s a mouthful. Let’s combine all our tasks together now!

Combining Gulp tasks

Let’s summarise what we’ve done. So far, we have created two distinct sets of Gulp tasks.

The first set is for a development process, where we compiled Sass to CSS, watched for changes, and reloaded the browser accordingly.

The second set is for an optimization process, where we ready all files for the production website. We optimized assets like CSS, JavaScript, and images in this process and copied fonts over from app to dist.

We’ve already grouped the first set of tasks together into a simple workflow with the gulp watch command:

gulp.task('watch', ['browserSync', 'sass'], function (){
  // ... watchers
})

The second set consists of tasks that we need to run to create the production website. This includes clean:dist, sass, useref, images and fonts.

If we went by the same train of thought, we could create a build task to combine everything together.

gulp.task('build', [`clean`, `sass`, `useref`, `images`, `fonts`], function (){
  console.log('Building files');
})

Unfortunately, we wouldn’t be able to write the build task this way because Gulp activates all tasks in the second argument simultaneously.

There’s a possibility that useref, images, or even fonts gets completed before clean does, which means the entire `dist` folder gets deleted.

So, to ensure that cleans get completed before the rest of the tasks, we need to use an extra plugin called Run Sequence.

$ npm install run-sequence --save-dev

Here’s the syntax of a task sequence with run sequence:

var runSequence = require('run-sequence');

gulp.task('task-name', function(callback) {
  runSequence('task-one', 'task-two', 'task-three', callback);
});

When task-name is called, Gulp will run task-one first. When task-one finishes, Gulp will automatically start task-two. Finally, when task-two is complete, Gulp will run task-three.

Run Sequence also allows you to run tasks simultaneously if you place them in an array:

gulp.task('task-name', function(callback) {
  runSequence('task-one', ['tasks','two','run','in','parallel'], 'task-three', callback);
});

In this case, Gulp first runs task-one. When task-one is completed, Gulp runs every task in the second argument simultaneously. All tasks in this second argument must be completed before task-three is run.

So we can now create a task that ensures that clean:dist runs first, followed by all the other tasks:

gulp.task('build', function (callback) {
  runSequence('clean:dist', 
    ['sass', 'useref', 'images', 'fonts'],
    callback
  )
})

To make things consistent, we can also build the same sequence with the first group. Let’s use default as the task name this time:

gulp.task('default', function (callback) {
  runSequence(['sass','browserSync', 'watch'],
    callback
  )
})

Why default? Because when you have a task named default, you can run it simply by typing the gulp command, which saves some keystrokes.

Finally, here’s a github repo for all the work we’ve done!

Wrapping it up

We’ve gone through the absolute basics of Gulp and created a workflow that’s able to compile Sass into CSS while watching HTML and JS files for changes at the same time. We can run this task with the gulp command in the command line.

We’ve also built a second task, build, that creates a dist folder for the production website. We compiled Sass into CSS, optimized all our assets, and copied the necessary folders into the dist folder. To run this task, we just have to type gulp build into the command line.

Lastly, we have a clean task that clears away from the generated dist folder any image caches that are created, allowing us to remove any old files that were inadvertently kept in dist.

We’ve created a robust workflow so far that’s capable enough for most web developers. There’s a lot more to Gulp and workflows that we can explore to make this process even better. Here are some ideas for you:

For development:

For optimization:

  • Removing unused CSS with unCSS
  • Further optimizing CSS with CSSO
  • Generating inline CSS for performance with Critical

In addition to development or optimization processes, you can also add write JavaScript unit tests with gulp-jasmine and even deploy your dist folder onto your production server automatically with gulp-rync.

As you can see, even though the workflow we’ve created does quite a few things, there’s a lot more that can be done. Creating a workflow that suits your needs can be extremely exciting and fulfilling, but it can be a lot to take in if you’re new to this.

There’s so much more to Gulp that it’s impossible to cover within this blog post, or even a series of posts. That’s why I wrote a book on automating your workflow, and I invite you to grab ten chapters for free if you’re interested in finding out more :)

Let me know what you felt about this article in the comments below! Oh yes, feel free to contact me if you have any questions on workflow. I’ll be happy to reply!


Gulp for Beginners originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/gulp-for-beginners/feed/ 76 207144
Cross Browser CSS Injection https://css-tricks.com/cross-browser-css-injection/ https://css-tricks.com/cross-browser-css-injection/#comments Mon, 28 Oct 2013 14:31:45 +0000 http://css-tricks.com/?p=154047 The ability to inject newly-modified CSS on every file change (without reloading the page) is the type of workflow-enhancement that you never truly appreciate… until you lose it.

This is exactly what happened to me recently.

For at least the …


Cross Browser CSS Injection originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The ability to inject newly-modified CSS on every file change (without reloading the page) is the type of workflow-enhancement that you never truly appreciate… until you lose it.

This is exactly what happened to me recently.

For at least the last 12 months I had been using Grunt and the LiveReload browser extension to inject CSS when my files changed. It felt like a really nice workflow until I had to work on a project that required IE7 & 8 support. The LiveReload plugin I was using simply didn’t support older versions of IE. For the first time in over a year I had to resort to manual page-refreshes every time I made a change to my CSS. It was painful. It’s also why I built Browser-Sync

Introducing Browser-Sync

Browser-sync is a tool that gives you cross-browser CSS injecting. It will watch over your files and the moment you make a change, it will inform all connected browsers to reload (inject) the new CSS. This all happens without reloading the page. Most importantly, it works in every browser I’ve been able to test it on.

How Browser-Sync came to be

I knew from the outset that simply inserting new CSS into browsers is easy enough to do. The issue I had to solve was how to communicate a file-system change back to the browsers. The Grunt + LiveReload combination I was using previously relied on Web Sockets. This is why there was no support for old IE.

Say hello to Socket.io

I had my lightbulb moment when using Karma for running unit-tests. Karma allows you to run tests in multiple browsers. While testing in IE8 one day, I realized that Karma was automatically re-running the tests on each file save.

Bingo. I had found something that was able to watch the file system for changes and inform browsers all about it. I started to dig into the Karma source code. Eventually I discovered they were using Socket.io to achieve this.

Starting to come together

Everything was in place. With the pain endured from manual page refreshing as my driving force and the discovery of Socket.io as my inspiration, I was well set-up to build a tool that I would use myself on a daily basis.

Getting set up

This guide assumes you already have Grunt installed inside a project and know how to use it. If you don’t, then you can learn about it on the Grunt site.

Browser-sync can be installed as a stand-alone command-line tool, or as a Grunt plugin. Because of the current popularity of Grunt I’ll focus here on how to set it up as as Grunt Task. If you would prefer the command-line only approach, please checkout these instructions.

From the same file directory as your Gruntfile.js:

npm install grunt-browser-sync

This will install Browser-sync locally into your project. Now you can make sure it’s loaded by Grunt by placing this near the end of your Gruntfile.js:

grunt.loadNpmTasks('grunt-browser-sync');

Finally, like all Grunt plugins, you’ll need to provide some configuration. At a minimum, you’ll need the following:

// Inside the Gruntfile.js config object
browser_sync: {
    files: {
        src : 'assets/css/style.css'
    }
}
Reader Jan Skovgaard writes in:

I got a bit confused when I tried to follow along the steps in the article. It simply did not work – So I went to the official website and read. Seems the steps have changed a bit and instead of naming the task “browser_sync” it should say “browserSync” otherwise grunt won’t run the task.

With your config set up, you can run the plugin with this command:

grunt browser_sync

Now you should receive an HTML snippet that you can paste into the footer of your website. Place that there. Now whenever you change that CSS file (or it’s changed by another build process), it will be automatically injected into all browsers.

Note: there are ways to specify multiple files and you can use wildcards (*) too. Please see the Readme on Github for more information.

A more automated approach

The example above is great for those situations where you already have a server. Building a site with WordPress or Rails, for example. But the downside is that you have that manual step of copying & pasting a snippet into a file. If you’re working with static files (HTML, CSS, & JS) then you can use the built-in server instead. The built-in server will automatically insert any HTML snippets needed so you don’t have to.

To use the built-in server, just set your config like this.

// Inside the Gruntfile.js config object
browser_sync: {
    files: {
        src : 'app/css/style.css'
    }, 
    options: {
      server: {
        baseDir: "app"
    }
  }
}

Files will now be served from the app directory and all the magic needed to inject CSS will be done for you.

Going even further

If you use the server option above, did you notice the IP address and port that is used? Normally something like 192.168.0.8:3001? Browser-sync tries to figure out a good external IP address to use for the server. That means you should be able to connect to it from any device/computer on the same WiFi network. The cool thing here is that the CSS injecting will work across all mobile devices and tablets too. When you see this type of automation in action, you’re going to find it hard to live without it.

If it doesn’t work for you

In my tests, I’ve found that on typical WiFi networks, Browser-sync does a fantastic job of getting the correct IP address. However, in a large office setup, you may find that it chooses an IP that is not accessible to other devices/computers. If this is the case, and you know what the correct one is, just provide it as an option like this:

// Inside the Gruntfile.js config object
browser_sync: {
    files: {
        src : 'app/css/style.css'
    }, 
    options: {
      server: {
        host: "192.168.1.1",
        baseDir: "app"
    }
  }
}

Beyond CSS injecting

Being a guest post on CSS-Tricks, I’ve focused mostly on setting up the CSS-injecting part of my tool. But Browser-sync does a lot more than that! It has something awesome called Ghost-mode.

Ghost mode will keep track of all connected browsers and keep the following in sync:

  1. Scroll Position – extremely helpful when developing with multi-monitor
  2. Form Fields – fill out a form in one browser and all others will be populated with that data.
  3. Links – Reviewing a few pages of a newly built site? Have it open on all your devices and when you navigate from page to page, all the browsers with follow you around!

Conclusion

I hope this all sounds pretty cool to you. I loved building Browser-sync. I welcome feedback and issue reporting so that we can improve it as a community.

Remember Browser-sync can be used two ways:


Cross Browser CSS Injection originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/cross-browser-css-injection/feed/ 39 154047
#010 – CodeKit For Great Success https://css-tricks.com/lodge/artists-website/010-codekit-for-great-success/ https://css-tricks.com/lodge/artists-website/010-codekit-for-great-success/#comments Wed, 30 Jan 2013 23:42:17 +0000 http://css-tricks.com/?page_id=20051 In this screencast we have CodeKit start watching our project. This makes lots of developer tasks much easier.

The first thing we do is us it to losslessly optimize an image. Easy one click.

Then we install Compass in the …


#010 – CodeKit For Great Success originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this screencast we have CodeKit start watching our project. This makes lots of developer tasks much easier.

The first thing we do is us it to losslessly optimize an image. Easy one click.

Then we install Compass in the project. This gives us the ability to use CSS3 mixins provided by Compass, instead of having to create our own, which we should surely do a worse job.

Perhaps most importantly, Compass (through CodeKit) now watches our project folder and automatically compiles our .scss files into .css that we actually use. As an added bonus, when save our .scss files in our code editor, those new styles are “injected” into the page automatically, which is awesome.


#010 – CodeKit For Great Success originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/lodge/artists-website/010-codekit-for-great-success/feed/ 8 20051
Style Injection is for Winners https://css-tricks.com/style-injection-is-for-winners/ https://css-tricks.com/style-injection-is-for-winners/#comments Fri, 04 Jan 2013 17:53:02 +0000 http://css-tricks.com/?p=19733 By “style injection”, I mean being able to see styling changes immediately after authoring them without having to manually refresh your browser window. This isn’t a brand new concept, I just mention it now because it’s so awesome that if …


Style Injection is for Winners originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
By “style injection”, I mean being able to see styling changes immediately after authoring them without having to manually refresh your browser window. This isn’t a brand new concept, I just mention it now because it’s so awesome that if it’s not a part of your workflow you should consider updating yours to include it.

The Past

For a long time, Dreamweaver had the ability to show you a live preview of what you were building. CSS Edit also had a thing like that. Now that is built into Espresso and at a quick glance I saw it still does previews but not split pane editable previews.

But they used some built-in WebKit thing to do it, running who knows exactly what version. I like doing my testing in browsers that people use. And besides, those aren’t going to work great when you’re preprocessing CSS.

No offense if you use and these editors or working this way, it’s just not for me.

New Style

The first to come along that I knew of was LiveReload. Through browser extensions, as you save files, the changes are injected automatically.

The name “LiveReload” implies that it reloads the page for you, which is true when you change HTML or JavaScript. Even that is handy, as it saves switching applications and manually refreshing the page. But when you change CSS (whether it is preprocessed or not) the styles are “injected” meaning they take effect on the page without a refresh.

I’m a fan of CodeKit which has now also been doing this for a good while. CodeKit only works with Safari and Chrome this way, but does so automatically without browser extensions.

If you’re willing to put a script tag on your page, LiveReload works in Chrome, Safari, Firefox, Mobile Safari, and Opera (with finagling). Without the script tag you can get it working in Safari, Chrome, and Firefox.

Mixture is going to have live updating as well, but I haven’t looked into how they are doing it just yet. Yeoman has refreshing but not injecting. It’s open source so maybe someone could add it =).

Why is Style Injection cool?

Because the page doesn’t refresh, you can style the page without affecting its state. Say you have a dialog box that pops up with a click and you want to style that dialog box. While using an app that does style injection, you can leave that dialog box open in the browser and author CSS that changes it and watch those changes happen immediately without refreshing the browser and losing that state. Not all states have a URL change associated with them. A dialog box is a common example of that.

Here’s an example of that:

This gets more useful the more complex the state is. Imagine you’re trying to style a rollover of a custom dropdown that appears in a panel that is by default closed. That’s a lot of steps to reproduce that state for each minor styling change.

Screen Setup

I love using Divvy to super quickly snap my code editor to the right and the browser to the left and get started working right away. I have Divvy set up to only have left and right boxes, no complex grid.

For the Record

CodePen does as-you-type live updating as well as has a Live View mode. Pretty darn cool and useful I think, but CodePen isn’t yet really for your actual web development workflow.


Style Injection is for Winners originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/style-injection-is-for-winners/feed/ 61 19733
Inject New CSS Rules https://css-tricks.com/snippets/javascript/inject-new-css-rules/ https://css-tricks.com/snippets/javascript/inject-new-css-rules/#comments Tue, 01 Jan 2013 14:35:29 +0000 http://css-tricks.com/?page_id=19644 If you need to change the style of an element with JavaScript, it’s typically better to change a class name and have the CSS already on the page take effect and change the style. However, there are exceptions to every …


Inject New CSS Rules originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
If you need to change the style of an element with JavaScript, it’s typically better to change a class name and have the CSS already on the page take effect and change the style. However, there are exceptions to every rule. For instance, you might want to programmatically change the pseudo-class (e.g. :hover). You can’t do that through JavaScript for the same reason inline style="" attributes can’t change pseudo classes.

You’ll need to inject a new <style> element onto the page with the correct styles in it. Best to inject it at the bottom of the page so it overrides your CSS above it. Easy with jQuery:

function injectStyles(rule) {
  var div = $("<div />", {
    html: '&shy;<style>' + rule + '</style>'
  }).appendTo("body");    
}

Usage

injectStyles('a:hover { color: red; }');

Demo

More Information


Inject New CSS Rules originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/snippets/javascript/inject-new-css-rules/feed/ 14 19644