Every time I open the BrowserSync docs I find something awesome.

Versions used below

{
  "browser-sync": "2.7.1",
  "gulp": "3.8.11",
  "gulp-sass": "2.0.0"
}

BrowserSync

BrowserSync is a great module that I use for a static web server with auto-reload. It does a lot more than auto-reload but that’s my main use for it.

When paired with Gulp, BrowserSync can inject css into a page – no page reload needed.

Basic Setup

Given this project structure

.
├── app/
│   ├── index.html
│   └── css/
│       └── app.css
├── gulpfile.js
└── package.json

Here is a simple gulp build that uses BrowserSync to serve static files and reload browsers when css or html changes.

var gulp = require('gulp');
// create new instance of BrowserSync
var browserSync = require('browser-sync').create();

gulp.task('watch', function(gulpCallback) {
  browserSync.init({
    // serve out of app/
    server: './app/',
    // launch default browser as soon as server is up
    open: true
  }, function callback() {
    // (server is now up)

    // set up watch to reload browsers when source changes
    gulp.watch(['app/index.html', 'app/css/*'], browserSync.reload);

    // notify gulp that this task is done
    gulpCallback();
  });
});

This is nice but the browser reloads the entire page when the css changes.

BrowserSync can do better.

Injecting Styles into the Page

With a small change to the watches it will push css updates without a page reload.

var gulp = require('gulp');
// create new instance of BrowserSync
var browserSync = require('browser-sync').create();

gulp.task('watch', function(gulpCallback) {
  browserSync.init({
    // serve out of app/
    server: './app/',
    // launch default browser as soon as server is up
    open: true
  }, function callback() {
    // (server is now up)

    // watch html and reload browsers when it changes
    gulp.watch('app/index.html', browserSync.reload);

    // watch css and stream to BrowserSync when it changes
    gulp.watch('app/css/*', function() {
      // grab css files and send them into browserSync.stream
      // this injects the css into the page
      gulp.src('app/css/*')
        .pipe(browserSync.stream());
    });

    // notify gulp that this task is done
    gulpCallback();
  });
});

This is a very simple example but you can move the call to browserSync.stream() elsewhere in more complex builds. As long as css files are going in, it should work.

Using a CSS Preprocessor

We’ll use Sass to generate css. Now the project looks like

.
├── app/
│   ├── css/
│   │   └── app.css  (index.html references this)
│   ├── index.html
│   └── scss/
│       └── app.scss (edit this to change styles)
├── gulpfile.js
└── package.json

Bringing in a CSS preprocessor requires another small change to the build.

var gulp = require('gulp');
var sass = require('gulp-sass');
// create new instance of BrowserSync
var browserSync = require('browser-sync').create();

gulp.task('watch', ['build-styles'], function(gulpCallback) {
  browserSync.init({
    // serve out of app/
    server: './app/',
    // launch default browser as soon as server is up
    open: true
  }, function callback() {
    // (server is now up)

    // watch html and reload browsers when it changes
    gulp.watch('app/index.html', browserSync.reload);

    // when sass files change run specified gulp task
    gulp.watch('app/scss/*', ['build-styles']);

    // notify gulp that this task is done
    gulpCallback();
  });
});

// run sass then stream resulting css to output dir and to BrowserSync
gulp.task('build-styles', function() {
  return gulp.src('app/scss/*')
    .pipe(sass())
    .pipe(gulp.dest('app/css'))
    // if BrowserSync's static server isn't running this stream is a no-op passthrough
    .pipe(browserSync.stream());
});

You could do something similar for Less and Stylus.

Injecting css like this is nice because it’s faster and parts of the UI that depend on JavaScript aren’t reset.