Skip to content

Commit

Permalink
Bugfix: useSourceHash (#28) Generate source hash on emit because af…
Browse files Browse the repository at this point in the history
…terEmit only has SizeOnlySource

Feature: New option `useSourceSize` to compare source sizes
  • Loading branch information
web-mi committed Apr 28, 2021
1 parent b5e7381 commit 7696820
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 9 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Add a script tag to your page pointed at the livereload server
ignore nothing. It is also possible to define an array and use multiple [anymatch](https://github.com/micromatch/anymatch) patterns.
- `delay` - (Default: `0`) amount of milliseconds by which to delay the live reload (in case build takes longer)
- `useSourceHash` - (Default: `false`) create hash for each file source and only notify livereload if hash has changed
- `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!)

## Why?

Expand Down
58 changes: 53 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class LiveReloadPlugin {
ignore: null,
quiet: false,
useSourceHash: false,
useSourceSize: false,
appendScriptTag: false,
delay: 0,
}, options);
Expand All @@ -35,6 +36,7 @@ class LiveReloadPlugin {
this.lastChildHashes = [];
this.server = null;
this.sourceHashs = {};
this.sourceSizes = {};
this.webpack = null;
this.infrastructureLogger = null;
this.isWebpack4 = false;
Expand All @@ -47,7 +49,8 @@ class LiveReloadPlugin {

compiler.hooks.compilation.tap(PLUGIN_NAME, this._applyCompilation.bind(this));
compiler.hooks.watchRun.tapAsync(PLUGIN_NAME, this._start.bind(this));
compiler.hooks.afterEmit.tap(PLUGIN_NAME, this._afterEmit.bind(this))
compiler.hooks.afterEmit.tap(PLUGIN_NAME, this._afterEmit.bind(this));
compiler.hooks.emit.tap(PLUGIN_NAME, this._emit.bind(this));
compiler.hooks.failed.tap(PLUGIN_NAME, this._failed.bind(this));
}

Expand Down Expand Up @@ -145,6 +148,7 @@ class LiveReloadPlugin {

const include = Object.entries(compilation.assets)
.filter(this._fileIgnoredOrNotEmitted.bind(this))
.filter(this._fileSizeDoesntMatch.bind(this))
.filter(this._fileHashDoesntMatch.bind(this))
.map((data) => data[0])
;
Expand All @@ -162,13 +166,22 @@ class LiveReloadPlugin {
}
}

/**
* @private
* @param compilation
*/
_emit(compilation) {
Object.entries(compilation.assets).forEach(this._calculateSourceHash.bind(this));
}

/**
* @private
*/
_failed() {
this.lastHash = null;
this.lastChildHashes = [];
this.sourceHashs = {};
this.sourceSizes = {};
}

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

/**
* Check compiled source size
*
* @param data
* @returns {boolean}
* @private
*/
_fileSizeDoesntMatch(data) {
if (!this.options.useSourceSize)
return true;

if (this.sourceSizes[data[0]] === data[1].size()) {
return false;
}

this.sourceSizes[data[0]] = data[1].size();
return true;
}

/**
* Check compiled source hash
*
Expand All @@ -236,16 +268,32 @@ class LiveReloadPlugin {
if (!this.options.useSourceHash)
return true;

const sourceHash = LiveReloadPlugin.generateHashCode(data[1].source());

if (this.sourceHashs[data[0]] === sourceHash) {
if (this.sourceHashs[data[0]].hash === this.sourceHashs[data[0]].calculated) {
return false;
}

this.sourceHashs[data[0]] = sourceHash;
// Update source hash
this.sourceHashs[data[0]].hash = this.sourceHashs[data[0]].calculated;
return true;
}

/**
* Calculate compiled source hash
*
* @param data
* @returns {void}
* @private
*/
_calculateSourceHash(data) {
if (!this.options.useSourceHash) return;

// Calculate source hash
this.sourceHashs[data[0]] = {
hash: this.sourceHashs[data[0]]?.hash ?? null,
calculated: LiveReloadPlugin.generateHashCode(data[1].source())
};
}

/**
* @private
*/
Expand Down
48 changes: 44 additions & 4 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ test('default options', function(t) {
t.equal(plugin.options.ignore, null);
t.equal(plugin.options.quiet, false);
t.equal(plugin.options.useSourceHash, false);
t.equal(plugin.options.useSourceSize, false);
t.equal(plugin.options.appendScriptTag, false);
t.equal(plugin.options.delay, 0);
t.equal(plugin._isRunning(), false);
Expand Down Expand Up @@ -178,6 +179,11 @@ test('filters out hashed files', function(t) {
});
const compilation = {
assets: {
'c.js': {
emitted: true,
size: () => 1,
source: () => "asdf",
},
'b.js': {
emitted: true,
size: () => 1,
Expand All @@ -192,12 +198,46 @@ test('filters out hashed files', function(t) {
children: []
};
plugin.sourceHashs = {
'b.js': 'Wrong hash',
'a.js': hashCode('asdf'),
'b.js': {hash: 'Wrong hash'},
'a.js': {hash: hashCode('asdf')},
};
plugin.server = {
notifyClients: function(files) {
t.deepEqual(files.sort(), ['b.js']);
t.deepEqual(files.sort(), ['b.js', 'c.js']);
t.end();
}
};
plugin._afterEmit(compilation);
});

test('filters out resized files', function(t) {
const plugin = new LiveReloadPlugin({
useSourceSize: true,
});
const compilation = {
assets: {
'c.js': {
emitted: true,
size: () => 10,
},
'b.js': {
emitted: true,
size: () => 10,
},
'a.js': {
emitted: true,
size: () => 20,
},
},
children: []
};
plugin.sourceSizes = {
'b.js': 20,
'a.js': 20,
};
plugin.server = {
notifyClients: function(files) {
t.deepEqual(files.sort(), ['b.js', 'c.js']);
t.end();
}
};
Expand Down Expand Up @@ -275,4 +315,4 @@ test('autoloadJs suffixes empty protocol without colon', function(t) {
const [,src] = plugin._autoloadJs().match(/src\s+=\s+"(.+)"/)
t.assert(src.startsWith('//'));
t.end();
});
});

0 comments on commit 7696820

Please sign in to comment.