Skip to content

Releases: BrowserSync/browser-sync

v2.17.0

30 Sep 17:13
Compare
Choose a tag to compare
  • FIXED https option is no longer clobbered when running from the CLI 27a08c2

  • ADDED - better support for per-route static file serving 97dd907
    For example, let's say you have a deployed Wordpress website at http://example.com where the assets live inside wp-content/themes/awesome/. Now lets imagine you need to make small CSS tweaks in style.css, but you don't want the hassle of running PHP + MySQL on your local machine... With Browsersync you can now easily map remote paths to local ones. So if you have the file wp-content/themes/awesome/style.css on your machine, you could run the following and have your changes update the live website.

    /**
    * This example will proxy an EXISTING website
    * whilst serving assets from your local directory.
    * This is crazy-powerful, especially when you consider
    * it works across all devices.
    */
    const bs = require('browser-sync').create();
    
    bs.init({
        proxy: 'http://example.com',
        files: ['htdocs/wp-content/themes/awesome'], // watch files
        serveStatic: [
            {
                route: '/wp-content/themes/awesome',     // remote path
                dir: 'htdocs/wp-content/themes/awesome'  // local path
            }
        ]
    });

    This kind of magic was always possible with Browsersync, but it required more complicated setup that we're happy to see the back of. The best bit is that the proxy will kick in if a file is not found locally. So in our Wordpress example, you could have nothing but a CSS file and everything would still work.

    A knock-on effect of this feature is that now you can map multiple remote paths to multiple local directories... I know, it's magical and amazing.

    // map 2 remote paths to 1 local directory
    serveStatic: [
        {
            route: ['/wp-content/themes/theme1', '/wp-content/themes/theme2'],
            dir: './my-local'  // local path
        }
    ]
    // map 1 remote path to 2 local directories
    serveStatic: [
        {
            route: '/wp-content/themes/theme1',
            dir: ['./my-local', './tmp']  // local path
        }
    ]

  • ADDED support for opening browsers with flags** #1179

    For example, if you wanted to open Chrome with certain flags when Browsersync starts, you can do

    const bs = require('browser-sync').create();
    
    bs.init({
    server: './app',
    browser: [
        {
            app: [
                'chromium-browser',
                '--app=http://localhost:8080',
                '--proxy-server=localhost:8080',
                '--user-data-dir=.tmp/chomium'
            ]
        }
    ]
    });

    This can also be combined with the string-only versions too - so to open chrome with flags, but safari + firefox as normal:

    const bs = require('browser-sync').create();
    
    bs.init({
    server: './app',
    browser: [
        {
            app: [
                'chromium-browser',
                '--app=http://localhost:8080',
                '--proxy-server=localhost:8080',
                '--user-data-dir=.tmp/chomium'
            ]
        },
        'safari',
        'firefox'
    ]
    });

v2.16.0

14 Sep 20:27
Compare
Choose a tag to compare

2 fixes & a really useful new option.



  • FIXED - the version number of the Browsersync client script is now added as a query param instead of within the file path. This is a massive help for users that have the snippet saved in a file.

    Fun fact: other than a sanity check to show which release of Browsersync you're using, the version number actually serves no purpose, and that's why:

  1. it should've never been part of the the path in the first place as it caused problems for people upgrading
  2. you've always been able to access the JS file without the version number at the end, but this wasn't the default... so no one did it... so I've fixed it now instead 👍

  • ADDED - new option cors: true - setting this will ensure that all assets served by Browsersync (including the script file itself) in all modes will have HTTP access control headers added.

    This allows any domain to access your files, which can lead to some creative workflows - for example, you could create a chrome extension that added some files you have locally into a live site & have Browsersync auto-update them when they change.


enjoy :)

2.15.0

05 Sep 19:37
Compare
Choose a tag to compare

Updates from 2.14 -> 2.15

  • Added: proxy.proxyReqWs to allow users to intercept/alter proxied web sockets (this is an api mirror to the underlying http-proxy lib) 277c17c
  • Fixed: protocol-relative URL rewriting now works as expected, which solves issues faced by WooCommerce users 42059df - so that now this...
<a href="//some-protocol-relative.com/some-path">My Link</a>

is correctly re-written to something like...

<a href="//localhost:3000/some-path">My Link</a>
  • Fixed: attempting to use --https with a non-https target no longer fails, and allows some pretty nice workflows 80c091d

eg:

$ browser-sync start --proxy 'localhost:8000' --https

Electron support

31 Jul 20:26
Compare
Choose a tag to compare

This release includes the addition of a few new options.

  • script.domain for situations where you want full control over the domain used to serve the client JS
  • localOnly for situations where you need to opt-out of Browsersync's dynamic host rewriting.

See the previous discussion for details, but here's the tl;dr:

