From 4bdf08bf1b306adc5c3ae640a8cfe04714cbc63b Mon Sep 17 00:00:00 2001 From: Evilebot Tnawi Date: Tue, 27 Nov 2018 14:54:58 +0300 Subject: [PATCH] fix: emit warnings on broken `@import` (#806) BREAKING CHANGE: invalid `@import` at rules now emit warnings --- lib/Warning.js | 20 ++++++ lib/postcss-css-loader-parser.js | 4 ++ lib/processCss.js | 7 +++ test/__snapshots__/import-option.test.js.snap | 62 ++++++++++++++++++- test/__snapshots__/loader.test.js.snap | 4 +- test/helpers.js | 7 +-- test/import-option.test.js | 8 ++- 7 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 lib/Warning.js diff --git a/lib/Warning.js b/lib/Warning.js new file mode 100644 index 00000000..20584fff --- /dev/null +++ b/lib/Warning.js @@ -0,0 +1,20 @@ +module.exports = class Warning extends Error { + constructor(warning) { + super(warning); + const { text, line, column } = warning; + this.name = 'Warning'; + + // Based on https://github.com/postcss/postcss/blob/master/lib/warning.es6#L74 + // We don't need `plugin` properties. + this.message = `${this.name}\n\n`; + + if (typeof line !== 'undefined') { + this.message += `(${line}:${column}) `; + } + + this.message += `${text}`; + + // We don't need stack https://github.com/postcss/postcss/blob/master/docs/guidelines/runner.md#31-dont-show-js-stack-for-csssyntaxerror + this.stack = false; + } +}; diff --git a/lib/postcss-css-loader-parser.js b/lib/postcss-css-loader-parser.js index 8b659295..9203ec2b 100644 --- a/lib/postcss-css-loader-parser.js +++ b/lib/postcss-css-loader-parser.js @@ -63,6 +63,10 @@ module.exports = postcss.plugin( } if (!url.replace(/\s/g, '').length) { + result.warn(`Unable to find uri in '${atrule.toString()}'`, { + node: atrule, + }); + return; } diff --git a/lib/processCss.js b/lib/processCss.js index ccc0e99b..90b01d49 100644 --- a/lib/processCss.js +++ b/lib/processCss.js @@ -12,6 +12,7 @@ const modulesValues = require('postcss-modules-values'); const cssLoaderParser = require('./postcss-css-loader-parser'); +const Warning = require('./Warning'); const CssSyntaxError = require('./CssSyntaxError'); const { getLocalIdent } = require('./utils'); @@ -83,6 +84,12 @@ module.exports = function processCss(inputSource, inputMap, options, callback) { : null, }) .then((result) => { + result + .warnings() + .forEach((warning) => + options.loaderContext.emitWarning(new Warning(warning)) + ); + callback(null, { source: result.css, map: result.map && result.map.toJSON(), diff --git a/test/__snapshots__/import-option.test.js.snap b/test/__snapshots__/import-option.test.js.snap index a4e57ee3..537ebded 100644 --- a/test/__snapshots__/import-option.test.js.snap +++ b/test/__snapshots__/import-option.test.js.snap @@ -240,4 +240,64 @@ exports.push([module.id, \\"@import URL(test.css);\\\\n@import url();\\\\n@impor " `; -exports[`import option true: warnings 1`] = `Array []`; +exports[`import option true: warnings 1`] = ` +Array [ + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(12:1) Unable to find uri in '@import url()'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(13:1) Unable to find uri in '@import url('')'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(14:1) Unable to find uri in '@import url(\\"\\")'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(17:1) Unable to find uri in '@import '''", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(18:1) Unable to find uri in '@import \\"\\"'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(19:1) Unable to find uri in '@import \\" \\"'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(20:1) Unable to find uri in '@import \\" +\\"'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(22:1) Unable to find uri in '@import url()'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(23:1) Unable to find uri in '@import url('')'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(24:1) Unable to find uri in '@import url(\\"\\")'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(37:1) Unable to find uri in '@import '", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(38:1) Unable to find uri in '@import foo-bar'", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(40:1) It looks like you didn't end your @import statement correctly. Child nodes are attached to it.", + "ModuleWarning: Module Warning (from \`replaced original path\`): +Warning + +(5:1) Unable to find uri in '@import URL(test.css)'", +] +`; diff --git a/test/__snapshots__/loader.test.js.snap b/test/__snapshots__/loader.test.js.snap index 2018c6ae..6bb6aba0 100644 --- a/test/__snapshots__/loader.test.js.snap +++ b/test/__snapshots__/loader.test.js.snap @@ -392,7 +392,7 @@ exports[`loader should compile with empty css entry point: warnings 1`] = `Array exports[`loader should throw error on invalid css syntax: errors 1`] = ` Array [ - [ModuleBuildError: Module build failed (from \`replaced original path\`): + "ModuleBuildError: Module build failed (from \`replaced original path\`): CssSyntaxError (2:3) Unknown word @@ -402,7 +402,7 @@ CssSyntaxError | ^ 3 | } 4 | -], +", ] `; diff --git a/test/helpers.js b/test/helpers.js index e9af5e9b..cdcc5acc 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -308,12 +308,11 @@ exports.evaluated = evaluated; function normalizeErrors(errors) { return errors.map((error) => { - // eslint-disable-next-line no-param-reassign - error.message = stripAnsi(error.message) + const message = error.toString(); + + return stripAnsi(message) .replace(/\(from .*?\)/, '(from `replaced original path`)') .replace(/at(.*?)\(.*?\)/g, 'at$1(`replaced original path`)'); - - return error; }); } diff --git a/test/import-option.test.js b/test/import-option.test.js index 61684e51..d5d3c2a0 100644 --- a/test/import-option.test.js +++ b/test/import-option.test.js @@ -1,4 +1,4 @@ -const { webpack, evaluated } = require('./helpers'); +const { webpack, evaluated, normalizeErrors } = require('./helpers'); describe('import option', () => { it('true', async () => { @@ -11,8 +11,10 @@ describe('import option', () => { expect(evaluated(module.source, modules)).toMatchSnapshot( 'module (evaluated)' ); - expect(stats.compilation.warnings).toMatchSnapshot('warnings'); - expect(stats.compilation.errors).toMatchSnapshot('errors'); + expect(normalizeErrors(stats.compilation.warnings)).toMatchSnapshot( + 'warnings' + ); + expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot('errors'); }); it('false', async () => {