Skip to content

Commit 1e20ac2

Browse files
authored
Bugfix: useSourceHash (#28) Generate source hash on emit because afterEmit only has SizeOnlySource (#67)
Feature: New option `useSourceSize` to compare source sizes
1 parent b5e7381 commit 1e20ac2

File tree

3 files changed

+102
-9
lines changed

3 files changed

+102
-9
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Add a script tag to your page pointed at the livereload server
4646
ignore nothing. It is also possible to define an array and use multiple [anymatch](https://github.com/micromatch/anymatch) patterns.
4747
- `delay` - (Default: `0`) amount of milliseconds by which to delay the live reload (in case build takes longer)
4848
- `useSourceHash` - (Default: `false`) create hash for each file source and only notify livereload if hash has changed
49+
- `useSourceSize` - (Default: `false`) check size for each file source and only notify livereload if size has changed (Faster than `useSourceHash` but it has a downside. If file size hasn't changed no reload is triggered. For example if color has changed from `#000000` to `#ffffff` no reload will be triggered!)
4950

5051
## Why?
5152

index.js

+56-5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class LiveReloadPlugin {
2525
ignore: null,
2626
quiet: false,
2727
useSourceHash: false,
28+
useSourceSize: false,
2829
appendScriptTag: false,
2930
delay: 0,
3031
}, options);
@@ -35,6 +36,7 @@ class LiveReloadPlugin {
3536
this.lastChildHashes = [];
3637
this.server = null;
3738
this.sourceHashs = {};
39+
this.sourceSizes = {};
3840
this.webpack = null;
3941
this.infrastructureLogger = null;
4042
this.isWebpack4 = false;
@@ -47,7 +49,8 @@ class LiveReloadPlugin {
4749

4850
compiler.hooks.compilation.tap(PLUGIN_NAME, this._applyCompilation.bind(this));
4951
compiler.hooks.watchRun.tapAsync(PLUGIN_NAME, this._start.bind(this));
50-
compiler.hooks.afterEmit.tap(PLUGIN_NAME, this._afterEmit.bind(this))
52+
compiler.hooks.afterEmit.tap(PLUGIN_NAME, this._afterEmit.bind(this));
53+
compiler.hooks.emit.tap(PLUGIN_NAME, this._emit.bind(this));
5154
compiler.hooks.failed.tap(PLUGIN_NAME, this._failed.bind(this));
5255
}
5356

@@ -145,6 +148,7 @@ class LiveReloadPlugin {
145148

146149
const include = Object.entries(compilation.assets)
147150
.filter(this._fileIgnoredOrNotEmitted.bind(this))
151+
.filter(this._fileSizeDoesntMatch.bind(this))
148152
.filter(this._fileHashDoesntMatch.bind(this))
149153
.map((data) => data[0])
150154
;
@@ -162,13 +166,22 @@ class LiveReloadPlugin {
162166
}
163167
}
164168

169+
/**
170+
* @private
171+
* @param compilation
172+
*/
173+
_emit(compilation) {
174+
Object.entries(compilation.assets).forEach(this._calculateSourceHash.bind(this));
175+
}
176+
165177
/**
166178
* @private
167179
*/
168180
_failed() {
169181
this.lastHash = null;
170182
this.lastChildHashes = [];
171183
this.sourceHashs = {};
184+
this.sourceSizes = {};
172185
}
173186

174187
/**
@@ -225,6 +238,25 @@ class LiveReloadPlugin {
225238
return !data[0].match(this.options.ignore) && size;
226239
}
227240

241+
/**
242+
* Check compiled source size
243+
*
244+
* @param data
245+
* @returns {boolean}
246+
* @private
247+
*/
248+
_fileSizeDoesntMatch(data) {
249+
if (!this.options.useSourceSize)
250+
return true;
251+
252+
if (this.sourceSizes[data[0]] === data[1].size()) {
253+
return false;
254+
}
255+
256+
this.sourceSizes[data[0]] = data[1].size();
257+
return true;
258+
}
259+
228260
/**
229261
* Check compiled source hash
230262
*
@@ -236,16 +268,35 @@ class LiveReloadPlugin {
236268
if (!this.options.useSourceHash)
237269
return true;
238270

239-
const sourceHash = LiveReloadPlugin.generateHashCode(data[1].source());
240-
241-
if (this.sourceHashs[data[0]] === sourceHash) {
271+
if (
272+
this.sourceHashs[data[0]] !== undefined
273+
&& this.sourceHashs[data[0]].hash === this.sourceHashs[data[0]].calculated
274+
) {
242275
return false;
243276
}
244277

245-
this.sourceHashs[data[0]] = sourceHash;
278+
// Update source hash
279+
this.sourceHashs[data[0]].hash = this.sourceHashs[data[0]].calculated;
246280
return true;
247281
}
248282

283+
/**
284+
* Calculate compiled source hash
285+
*
286+
* @param data
287+
* @returns {void}
288+
* @private
289+
*/
290+
_calculateSourceHash(data) {
291+
if (!this.options.useSourceHash) return;
292+
293+
// Calculate source hash
294+
this.sourceHashs[data[0]] = {
295+
hash: this.sourceHashs[data[0]] ? this.sourceHashs[data[0]].hash : null,
296+
calculated: LiveReloadPlugin.generateHashCode(data[1].source())
297+
};
298+
}
299+
249300
/**
250301
* @private
251302
*/

test.js

+45-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ test('default options', function(t) {
1010
t.equal(plugin.options.ignore, null);
1111
t.equal(plugin.options.quiet, false);
1212
t.equal(plugin.options.useSourceHash, false);
13+
t.equal(plugin.options.useSourceSize, false);
1314
t.equal(plugin.options.appendScriptTag, false);
1415
t.equal(plugin.options.delay, 0);
1516
t.equal(plugin._isRunning(), false);
@@ -178,6 +179,11 @@ test('filters out hashed files', function(t) {
178179
});
179180
const compilation = {
180181
assets: {
182+
'c.js': {
183+
emitted: true,
184+
size: () => 1,
185+
source: () => "asdf",
186+
},
181187
'b.js': {
182188
emitted: true,
183189
size: () => 1,
@@ -192,12 +198,47 @@ test('filters out hashed files', function(t) {
192198
children: []
193199
};
194200
plugin.sourceHashs = {
195-
'b.js': 'Wrong hash',
196-
'a.js': hashCode('asdf'),
201+
'b.js': {hash: 'Wrong hash'},
202+
'a.js': {hash: hashCode('asdf')},
197203
};
198204
plugin.server = {
199205
notifyClients: function(files) {
200-
t.deepEqual(files.sort(), ['b.js']);
206+
t.deepEqual(files.sort(), ['b.js', 'c.js']);
207+
t.end();
208+
}
209+
};
210+
plugin._emit(compilation);
211+
plugin._afterEmit(compilation);
212+
});
213+
214+
test('filters out resized files', function(t) {
215+
const plugin = new LiveReloadPlugin({
216+
useSourceSize: true,
217+
});
218+
const compilation = {
219+
assets: {
220+
'c.js': {
221+
emitted: true,
222+
size: () => 10,
223+
},
224+
'b.js': {
225+
emitted: true,
226+
size: () => 10,
227+
},
228+
'a.js': {
229+
emitted: true,
230+
size: () => 20,
231+
},
232+
},
233+
children: []
234+
};
235+
plugin.sourceSizes = {
236+
'b.js': 20,
237+
'a.js': 20,
238+
};
239+
plugin.server = {
240+
notifyClients: function(files) {
241+
t.deepEqual(files.sort(), ['b.js', 'c.js']);
201242
t.end();
202243
}
203244
};
@@ -275,4 +316,4 @@ test('autoloadJs suffixes empty protocol without colon', function(t) {
275316
const [,src] = plugin._autoloadJs().match(/src\s+=\s+"(.+)"/)
276317
t.assert(src.startsWith('//'));
277318
t.end();
278-
});
319+
});

0 commit comments

Comments
 (0)