Browsersync goes out of it's way to 'just work' in most use-cases - but this requires some dynamic aspects that are OTT for something as simple as an Electron workflow, where you probably just want to reload files when they change.

Electron users

To have Browsersync watch over your files and reload your app when they change, just use the localOnly flag & then copy/paste the snippet into your footer.

cli

browser-sync start --localOnly --files './app'

api

const bs = require('browser-sync').create();
bs.init({
  localOnly: true,
  files: './app'
});

Adding localOnly will remove any attempts to set the domain automagically in script tags or WebSocket addresses and instead will hard-code the correct localhost address. This is exactly what is needed for use in electron.

2.12.1

11 Apr 18:30
Compare
Choose a tag to compare

As work continues on Browsersync V3, I've decided to take some time to back-port some improvements that have been discovered during the re-write. Many new features are not compatible with the architecture of this 2.x master branch, but those that are have made it into this 2.12 release.

Proxy

  • Add proxyReq & proxyRes to better align with http-proxy API - this allows you to modify the request before and after it hits the target.
  • Remove foxy module, bring proxy code into core. There was too much duplication & glue-code caused by having the proxy module separate and given they are intrinsically linked, it made sense to keep all of the logic together.

Middleware

  • Allow middleware to be registered per-route. Previously, if you wanted to only apply a middleware based on a route, you had to check the url manually, now you can mix & match 'global' middleware that affect every request with more targeted ones that only act when a particular
    route is hit. (see below for examples)

CLI

  • Switch from meow to yargs - for more features re: processing CLI input
  • Allow dot notation - to enable nested properties (eg: --proxy.ws)
  • Allow multiple items per option (eg: --files "*.html" "*.css")
  • Allow per-command help (eg: browser-sync start --help, browser-sync recipe --help etc)
  • Add short-hand alias for common options (eg: -s for server, -p for proxy etc)
  • Accept config from browser-sync key in package.json #1040
  • Allow flags to override all other forms of config

Plugins

  • Allow options in query strings - a big help when using the cli + plugins
    • (eg: browser-sync start -s --plugins bs-html-injector?files[]=*.html)

Snippet

  • Append snippet to end of document - by far the most commonly reported bug is a result of the deliberately simple regex used to insert the script tag directly after the first <body> tag. During testing for V3 I discovered that every single browser that we support is more than happy to accept a JS file that is loaded as the final thing on the page (even after the body/html tags) - this discovery alone should solve the countless hours that have been consumed reporting & replying to issues related to this.

Bug fixes

  • Always show 'codeSync' option - in sync-option in UI - #931 #802
  • Don't clobber existing url params on injected files - part of #687

Examples

Below are a few examples showing what is now possible in 2.12.0

Proxy - proxyReq & proxyRes

proxy: {
    target: "http://www.bbc.co.uk",
    /**
     * Functions given here will be called with the proxy 
     * request object *before* it hits your application
     */
    proxyReq: [
        function (proxyReq) {
            proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
        }
    ],
    /**
     * Functions given here will be called with the response 
     * object *before* it hits the browser
     */
    proxyRes: [
        /**
         * Here you have access to the raw response from your
         * application *before* it hits the browser
         */
        function (res) {
            res.headers['some-other-header'] = 'value';
        }
    ]
}

Middleware - applied on a per-route basis

Before - you needed to check the url manually

middleware: [function (req, res, next) {
    if (req.url.match(/^\/api/)) {
        // some middleware logic
    } else {
        next();
    }
}]

After - define the route up front

middleware: [
    {
        route: "/api",
        handle: function (req, res, next) {
            // some middleware logic
        }
    }
]

Mix and match - some middleware are global, some per-route. No problem. Here's an example where 2 global middleware apply to every route, and one applies to /api only

middleware: [
    require("compression")(), // global gzip middleware
    function (req, res, next) {
       // some other generic middleware
       next();
    },
    {
        route: "/api", // per-route
        handle: function (req, res, next) {
            // some middleware logic
            // like handing the request off to a proxy etc
        }
    }
]

CLI improvements

new short hand examples

  • -p = --proxy
  • -s = --server
  • -f = --files
  • -b = --browser
  • -c = --config
  • --ss = --serveStatic
# Start a server from the `app` directory, watching all files
$ browser-sync start -s 'app' -f 'app'

# Proxy a PHP app + serve static files & watch them
$ browser-sync start -p 'mylocal.dev' --ss 'public' -f 'public'

# Start Browsersync from a config file
$ browser-sync start -c conf/browser-sync.js

# Start Browsersync from a config file with overriding flags
$ browser-sync start -c conf/browser-sync.js --port 4000

inline plugin options

