Skip to content

Commit

Permalink
Add BrowserSync
Browse files Browse the repository at this point in the history
  • Loading branch information
sedubois committed Sep 23, 2016
1 parent 0f88f55 commit d07da62
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 48 deletions.
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

### Development

Run `npm start` to see your app at `localhost:3000`
Run `npm start` to see your app at `localhost:3000` and on your local network via BrowserSync, with hot reloading.

### Building & Deploying

Expand Down Expand Up @@ -119,7 +119,7 @@ get a performance check right in your terminal!

#### Browser testing

`npm run start:tunnel` makes your locally-running app globally available on the web
`npm run start:tunnel` makes your app available as with `npm start`, as well as on the web
via a temporary URL: great for testing on different devices, client demos, etc!

#### Unit testing
Expand Down
16 changes: 10 additions & 6 deletions docs/general/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ history irreversibly by accident.
npm run start
```

Starts the development server running on `http://localhost:3000`
Starts the development server and makes your application accessible with
[BrowserSync](https://www.browsersync.io/) at `localhost:3001` and on a local IP address (check your startup logs).

This means that your changes will keep in sync on all your local devices,
even when you update the code or you scroll the page on one of them!

Make sure to check the BrowserSync dashboard at `localhost:3002`.

## Cleaning

Expand Down Expand Up @@ -53,9 +59,7 @@ generate container`)
npm start
```

Starts the development server and makes your application accessible at
`localhost:3000`. Tunnels that server with `ngrok`, which means the website
accessible anywhere! Changes in the application code will be hot-reloaded.
Starts the development server and makes your hot-reloadable application accessible everywhere with BrowserSync.

### Production

Expand Down Expand Up @@ -141,8 +145,8 @@ Watches changes to your application and reruns tests whenever a file changes.
```Shell
npm run start:tunnel
```
Starts the development server and tunnels it with `ngrok`, making the website
available on the entire world. Useful for testing on different devices in different locations!
Starts the development server as usual for development, with an extra tunnels to make the website
available to the entire world. Useful for testing on different devices in different locations!

### Performance testing

Expand Down
9 changes: 4 additions & 5 deletions docs/testing/remote-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
npm run start:tunnel
```

This command will start a server and tunnel it with `ngrok`. You'll get a URL
that looks a bit like this: `http://abcdef.ngrok.com`
Starts the development server similarly to `npm start`, with an extra address XXX.localtunnel.me where XXX is
your app name configured in `package.json`.

This URL will show the version of your application that's in the `build` folder,
and it's accessible from the entire world! This is great for testing on different
devices and from different locations!
This means your app is accessible from the entire world!
This is great for testing on different devices and from different locations.
1 change: 0 additions & 1 deletion internals/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const ReactBoilerplate = {
'compression',
'cross-env',
'express',
'ip',
'minimist',
'sanitize.css',
],
Expand Down
30 changes: 30 additions & 0 deletions internals/scripts/browserSync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const browserSync = require('browser-sync');
const path = require('path');
const pkg = require(path.resolve(process.cwd(), 'package.json'));

const logger = require('../../server/logger');

module.exports = function startBrowserSync(port, middleware, cb) {
const bsConfig = {
proxy: {
target: `localhost:${port}`,
middleware,
},

// no need to watch '*.js' here, webpack will take care of it for us,
// including full page reloads if HMR won't work
files: ['build/content/**/*.*'],
};
if (process.env.ENABLE_TUNNEL) {
bsConfig.tunnel = pkg.name.replace(/\W/g,'');
}
const bs = browserSync.create();

bs.init(bsConfig, (err, bs) => {
if (err) return cb(err);
logger.browserSyncStarted();

// return the BrowserSync URLs, in case someone cares
cb(null, bs.getOption("urls"));
});
};
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@
"compression",
"cross-env",
"express",
"ip",
"minimist",
"sanitize.css"
],
Expand All @@ -198,6 +197,7 @@
},
"dependencies": {
"babel-polyfill": "6.13.0",
"browser-sync": "^2.16.0",
"chalk": "1.1.3",
"cross-env": "2.0.1",
"compression": "1.6.2",
Expand All @@ -206,7 +206,6 @@
"immutable": "3.8.1",
"intl": "1.2.4",
"invariant": "2.2.1",
"ip": "1.1.3",
"lodash": "4.15.0",
"minimist": "1.2.0",
"react": "15.3.1",
Expand Down
16 changes: 7 additions & 9 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@

const express = require('express');
const logger = require('./logger');
const browserSync = require('../internals/scripts/browserSync');

const argv = require('minimist')(process.argv.slice(2));
const setup = require('./middlewares/frontendMiddleware');
const isDev = process.env.NODE_ENV !== 'production';
const ngrok = (isDev && process.env.ENABLE_TUNNEL) || argv.tunnel ? require('ngrok') : false;
const resolve = require('path').resolve;
const app = express();

// If you need a backend, e.g. an API, add your custom backend-specific middleware here
// app.use('/api', myApi);

// In production we need to pass these values in instead of relying on webpack
setup(app, {
const middleware = setup(app, {
outputPath: resolve(process.cwd(), 'build'),
publicPath: '/',
});
Expand All @@ -28,16 +27,15 @@ app.listen(port, (err) => {
return logger.error(err.message);
}

// Connect to ngrok in dev mode
if (ngrok) {
ngrok.connect(port, (innerErr, url) => {
// Configure browserSync in dev mode
if (process.env.NODE_ENV !== 'production') {
browserSync(port, middleware, (innerErr) => {
if (innerErr) {
return logger.error(innerErr);
}

logger.appStarted(port, url);
logger.appStarted();
});
} else {
logger.appStarted(port);
logger.appStarted();
}
});
21 changes: 5 additions & 16 deletions server/logger.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
/* eslint-disable no-console */

const chalk = require('chalk');
const ip = require('ip');

const divider = chalk.gray('\n-----------------------------------');

/**
* Logger middleware, you can customize it to make messages more personal
Expand All @@ -16,21 +13,13 @@ const logger = {
},

// Called when express.js app starts on given port w/o errors
appStarted: (port, tunnelStarted) => {
appStarted: () => {
console.log(`Server started ${chalk.green('✓')}`);
},

// If the tunnel started, log that and the URL it's available at
if (tunnelStarted) {
console.log(`Tunnel initialised ${chalk.green('✓')}`);
}

console.log(`
${chalk.bold('Access URLs:')}${divider}
Localhost: ${chalk.magenta(`http://localhost:${port}`)}
LAN: ${chalk.magenta(`http://${ip.address()}:${port}`) +
(tunnelStarted ? `\n Proxy: ${chalk.magenta(tunnelStarted)}` : '')}${divider}
${chalk.blue(`Press ${chalk.italic('CTRL-C')} to stop`)}
`);
// Called when BrowserSync starts w/o errors
browserSyncStarted: () => {
console.log(`BrowserSync started ${chalk.green('✓')}`);
},
};

Expand Down
17 changes: 10 additions & 7 deletions server/middlewares/frontendMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ const addDevMiddlewares = (app, webpackConfig) => {
});

app.use(middleware);
app.use(webpackHotMiddleware(compiler));

const hotMiddleware = webpackHotMiddleware(compiler);
app.use(hotMiddleware);

// Since webpackDevMiddleware uses memory-fs internally to store build
// artifacts, we use it instead
Expand All @@ -40,6 +42,8 @@ const addDevMiddlewares = (app, webpackConfig) => {
}
});
});

return [middleware, hotMiddleware];
};

// Production middlewares
Expand All @@ -54,6 +58,8 @@ const addProdMiddlewares = (app, options) => {
app.use(publicPath, express.static(outputPath));

app.get('*', (req, res) => res.sendFile(path.resolve(outputPath, 'index.html')));

return [];
};

/**
Expand All @@ -63,11 +69,8 @@ module.exports = (app, options) => {
const isProd = process.env.NODE_ENV === 'production';

if (isProd) {
addProdMiddlewares(app, options);
} else {
const webpackConfig = require('../../internals/webpack/webpack.dev.babel');
addDevMiddlewares(app, webpackConfig);
return addProdMiddlewares(app, options);
}

return app;
const webpackConfig = require('../../internals/webpack/webpack.dev.babel');
return addDevMiddlewares(app, webpackConfig);
};

0 comments on commit d07da62

Please sign in to comment.