From 5d21b2fb88a129117f9ed76a5625a27b2699284c Mon Sep 17 00:00:00 2001 From: Cole Turner Date: Mon, 17 Jul 2017 05:37:48 -0400 Subject: [PATCH] Support issuer filtering when matching rules (fixes #149) (#150) * fix(loader): add support for issuer when matching rules With Webpack v2 one can use svg-sprite-loader for JavaScript/JSX modules while still using other loaders in other contexts (CSS for example). This is possible by using the "issuer" configuration for loader rules. For use with Webpack v1 an error will still occur. Fixes #149 * test(loader): add coverage for Webpack v1+2 handling of issuer in rules This adds coverage to the loader tests so that the "issuer" attribute on loader rules is honored when evaluating Webpack v2 config. For v1 configuration the issuer attribute is ignored and the previous errors are expected. --- lib/loader.js | 3 ++- lib/utils/get-matched-rules.js | 22 +++++++++++++++++++--- test/loader.test.js | 17 ++++++++++++++++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/loader.js b/lib/loader.js index 232f073..fd507d8 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -53,7 +53,8 @@ module.exports = function loader(content) { throw new Exceptions.InvalidRuntimeException(config.runtimeGenerator); } - const matchedRules = utils.getMatchedRules(resource, utils.getLoadersRules(compiler)); + const issuer = loaderContext._module && loaderContext._module.issuer; + const matchedRules = utils.getMatchedRules(resource, utils.getLoadersRules(compiler), issuer); if (matchedRules.length > 1 && !compiler.isChild()) { this.emitWarning(new Exceptions.SeveralRulesAppliedException(resource, matchedRules)); } diff --git a/lib/utils/get-matched-rules.js b/lib/utils/get-matched-rules.js index ba52d43..35910ce 100644 --- a/lib/utils/get-matched-rules.js +++ b/lib/utils/get-matched-rules.js @@ -1,13 +1,29 @@ -// eslint-disable-next-line import/no-extraneous-dependencies +/* eslint-disable import/no-extraneous-dependencies */ const ruleMatcher = require('webpack/lib/ModuleFilenameHelpers').matchObject; +const isWebpack1 = require('./is-webpack-1'); +const RuleSet = !isWebpack1 ? require('webpack/lib/RuleSet') : null; /** * @param {string} request * @param {Rule[]} rules Webpack loaders config * @return {Rule[]} */ -function getMatchedRules(request, rules) { - return rules.filter(rule => ruleMatcher(rule, request)); +function getMatchedRules(request, rules, issuer) { + const matchedRules = rules.filter(rule => ruleMatcher(rule, request)); + + if (issuer) { + return matchedRules.filter((rule) => { + // If rule doesn't have an issuer or RuleSet is not available + if (!rule.issuer || !RuleSet) { + return true; + } + + const matcher = RuleSet.normalizeCondition(rule.issuer); + return matcher(issuer); + }); + } + + return matchedRules; } module.exports = getMatchedRules; diff --git a/test/loader.test.js b/test/loader.test.js index dc0958a..62226e3 100644 --- a/test/loader.test.js +++ b/test/loader.test.js @@ -37,7 +37,7 @@ describe('loader and plugin', () => { errors[0].error.should.be.instanceOf(Exceptions.InvalidRuntimeException); }); - it('should warn if several rules applied to module', async () => { + it('should warn if several rules applied to module without issuer applied', async () => { const { warnings } = await compile({ entry: './entry', module: rules( @@ -64,6 +64,21 @@ describe('loader and plugin', () => { assets['main.js'].source().should.contain('olala'); }); + + it('should filter rules against issuer', async () => { + const { warnings } = await compile({ + entry: './entry', + module: rules( + svgRule(), + rule({ test: /\.svg$/, loader: loaderPath, issuer: /\.css$/ }) + ) + }); + + warnings.should.be.lengthOf(isWebpack1 ? 2 : 0); + if (isWebpack1) { + warnings[0].warning.should.be.instanceOf(Exceptions.SeveralRulesAppliedException); + } + }); }); describe('extract mode', () => {