# 1. Start a server from the `app` directory
# 2. Register the bs-html-injector plugin with files: ['*.html'] option
browser-sync start -s 'app' --plugins bs-html-injector?files[]=*.html 

Have fun!

This is meant to be a non-breaking-change release, so please inform me if you encounter any issues. :)

v2.10.1 bug-fix release

15 Dec 13:46
Compare
Choose a tag to compare

This is an important bug-fix release related to gulp-style workflows. The stream() method accepts a 'match' option to exclude things such as .map files - this was broken for directories beginning with a . (dot) - this is now fixed in this release, so the following will work as you expect

gulp.task('styles', function () {
  return gulp.src('.tmp/scss/**')
    .pipe(sourcemaps.init())
    .pipe(sass().on('error', x => console.log(x)))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('.tmp/css'))
    .pipe(browserSync.stream({match: '**/*.css'}));
});

v2.9.1

03 Sep 15:26
Compare
Choose a tag to compare

Updates since 2.8.1 (the last release notes).

  • Https - The self-signed ssl certs that Browsersync ships with for local development have been updated (twice...... don't ask) - they had previously expired after the first year, so this time I set it to 10 years to be safe :p 45104a7 a2f4767
  • File Watching - @Plou sent a fix that stops ../../css style paths from being ignored. For those of you that don't have tooling configs in the project root - this is your lucky day. 33d49d2
  • New Feature - Scroll syncing across elements - two new, opt-in options now enabled scroll sync in situations where it aint the window doing the scrolling. See google/web-starter-kit#750 for a back-story and the docs for examples.

Update asap & enjoy

2.8.1

29 Jul 07:56
Compare
Choose a tag to compare

bug-fix release.

For the longest time, trying to use Browsersync to proxy your existing server setup or live website has worked extremely well - unless your app also uses web-sockets (Browsersync uses web sockets internally to communicate with browsers).

Now though, I'm pleased to announce this problem is resolved - all you need to do is provide the following configuration if using the api/grunt/gulp etc

bs.init({
    proxy: {
        target: "https://yourawesomeapp.dev",
        ws: true
    }
});

or on the command line:

browser-sync start --proxy "https://yourawesomeapp.dev" --ws

Now your web-socket enabled apps can also run perfectly well through Browsersync. Enjoy :)

2.8.0

19 Jul 20:41
Compare
Choose a tag to compare

This is a minor release with 2 additional options.

  • Added proxy.proxyRes option to allow modifications to the response after the server has sent it. This is useful in situations where, for example, you'd want to overwrite headers before they hit the browser - like in this example - thanks to @lookfirst.
  • Added serveStatic option. We already include the serve-static library and some recent use-cases have shown a valid use-case for both the proxy + a static file server (think loading local assets into a live/staging website - way cool). So now you can do something like the following;
var bs = require('./').create();

bs.init({
    proxy: 'http://www.bbc.co.uk',
    files: ["**/*.css"],
    serveStatic: ["./css"],
    rewriteRules: [
        {
            match: "http://www.bbc.co.uk/some/css/styles.css",
            replace: "/css/styles.css"
        }
    ]
});

The file paths in that example are fictional, but serve to highlight how you could, with a combination of Browsersync options, proxy a live website, replace a link to point to a locally served css file, watch that file for changes & inject it whenever it does.

2.6.0

12 Apr 22:31
Compare
Choose a tag to compare

Features

This is a feature-packed release! We've crammed into this 2.6.0 release the usual
bug fixes & tweaks along with some entirely new APIs & workflow possibilities. It's a good one!

http-protocol

We've seen interest in allowing communication to the BrowserSync server from
separate processes to enable things like reloading browsers following a build script
(using npm as opposed to grunt, gulp etc). To enable this we've introduced a new
http protocol. Basically you'll be able to start BrowserSync
in one terminal window and then communicate to the process from another.

# run a server from any folder
browser-sync start --server

# from another window, tell all browsers to reload their css files
browser-sync reload --files "*.css"

This is really cool (and a bit magic) - but it gets even more interesting when
you consider that anything can hit the correct HTTP endpoint of a browser-sync server
and have the page reload. Think about how cool it would be having a Wordpress plugin that listens to
some post saved event and then reloads all browsers/devices? No problemo...

/* PHP pseudo codez */
add_action( 'save_post', function() {
    http_get("http://localhost:3000/__browser_sync__?method=reload");
});

Docs coming soon...

  • http-protocol:
    • Add support for https comms (efd4f39c)
    • Add reload method to http protocol (f6a3601f)
  • commands: Add reload command for http-protocol comms (c0fe70dc)

More flexible .reload()

Normally, should you want to reload core.css & styles.css in the same page, you would do...

browserSync.reload(['core.css', 'styles.css']);

