From 61927eaa4d251c59893890c8eec9c7cb93319c81 Mon Sep 17 00:00:00 2001 From: Josh McCullough Date: Wed, 29 Jan 2020 10:02:29 -0500 Subject: [PATCH 1/3] feat: use webpack hashFunction rather than hard-code MD4 --- src/Webpack4Cache.js | 2 +- src/Webpack5Cache.js | 12 ++++++------ src/hash-helper.js | 16 +++++++++++++++ src/index.js | 7 +++---- test/hash-helper.test.js | 42 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 src/hash-helper.js create mode 100644 test/hash-helper.test.js diff --git a/src/Webpack4Cache.js b/src/Webpack4Cache.js index c4362de6..5dc5ae33 100644 --- a/src/Webpack4Cache.js +++ b/src/Webpack4Cache.js @@ -5,7 +5,7 @@ import findCacheDir from 'find-cache-dir'; import serialize from 'serialize-javascript'; export default class Webpack4Cache { - constructor(compilation, options) { + constructor(compiler, compilation, options) { this.options = options; this.cacheDir = options.cache === true diff --git a/src/Webpack5Cache.js b/src/Webpack5Cache.js index ff0e6d83..4e4576c7 100644 --- a/src/Webpack5Cache.js +++ b/src/Webpack5Cache.js @@ -1,13 +1,14 @@ -import crypto from 'crypto'; - // eslint-disable-next-line import/extensions,import/no-unresolved import getLazyHashedEtag from 'webpack/lib/cache/getLazyHashedEtag'; import serialize from 'serialize-javascript'; +import { getHasher } from './hash-helper'; + export default class Cache { - constructor(compilation, options) { - this.options = options; + constructor(compiler, compilation, options) { + this.compiler = compiler; this.compilation = compilation; + this.options = options; } isEnabled() { @@ -15,8 +16,7 @@ export default class Cache { } createCacheIdent(task) { - const cacheKeys = crypto - .createHash('md4') + const cacheKeys = getHasher(this.compiler) .update(serialize(task.cacheKeys)) .digest('hex'); diff --git a/src/hash-helper.js b/src/hash-helper.js new file mode 100644 index 00000000..cb3842dc --- /dev/null +++ b/src/hash-helper.js @@ -0,0 +1,16 @@ +import crypto from 'crypto'; + +export function getHasher(compiler = null) { + const hashFunction = + compiler && compiler.output && compiler.output.hashFunction; + + if (typeof hashFunction === 'string') { + return crypto.createHash(hashFunction); + } else if (typeof hashFunction === 'function') { + return hashFunction(); + } + return crypto.createHash('md4'); + +} + +export default getHasher; diff --git a/src/index.js b/src/index.js index 85e7d403..71b24290 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,3 @@ -import crypto from 'crypto'; import path from 'path'; import { SourceMapConsumer } from 'source-map'; @@ -16,6 +15,7 @@ import terserPackageJson from 'terser/package.json'; import schema from './options.json'; import TaskRunner from './TaskRunner'; +import { getHasher } from './hash-helper'; const warningRegex = /\[.+:([0-9]+),([0-9]+)\]/; @@ -394,8 +394,7 @@ class TerserPlugin { 'terser-webpack-plugin-options': this.options, nodeVersion: process.version, filename: file, - contentHash: crypto - .createHash('md4') + contentHash: getHasher(compiler) .update(input) .digest('hex'), }; @@ -499,7 +498,7 @@ class TerserPlugin { const taskRunner = new TaskRunner({ taskGenerator, files, - cache: new CacheEngine(compilation, this.options), + cache: new CacheEngine(compiler, compilation, this.options), parallel: this.options.parallel, }); diff --git a/test/hash-helper.test.js b/test/hash-helper.test.js new file mode 100644 index 00000000..a1d9512b --- /dev/null +++ b/test/hash-helper.test.js @@ -0,0 +1,42 @@ +import crypto from 'crypto'; + +import { getHasher } from '../src/hash-helper'; + +const UNHASHED = 'this is some text'; +const HASHED_MD4 = '565a21837631bdec2da173a5de2a2f87'; +const HASHED_SHA1 = '0393694d16b84deb612e47ce6252bd35f0d86c06'; + +describe('getHasher', () => { + it('should return MD4 hasher with no compiler parameter', () => { + const hasher = getHasher(); + + expect(hasher).not.toBeNull(); + expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_MD4); + }); + + it('should return MD4 hasher with incomplete compiler parameter', () => { + const compiler = { incomplete: { bad: {} } }; + const hasher = getHasher(compiler); + + expect(hasher).not.toBeNull(); + expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_MD4); + }); + + it('should return hasher with string as hashFunction', () => { + const compiler = { output: { hashFunction: 'SHA1' } }; + const hasher = getHasher(compiler); + + expect(hasher).not.toBeNull(); + expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_SHA1); + }); + + it('should return hasher with function as hashFunction', () => { + const compiler = { + output: { hashFunction: () => crypto.createHash('SHA1') }, + }; + const hasher = getHasher(compiler); + + expect(hasher).not.toBeNull(); + expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_SHA1); + }); +}); From 2e0285b3ba1236984070e7e4bded01da6c0ead7f Mon Sep 17 00:00:00 2001 From: Josh McCullough Date: Wed, 29 Jan 2020 10:36:22 -0500 Subject: [PATCH 2/3] fix: move getHasher to TerserPlugin --- src/Webpack5Cache.js | 4 ++-- src/hash-helper.js | 16 --------------- src/index.js | 17 ++++++++++++++-- test/TerserPlugin.test.js | 41 ++++++++++++++++++++++++++++++++++++++ test/hash-helper.test.js | 42 --------------------------------------- 5 files changed, 58 insertions(+), 62 deletions(-) delete mode 100644 src/hash-helper.js delete mode 100644 test/hash-helper.test.js diff --git a/src/Webpack5Cache.js b/src/Webpack5Cache.js index 4e4576c7..e610703c 100644 --- a/src/Webpack5Cache.js +++ b/src/Webpack5Cache.js @@ -2,7 +2,7 @@ import getLazyHashedEtag from 'webpack/lib/cache/getLazyHashedEtag'; import serialize from 'serialize-javascript'; -import { getHasher } from './hash-helper'; +import TerserPlugin from './index'; export default class Cache { constructor(compiler, compilation, options) { @@ -16,7 +16,7 @@ export default class Cache { } createCacheIdent(task) { - const cacheKeys = getHasher(this.compiler) + const cacheKeys = TerserPlugin.getHasher(this.compiler) .update(serialize(task.cacheKeys)) .digest('hex'); diff --git a/src/hash-helper.js b/src/hash-helper.js deleted file mode 100644 index cb3842dc..00000000 --- a/src/hash-helper.js +++ /dev/null @@ -1,16 +0,0 @@ -import crypto from 'crypto'; - -export function getHasher(compiler = null) { - const hashFunction = - compiler && compiler.output && compiler.output.hashFunction; - - if (typeof hashFunction === 'string') { - return crypto.createHash(hashFunction); - } else if (typeof hashFunction === 'function') { - return hashFunction(); - } - return crypto.createHash('md4'); - -} - -export default getHasher; diff --git a/src/index.js b/src/index.js index 71b24290..3771a310 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ +import crypto from 'crypto'; import path from 'path'; import { SourceMapConsumer } from 'source-map'; @@ -15,7 +16,6 @@ import terserPackageJson from 'terser/package.json'; import schema from './options.json'; import TaskRunner from './TaskRunner'; -import { getHasher } from './hash-helper'; const warningRegex = /\[.+:([0-9]+),([0-9]+)\]/; @@ -394,7 +394,7 @@ class TerserPlugin { 'terser-webpack-plugin-options': this.options, nodeVersion: process.version, filename: file, - contentHash: getHasher(compiler) + contentHash: TerserPlugin.getHasher(compiler) .update(input) .digest('hex'), }; @@ -566,6 +566,19 @@ class TerserPlugin { ); }); } + + static getHasher(compiler = null) { + const hashFunction = + compiler && compiler.output && compiler.output.hashFunction; + + if (typeof hashFunction === 'string') { + return crypto.createHash(hashFunction); + } else if (typeof hashFunction === 'function') { + return hashFunction(); + } + + return crypto.createHash('md4'); + } } export default TerserPlugin; diff --git a/test/TerserPlugin.test.js b/test/TerserPlugin.test.js index f73b614c..c289da33 100644 --- a/test/TerserPlugin.test.js +++ b/test/TerserPlugin.test.js @@ -1,3 +1,5 @@ +import crypto from 'crypto'; + import RequestShortener from 'webpack/lib/RequestShortener'; import { javascript } from 'webpack'; import MainTemplate from 'webpack/lib/MainTemplate'; @@ -385,3 +387,42 @@ describe('TerserPlugin', () => { ).toMatchSnapshot(); }); }); + +const UNHASHED = 'this is some text'; +const HASHED_MD4 = '565a21837631bdec2da173a5de2a2f87'; +const HASHED_SHA1 = '0393694d16b84deb612e47ce6252bd35f0d86c06'; + +describe('getHasher', () => { + it('should return MD4 hasher with no compiler parameter', () => { + const hasher = TerserPlugin.getHasher(); + + expect(hasher).not.toBeNull(); + expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_MD4); + }); + + it('should return MD4 hasher with incomplete compiler parameter', () => { + const compiler = { incomplete: { bad: {} } }; + const hasher = TerserPlugin.getHasher(compiler); + + expect(hasher).not.toBeNull(); + expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_MD4); + }); + + it('should return hasher with string as hashFunction', () => { + const compiler = { output: { hashFunction: 'SHA1' } }; + const hasher = TerserPlugin.getHasher(compiler); + + expect(hasher).not.toBeNull(); + expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_SHA1); + }); + + it('should return hasher with function as hashFunction', () => { + const compiler = { + output: { hashFunction: () => crypto.createHash('SHA1') }, + }; + const hasher = TerserPlugin.getHasher(compiler); + + expect(hasher).not.toBeNull(); + expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_SHA1); + }); +}); diff --git a/test/hash-helper.test.js b/test/hash-helper.test.js deleted file mode 100644 index a1d9512b..00000000 --- a/test/hash-helper.test.js +++ /dev/null @@ -1,42 +0,0 @@ -import crypto from 'crypto'; - -import { getHasher } from '../src/hash-helper'; - -const UNHASHED = 'this is some text'; -const HASHED_MD4 = '565a21837631bdec2da173a5de2a2f87'; -const HASHED_SHA1 = '0393694d16b84deb612e47ce6252bd35f0d86c06'; - -describe('getHasher', () => { - it('should return MD4 hasher with no compiler parameter', () => { - const hasher = getHasher(); - - expect(hasher).not.toBeNull(); - expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_MD4); - }); - - it('should return MD4 hasher with incomplete compiler parameter', () => { - const compiler = { incomplete: { bad: {} } }; - const hasher = getHasher(compiler); - - expect(hasher).not.toBeNull(); - expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_MD4); - }); - - it('should return hasher with string as hashFunction', () => { - const compiler = { output: { hashFunction: 'SHA1' } }; - const hasher = getHasher(compiler); - - expect(hasher).not.toBeNull(); - expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_SHA1); - }); - - it('should return hasher with function as hashFunction', () => { - const compiler = { - output: { hashFunction: () => crypto.createHash('SHA1') }, - }; - const hasher = getHasher(compiler); - - expect(hasher).not.toBeNull(); - expect(hasher.update(UNHASHED).digest('hex')).toEqual(HASHED_SHA1); - }); -}); From 49d0251061d9b22e4e7de2789a5ed3b053040edd Mon Sep 17 00:00:00 2001 From: Josh McCullough Date: Wed, 29 Jan 2020 11:01:15 -0500 Subject: [PATCH 3/3] fix: use Webpack's createHash function to get hasher --- src/index.js | 10 ++-------- test/TerserPlugin.test.js | 6 +++++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/index.js b/src/index.js index 3771a310..af55891c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,3 @@ -import crypto from 'crypto'; import path from 'path'; import { SourceMapConsumer } from 'source-map'; @@ -10,6 +9,7 @@ import { javascript, version as webpackVersion, } from 'webpack'; +import createHash from 'webpack/lib/util/createHash'; import validateOptions from 'schema-utils'; import serialize from 'serialize-javascript'; import terserPackageJson from 'terser/package.json'; @@ -571,13 +571,7 @@ class TerserPlugin { const hashFunction = compiler && compiler.output && compiler.output.hashFunction; - if (typeof hashFunction === 'string') { - return crypto.createHash(hashFunction); - } else if (typeof hashFunction === 'function') { - return hashFunction(); - } - - return crypto.createHash('md4'); + return createHash(hashFunction || 'md4'); } } diff --git a/test/TerserPlugin.test.js b/test/TerserPlugin.test.js index c289da33..6fce4fc9 100644 --- a/test/TerserPlugin.test.js +++ b/test/TerserPlugin.test.js @@ -417,8 +417,12 @@ describe('getHasher', () => { }); it('should return hasher with function as hashFunction', () => { + function sha1() { + return crypto.createHash('SHA1'); + } + const compiler = { - output: { hashFunction: () => crypto.createHash('SHA1') }, + output: { hashFunction: sha1 }, }; const hasher = TerserPlugin.getHasher(compiler);