Releases: BrowserSync/browser-sync
v2.17.0
- 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 athttp://example.com
where the assets live insidewp-content/themes/awesome/
. Now lets imagine you need to make small CSS tweaks instyle.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 filewp-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
2 fixes & a really useful new option.
- FIXED - current connections will show once again in the UI - BrowserSync/UI@00af3da
-
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:
- it should've never been part of the the path in the first place as it caused problems for people upgrading
- 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
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 anon-https
target no longer fails, and allows some pretty nice workflows 80c091d
eg:
$ browser-sync start --proxy 'localhost:8000' --https
Electron support
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 JSlocalOnly
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
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
toyargs
- 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
)
- (eg:
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
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
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
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
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 theserve-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
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:
- 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');
We've also added a global debounce option for reloading, as well as making reloadDelay
&& reloadDebounce
available from the cli
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:
.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
You can now open the UI directly when in snippet mode
browser-sync start --open "ui"
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)