... which is fine - but sometimes you either don't know the exact filename referenced
in the DOM, or you would prefer not to hard-code the paths in your build scripts; either
way, you can now simply provide a wild-card and ALL assets with the same extension will be
reloaded.

/** refresh every CSS on page **/
browserSync.reload('*.css');
  • client: Bump client to allow wildcards in reload method - (1e4de8f7, closes #572)

We've also added a global debounce option for reloading, as well as making reloadDelay && reloadDebounce available from the cli

  • reload: Add reload-delay and reload-debounce to cli -, (38d62c96, closes #329, #562)

File Watching

We've now switched to chokidar for file watching (previously Gaze). This directly
addresses, amongst other things, one of the most commonly reported issues related
to watching file and directories - the ability (or previously the lack of) to watch
and report on new & incoming files.

We've also taken this opportunity to add a couple of extra ways to work with files in BrowserSync

User-defined watchers and callbacks

Usually, BrowserSync will just do the correct thing, if you give it this...

browserSync({
    server: "app",
    files: ["app/css/*.css", "app/*.html"]
})

... and then change a css file, it will inject it into all browsers - or perform a
full reload when you change a html file. That's great, but now that we've added
the ability to provide custom callbacks, it opens up a whole new range of things we can do.

Here's one example, where we provide the glob app/*.html (which BrowserSync will handle as normal)
& also an object with match & fn properties. Any object such as this will be ignore
by BrowserSync internally and by all plugins, so for simple projects it's entirely possible that you
could ditch your build tools and create a workflow entirely around BrowserSync

var bs = require("browser-sync").create();

bs.init({
    server: "./app",
    files: [
        "app/*.html",
        {
            match: "app/scss/*.scss",
            fn: function (event, file) {
                if (event === "change") {
                    processSass(file); // pseudo code, you get the point 
                    bs.reload("*.css");
                }
            }
        }
    ]
});

To top this off, we've added a public .watch() method. Please note however, whilst this is
literally just pointing to internal watch method, it has no features relating to BrowserSync.
Use it as a stand-alone watcher and even interact with your BrowserSync Server if you like.

var bs     = require("browser-sync").create();
var inject = bs.reload.bind(null, "*.css");

bs.watch("app/*.html").on("change", bs.reload); // hard reload
bs.watch("app/css/*.css").on("change", inject); // inject

bs.init({server: "./app"});
  • file-watcher: Add .watch() to public api (6a2609f0)
  • watchers:
    • Allow per-watcher options hash. (3c069fba)
    • switch to chokidar for file-watching, implement callback interface on per-patter (14afddfc)

.stream()

Previously, when you could pipe a stream into .reload({stream: true}) - the filenames are
recorded and each connected browser will be informed that those files changed. This was obviously
a tacked-on feature and I have no idea why I didn't just create a separate method in the first
place - but anyway here it is:

var bs = require("browser-sync").create();

gulp.task('sass', function () {
    return gulp.src('scss/**/*.scss')
        .pipe(sass({sourcemap: true}))
        .pipe(gulp.dest('css'))
        .pipe(bs.stream());

Or, if you need to filter out source maps so that browsers are only informed about
the files you want reloading (the css files), you can now provide a glob pattern:

var bs = require("browser-sync").create();

gulp.task('sass', function () {
    return gulp.src('scss/**/*.scss')
        .pipe(sass({sourcemap: true}))
        .pipe(gulp.dest('css'))
        .pipe(bs.stream({match: "**/*.css"}));
  • stream: Implement dedicated .stream() method for better handling streams & to pave the (2581e7a1)

CLI

You can now give the browser option on the command line.

browser-sync start --server app/dist --browser firefox --browser safari
  • cli: allow 'browser' option from cli - (ca517d03, closes #552)

You can now open the UI directly when in snippet mode

browser-sync start --open "ui"
  • open: Allow open: 'ui' and open: 'ui-external' when in snippet mode - (d0333582, closes #571)

Plugins

We'll be announcing some amazing plugins soon, so watch out for that, but this change was to make it easier to register plugins so you can do things like this:

var bs       = require("browser-sync").create();

bs.init({
    server: "./app",
    plugins: [
        {
            module: "bs-html-injector",
            options: {
                files: "./app/*.html"
            }
        }
    ]
});

Allowing plugins to be registered directly inline like this is a very important feature - it enables
the use of plugins in places you otherwise couldn't (for example, in the gruntfile.js configuration).

It's more verbose however, so if you do have access to the api, the same thing can be done with:

var bs = require("browser-sync");
bs.use(require("bs-html-injector"), {files: "./app/*.html"});
bs.init({server: "./app});
  • plugins: Accept object literal as plugin + options (757f492e)

Bug Fixes

  • server: set index correctly if serveStaticOptions: {index: } given (34816a76)