diff --git a/README.md b/README.md index 7063fed3..ec57fdd0 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,33 @@ new HardSourceWebpackPlugin({ }), ``` +Some further configuration is possible through provided plugins. + +```js + plugins: [ + new HardSourceWebpackPlugin(), + + // You can optionally exclude items that may not be working with HardSource + // or items with custom loaders while you are actively developing the + // loader. + new HardSourceWebpackPlugin.ExcludeModulePlugin([ + { + // HardSource works with mini-css-extract-plugin but due to how + // mini-css emits assets, assets are not emitted on repeated builds with + // mini-css and hard-source together. Ignoring the mini-css loader + // modules, but not the other css loader modules, excludes the modules + // that mini-css needs rebuilt to output assets every time. + test: /mini-css-extract-plugin[\\/]dist[\\/]loader/, + }, + { + test: /my-loader/, + include: path.join(__dirname, 'vendor'), + }, + ]), + ] +``` + + ## Options ### `cacheDirectory` diff --git a/index.js b/index.js index e549425f..0d0b910b 100644 --- a/index.js +++ b/index.js @@ -20,11 +20,12 @@ const LoggerFactory = require('./lib/loggerFactory'); const cachePrefix = require('./lib/util').cachePrefix; const CacheSerializerFactory = require('./lib/CacheSerializerFactory'); -const SerializerAppendPlugin = require('./lib/SerializerAppendPlugin'); +const ExcludeModulePlugin = require('./lib/ExcludeModulePlugin'); +const HardSourceLevelDbSerializerPlugin = require('./lib/SerializerLeveldbPlugin'); const SerializerAppend2Plugin = require('./lib/SerializerAppend2Plugin'); +const SerializerAppendPlugin = require('./lib/SerializerAppendPlugin'); const SerializerCacachePlugin = require('./lib/SerializerCacachePlugin'); const SerializerJsonPlugin = require('./lib/SerializerJsonPlugin'); -const HardSourceLevelDbSerializerPlugin = require('./lib/SerializerLeveldbPlugin'); const hardSourceVersion = require('./package.json').version; @@ -557,8 +558,10 @@ class HardSourceWebpackPlugin { module.exports = HardSourceWebpackPlugin; -HardSourceWebpackPlugin.SerializerAppendPlugin = SerializerAppendPlugin; +HardSourceWebpackPlugin.ExcludeModulePlugin = ExcludeModulePlugin; +HardSourceWebpackPlugin.HardSourceLevelDbSerializerPlugin = HardSourceLevelDbSerializerPlugin; +HardSourceWebpackPlugin.LevelDbSerializerPlugin = HardSourceLevelDbSerializerPlugin; HardSourceWebpackPlugin.SerializerAppend2Plugin = SerializerAppend2Plugin; +HardSourceWebpackPlugin.SerializerAppendPlugin = SerializerAppendPlugin; HardSourceWebpackPlugin.SerializerCacachePlugin = SerializerCacachePlugin; HardSourceWebpackPlugin.SerializerJsonPlugin = SerializerJsonPlugin; -HardSourceWebpackPlugin.HardSourceLevelDbSerializerPlugin = HardSourceLevelDbSerializerPlugin; diff --git a/lib/ExcludeModulePlugin.js b/lib/ExcludeModulePlugin.js new file mode 100644 index 00000000..d5a25b00 --- /dev/null +++ b/lib/ExcludeModulePlugin.js @@ -0,0 +1,53 @@ +const pluginCompat = require('./util/plugin-compat'); + +const matchTest = (test, source) => { + if (Array.isArray(test)) { + return test.some(subtest => matchTest(subtest, source)); + } else if (test instanceof RegExp) { + return test.test(source); + } else if (typeof test === 'string') { + return source.startsWith(test); + } else if (typeof test === 'function') { + return test(source); + } + return false; +}; + +const matchOne = ({ test, include, exclude }, source) => { + return ( + (test ? matchTest(test, source) : true) && + (include ? matchTest(include, source) : true) && + (exclude ? !matchTest(exclude, source) : true) + ); +}; + +const matchAny = (test, source) => { + if (Array.isArray(test)) { + return test.some(subtest => matchOne(subtest, source)); + } + return matchOne(test, source); +}; + +class ExcludeModulePlugin { + constructor(match) { + this.match = match; + } + + apply(compiler) { + const compilerHooks = pluginCompat.hooks(compiler); + + compilerHooks.afterPlugins.tap('HardSource - ExcludeModulePlugin', () => { + compilerHooks._hardSourceAfterFreezeModule.tap( + 'HardSource - ExcludeModulePlugin', + (frozen, module, extra) => { + if (matchAny(this.match, module.identifier())) { + return null; + } + return frozen; + }, + ); + }); + } +} + +module.exports = ExcludeModulePlugin; diff --git a/tests/fixtures/hard-source-exclude-plugin/fib.js b/tests/fixtures/hard-source-exclude-plugin/fib.js new file mode 100644 index 00000000..a0a9ae75 --- /dev/null +++ b/tests/fixtures/hard-source-exclude-plugin/fib.js @@ -0,0 +1,3 @@ +module.exports = function(n) { + return n + (n > 0 ? n - 1 : 0); +}; diff --git a/tests/fixtures/hard-source-exclude-plugin/index.js b/tests/fixtures/hard-source-exclude-plugin/index.js new file mode 100644 index 00000000..8acf0395 --- /dev/null +++ b/tests/fixtures/hard-source-exclude-plugin/index.js @@ -0,0 +1,3 @@ +var fib = require('./fib'); + +console.log(fib(3)); diff --git a/tests/fixtures/hard-source-exclude-plugin/webpack.config.js b/tests/fixtures/hard-source-exclude-plugin/webpack.config.js new file mode 100644 index 00000000..f5b2835a --- /dev/null +++ b/tests/fixtures/hard-source-exclude-plugin/webpack.config.js @@ -0,0 +1,21 @@ +var HardSourceWebpackPlugin = require('../../..'); + +module.exports = { + context: __dirname, + entry: './index.js', + output: { + path: __dirname + '/tmp', + filename: 'main.js', + }, + plugins: [ + new HardSourceWebpackPlugin({ + cacheDirectory: 'cache', + environmentHash: { + root: __dirname + '/../../..', + }, + }), + new HardSourceWebpackPlugin.ExcludeModulePlugin({ + test: /fib\.js$/, + }), + ], +}; diff --git a/tests/hard-source.js b/tests/hard-source.js index b56248f7..bbe9f07e 100644 --- a/tests/hard-source.js +++ b/tests/hard-source.js @@ -2,8 +2,10 @@ var fs = require('fs'); var expect = require('chai').expect; -var itCompilesChange = require('./util').itCompilesChange; var itCompiles = require('./util').itCompiles; +var itCompilesChange = require('./util').itCompilesChange; +var itCompilesHardModules = require('./util').itCompilesHardModules; +var itCompilesTwice = require('./util').itCompilesTwice; var itCompilesWithCache = require('./util').itCompilesWithCache; var writeFiles = require('./util').writeFiles; @@ -273,4 +275,7 @@ describe('hard-source features', function() { 'yarn.lock': 'b', }); + itCompilesTwice('hard-source-exclude-plugin'); + itCompilesHardModules('hard-source-exclude-plugin', ['./index.js', '!./fib.js']); + }); diff --git a/tests/util/index.js b/tests/util/index.js index 604efe97..ad3bebe2 100644 --- a/tests/util/index.js +++ b/tests/util/index.js @@ -485,7 +485,11 @@ exports.itCompilesHardModules = function(fixturePath, filesA, filesB, expectHand }); } else { - expect(hardModules).to.include(handle); + if (handle.startsWith('!')) { + expect(hardModules).to.not.include(handle.substring(1)); + } else { + expect(hardModules).to.include(handle); + } } }); }