Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2802036

Browse files
committed
Hot module replacement on "live reload"
1 parent c8ac8e7 commit 2802036

File tree

5 files changed

+78
-30
lines changed

5 files changed

+78
-30
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"chai": "^3.5.0",
4848
"chai-http": "^3.0.0",
4949
"chokidar": "^1.6.1",
50-
"eslint": "^3.13.0",
50+
"eslint": "^3.13.1",
5151
"eslint-config-airbnb-base": "^11.0.1",
5252
"eslint-plugin-flowtype": "^2.29.2",
5353
"eslint-plugin-import": "^2.2.0",

scripts/build.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ const babel = require('babel-core');
1414
const chokidar = require('chokidar');
1515
const task = require('./task');
1616

17+
const delay100ms = (timeout => (callback) => {
18+
if (timeout) clearTimeout(timeout);
19+
timeout = setTimeout(callback, 100); // eslint-disable-line no-param-reassign
20+
})();
21+
1722
module.exports = task('build', ({ watch = false, onComplete } = {}) => new Promise((resolve) => {
1823
let ready = false;
1924

@@ -24,7 +29,7 @@ module.exports = task('build', ({ watch = false, onComplete } = {}) => new Promi
2429
watcher.on('all', (event, src) => {
2530
// Reload the app if .env or package.json file has changed (in watch mode)
2631
if (src === '.env' || src === 'package.json' || src === 'yarn.lock') {
27-
if (ready && onComplete) onComplete();
32+
if (ready && onComplete) delay100ms(onComplete);
2833
return;
2934
}
3035

@@ -62,12 +67,13 @@ module.exports = task('build', ({ watch = false, onComplete } = {}) => new Promi
6267
fs.writeFileSync(dest, data, 'utf8');
6368
console.log(src, '->', dest);
6469
}
65-
if (ready && onComplete) onComplete();
70+
if (ready && onComplete) delay100ms(onComplete);
6671
break;
6772

6873
// Remove directory if it was removed from the source folder
6974
case 'unlinkDir':
7075
if (fs.existsSync(dest)) fs.rmdirSync(dest);
76+
if (ready && onComplete) onComplete();
7177
break;
7278

7379
default:

scripts/run.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,9 @@ const task = require('./task');
1515
let build;
1616
let server;
1717

18-
// Run `node build/server.js` on a background thread
19-
function spawnServerProcess() {
20-
const args = process.env.NODE_DEBUG === 'true' ? ['--inspect', '--no-lazy'] : [];
21-
server = cp.spawn('node', [...args, 'server.js'], { cwd: './build', stdio: 'inherit' });
22-
}
23-
2418
// Gracefull shutdown
2519
process.once('cleanup', () => {
2620
if (server) {
27-
server.removeListener('exit', spawnServerProcess);
2821
server.addListener('exit', () => {
2922
server = null;
3023
process.exit();
@@ -67,12 +60,13 @@ module.exports = task('run', () => Promise.resolve()
6760
.then(() => build({
6861
watch: true,
6962
onComplete() {
70-
if (server) {
71-
server.removeListener('exit', spawnServerProcess);
72-
server.addListener('exit', spawnServerProcess);
73-
server.kill();
63+
if (!server) {
64+
// Launch `node build/server.js` on a background thread
65+
server = cp.spawn('node',
66+
[...(process.env.NODE_DEBUG === 'true' ? ['--inspect', '--no-lazy'] : []), 'server.js'],
67+
{ cwd: './build', stdio: ['inherit', 'inherit', 'inherit', 'ipc'] });
7468
} else {
75-
spawnServerProcess();
69+
server.send('reload');
7670
}
7771
},
7872
}))

src/server.js

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,54 @@
88
*/
99

1010
/* @flow */
11+
/* eslint-disable global-require, no-console, no-confusing-arrow */
1112

12-
import app from './app';
13-
import db from './db';
14-
import redis from './redis';
13+
let db;
14+
let app;
15+
let redis;
16+
let server;
17+
let reload = Promise.resolve();
1518

16-
const server = app.listen(process.env.PORT, () => {
17-
process.stdout.write(`Node.js API server is listening on http://localhost:${String(process.env.PORT)}/\n`);
18-
});
19+
// Launch Node.js server
20+
const launch = (callback) => {
21+
db = require('./db').default;
22+
app = require('./app').default;
23+
redis = require('./redis').default;
24+
server = app.listen(process.env.PORT, () => {
25+
console.log(`Node.js API server is listening on http://localhost:${String(process.env.PORT)}/`);
26+
if (callback) callback();
27+
});
28+
};
29+
30+
// Shutdown Node.js server and database clients
31+
const shutDown = () => Promise.resolve()
32+
.then(() => server && new Promise(resolve => server.close(resolve)))
33+
.then(() => Promise.all([
34+
() => db && db.destroy(),
35+
() => redis && new Promise(resolve => redis.quit(resolve)),
36+
]));
37+
38+
const handleError = err => console.error(err.stack);
1939

2040
// Graceful shutdown
21-
process.once('SIGTERM', () => {
22-
server.close(() => db.destroy(() => redis.quit(() => process.exit())));
23-
});
41+
process.once('SIGTERM', () => shutDown().then(() => process.exit()));
42+
43+
// In development mode the app is launched with an IPC channel
44+
if (process.channel) {
45+
// Prevent exiting the process in development mode
46+
process.on('uncaughtException', handleError);
47+
// Restart the server on code changes (see scripts/run.js)
48+
process.on('message', (message) => {
49+
if (message === 'reload') {
50+
reload = reload.then(() => shutDown()).then(() => {
51+
Object.keys(require.cache).forEach((key) => {
52+
if (key.indexOf('node_modules') === -1) delete require.cache[key];
53+
});
54+
return new Promise(resolve => launch(resolve)).catch(handleError);
55+
});
56+
}
57+
});
58+
process.on('disconnect', () => process.emit('SIGTERM'));
59+
}
2460

25-
export default server;
61+
launch();

yarn.lock

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -949,9 +949,9 @@ eslint-plugin-import@^2.2.0:
949949
minimatch "^3.0.3"
950950
pkg-up "^1.0.0"
951951

952-
eslint@^3.13.0:
953-
version "3.13.0"
954-
resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.13.0.tgz#636925fd163c9babe2e8be7ae43caf518d469577"
952+
eslint@^3.13.1:
953+
version "3.13.1"
954+
resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.13.1.tgz#564d2646b5efded85df96985332edd91a23bff25"
955955
dependencies:
956956
babel-code-frame "^6.16.0"
957957
chalk "^1.1.3"
@@ -1498,10 +1498,14 @@ http-signature@~1.1.0:
14981498
jsprim "^1.2.2"
14991499
sshpk "^1.7.0"
15001500

1501-
[email protected], iconv-lite@~0.4.13:
1501+
15021502
version "0.4.13"
15031503
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
15041504

1505+
[email protected], iconv-lite@~0.4.13:
1506+
version "0.4.15"
1507+
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
1508+
15051509
ignore@^3.2.0:
15061510
version "3.2.0"
15071511
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435"
@@ -2362,7 +2366,15 @@ range-parser@~1.2.0:
23622366
version "1.2.0"
23632367
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
23642368

2365-
raw-body@^2.1.0, raw-body@~2.1.7:
2369+
raw-body@^2.1.0:
2370+
version "2.2.0"
2371+
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96"
2372+
dependencies:
2373+
bytes "2.4.0"
2374+
iconv-lite "0.4.15"
2375+
unpipe "1.0.0"
2376+
2377+
raw-body@~2.1.7:
23662378
version "2.1.7"
23672379
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774"
23682380
dependencies:

0 commit comments

Comments
 (0)