diff --git a/lib/index.js b/lib/index.js index a4ef3a90..95c6a65b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -186,6 +186,7 @@ module.exports = function loader (css, map) { return null }) }).catch((err) => { + if (err.file) this.addDependency(err.file) return err.name === 'CssSyntaxError' ? cb(new SyntaxError(err)) : cb(err) }) } diff --git a/package.json b/package.json index 31408441..907bb447 100644 --- a/package.json +++ b/package.json @@ -20,10 +20,12 @@ "jest": "^21.0.0", "jsdoc-to-markdown": "^3.0.0", "memory-fs": "^0.4.0", + "postcss-import": "^11.0.0", "postcss-js": "^1.0.0", "standard": "^10.0.0", "standard-version": "^4.0.0", "sugarss": "^1.0.0", + "util.promisify": "^1.0.0", "webpack": "^3.0.0" }, "scripts": { diff --git a/test/__snapshots__/loader.test.js.snap b/test/__snapshots__/loader.test.js.snap index 97a69ae8..b88ef9ef 100644 --- a/test/__snapshots__/loader.test.js.snap +++ b/test/__snapshots__/loader.test.js.snap @@ -1,3 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Loader Default 1`] = `"module.exports = \\"a { color: black }\\\\n\\""`; + +exports[`Loader Watching Dependencies Error 1`] = `"module.exports = \\"a { color: black }\\\\n\\""`; + +exports[`Loader Watching Dependencies Error 2`] = `"throw new Error(\\"Module build failed: Syntax Error \\\\n\\\\n(1:5) Unknown word\\\\n\\\\n\\\\u001b[31m\\\\u001b[1m>\\\\u001b[22m\\\\u001b[39m\\\\u001b[90m 1 | \\\\u001b[39ma \\\\u001b[33m{\\\\u001b[39m color black \\\\u001b[33m}\\\\u001b[39m\\\\n \\\\u001b[90m | \\\\u001b[39m \\\\u001b[31m\\\\u001b[1m^\\\\u001b[22m\\\\u001b[39m\\\\n \\\\u001b[90m 2 | \\\\u001b[39m\\\\n\\");"`; + +exports[`Loader Watching Dependencies Error 3`] = `"module.exports = \\"a { color: black }\\\\n\\""`; diff --git a/test/fixtures/watch/watching/index.js b/test/fixtures/watch/watching/index.js new file mode 100644 index 00000000..61e122b2 --- /dev/null +++ b/test/fixtures/watch/watching/index.js @@ -0,0 +1,3 @@ +import style from './style.css' + +export default style diff --git a/test/fixtures/watch/watching/noSyntaxError.css b/test/fixtures/watch/watching/noSyntaxError.css new file mode 100644 index 00000000..fa33ad5f --- /dev/null +++ b/test/fixtures/watch/watching/noSyntaxError.css @@ -0,0 +1 @@ +a { color: black } diff --git a/test/fixtures/watch/watching/style.css b/test/fixtures/watch/watching/style.css new file mode 100644 index 00000000..bee68e0d --- /dev/null +++ b/test/fixtures/watch/watching/style.css @@ -0,0 +1 @@ +@import "./styleDep"; diff --git a/test/fixtures/watch/watching/syntaxError.css b/test/fixtures/watch/watching/syntaxError.css new file mode 100644 index 00000000..4943cb88 --- /dev/null +++ b/test/fixtures/watch/watching/syntaxError.css @@ -0,0 +1 @@ +a { color black } diff --git a/test/helpers/compiler.js b/test/helpers/compiler.js index 8618632c..cbbfb32c 100644 --- a/test/helpers/compiler.js +++ b/test/helpers/compiler.js @@ -43,11 +43,21 @@ module.exports = function compiler (fixture, config, options) { if (!options.emit) compiler.outputFileSystem = new MemoryFS() - return new Promise((resolve, reject) => { - return compiler.run((err, stats) => { - if (err) reject(err) + if (options.watch) { + return new Promise((resolve, reject) => { + const watcher = compiler.watch({}, (err, stats) => { + options.watch(err, stats, (s) => { + watcher.close(resolve) + }) + }) + }) + } else { + return new Promise((resolve, reject) => { + return compiler.run((err, stats) => { + if (err) reject(err) - resolve(stats) + resolve(stats) + }) }) - }) + } } diff --git a/test/helpers/fs.js b/test/helpers/fs.js new file mode 100644 index 00000000..1a670be3 --- /dev/null +++ b/test/helpers/fs.js @@ -0,0 +1,33 @@ +const path = require('path') +const { readFile: _readFile, writeFile: _writeFile, unlink: _unlink } = require('fs') +const promisify = require('util.promisify') + +const fs = { + readFile: promisify(_readFile), + writeFile: promisify(_writeFile), + unlink: promisify(_unlink) +} + +function readFile (name) { + const file = path.join(__dirname, '../fixtures', name) + + return fs.readFile(file) + .then(data => data.toString()) +} + +function writeFile (name, contents) { + const file = path.join(__dirname, '../fixtures', name) + + return fs.writeFile(file, contents) +} + +module.exports.copyFile = function copyFile (src, dest) { + return readFile(src) + .then(contents => writeFile(dest, contents)) +} + +module.exports.deleteFile = function deleteFile (name) { + const file = path.join(__dirname, '../fixtures', name) + + return fs.unlink(file) +} diff --git a/test/loader.test.js b/test/loader.test.js index 57e8ffcd..7fbafe5b 100644 --- a/test/loader.test.js +++ b/test/loader.test.js @@ -2,6 +2,7 @@ const webpack = require('./helpers/compiler') const { loader } = require('./helpers/compilation') +const { copyFile, deleteFile } = require('./helpers/fs'); describe('Loader', () => { test('Default', () => { @@ -20,4 +21,67 @@ describe('Loader', () => { expect(src).toMatchSnapshot() }) }) + + describe('Watching', () => { + describe('Dependencies', () => { + const files = { + syntaxError: "watch/watching/syntaxError.css", + noSyntaxError: "watch/watching/noSyntaxError.css", + changingFile: "watch/watching/styleDep.css" + } + + beforeEach(() => copyFile(files.noSyntaxError, files.changingFile)) + + afterEach(() => deleteFile(files.changingFile)) + + test('Error', () => { + const config = { + loader: { + options: { + plugins: [require("postcss-import")], + } + } + } + + const steps = [ + (stats) => { + const { err, src } = loader(stats) + + expect(src).toMatchSnapshot() + expect(err.length).toEqual(0) + + return copyFile(files.syntaxError, files.changingFile) + }, + (stats) => { + const { err, src } = loader(stats) + + expect(src).toMatchSnapshot() + expect(err.length).toEqual(1) + + return copyFile(files.noSyntaxError, files.changingFile) + }, + (stats, close) => { + const { err, src } = loader(stats) + + expect(src).toMatchSnapshot() + expect(src).toEqual("module.exports = \"a { color: black }\\n\"") + expect(err.length).toEqual(0) + + return close() + } + ]; + + var currentStep = 0 + + const options = { + watch (err, stats, close) { + steps[currentStep](stats, close) + currentStep++ + } + } + + return webpack('watch/watching/index.js', config, options) + }) + }) + }) })