Skip to content

Commit d18a1cc

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

File tree

3 files changed

+98
-9
lines changed

3 files changed

+98
-9
lines changed

README.md

Lines changed: 1 addition & 0 deletions
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

Lines changed: 53 additions & 5 deletions
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,32 @@ 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 (this.sourceHashs[data[0]]?.hash === this.sourceHashs[data[0]].calculated) {
242272
return false;
243273
}
244274

245-
this.sourceHashs[data[0]] = sourceHash;
275+
// Update source hash
276+
this.sourceHashs[data[0]].hash = this.sourceHashs[data[0]].calculated;
246277
return true;
247278
}
248279

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

test.js

Lines changed: 44 additions & 4 deletions
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,46 @@ 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._afterEmit(compilation);
211+
});
212+
213+
test('filters out resized files', function(t) {
214+
const plugin = new LiveReloadPlugin({
215+
useSourceSize: true,
216+
});
217+
const compilation = {
218+
assets: {
219+
'c.js': {
220+
emitted: true,
221+
size: () => 10,
222+
},
223+
'b.js': {
224+
emitted: true,
225+
size: () => 10,
226+
},
227+
'a.js': {
228+
emitted: true,
229+
size: () => 20,
230+
},
231+
},
232+
children: []
233+
};
234+
plugin.sourceSizes = {
235+
'b.js': 20,
236+
'a.js': 20,
237+
};
238+
plugin.server = {
239+
notifyClients: function(files) {
240+
t.deepEqual(files.sort(), ['b.js', 'c.js']);
201241
t.end();
202242
}
203243
};
@@ -275,4 +315,4 @@ test('autoloadJs suffixes empty protocol without colon', function(t) {
275315
const [,src] = plugin._autoloadJs().match(/src\s+=\s+"(.+)"/)
276316
t.assert(src.startsWith('//'));
277317
t.end();
278-
});
318+
});

0 commit comments

Comments
 (0)