From 75a977f90c359409d19598d94bad6188936eb030 Mon Sep 17 00:00:00 2001 From: Patrick Abkarian Date: Sat, 4 Aug 2018 06:45:35 +0200 Subject: [PATCH 01/17] chore(package): update `postcss` v6.0.0...7.0.0 (`dependencies`) (#375) BREAKING CHANGE: requires `node >= v6.0.0` --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 4d26c130..bbeaf8da 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,11 @@ "lib" ], "engines": { - "node": ">= 4" + "node": ">= 6" }, "dependencies": { "loader-utils": "^1.1.0", - "postcss": "^6.0.0", + "postcss": "^7.0.0", "postcss-load-config": "^2.0.0", "schema-utils": "^0.4.0" }, @@ -20,7 +20,7 @@ "jsdoc-to-markdown": "^4.0.0", "memory-fs": "^0.4.0", "postcss-import": "^11.0.0", - "postcss-js": "^1.0.0", + "postcss-js": "^2.0.0", "standard": "^11.0.0", "standard-version": "^4.0.0", "sugarss": "^1.0.0", From 5e6e859a855ceafea62f826db79239766ef6a40a Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sat, 4 Aug 2018 11:27:14 +0200 Subject: [PATCH 02/17] test: replace helpers with `@webpack-utilities/test` (#386) --- package.json | 15 +++-- {lib => src}/Error.js | 0 {lib => src}/index.js | 0 {lib => src}/options.js | 0 {lib => src}/options.json | 0 test/Errors.test.js | 54 +++++++++++++---- test/__snapshots__/Errors.test.js.snap | 6 +- test/__snapshots__/loader.test.js.snap | 6 -- test/fixtures/watch/error.css | 1 - test/fixtures/watch/index.css | 1 - test/fixtures/watch/index.js | 3 - test/fixtures/watch/style.css | 1 - test/helpers/compilation.js | 66 -------------------- test/helpers/compiler.js | 63 ------------------- test/helpers/fs.js | 38 ------------ test/loader.test.js | 83 ++------------------------ test/options/config.test.js | 57 +++++++++++------- test/options/exec.test.js | 18 +++--- test/options/parser.test.js | 19 +++--- test/options/plugins.test.js | 45 +++++++++----- test/options/sourceMap.test.js | 34 +++++++---- test/options/stringifier.test.js | 19 +++--- test/options/syntax.test.js | 19 +++--- 23 files changed, 180 insertions(+), 368 deletions(-) rename {lib => src}/Error.js (100%) rename {lib => src}/index.js (100%) rename {lib => src}/options.js (100%) rename {lib => src}/options.json (100%) delete mode 100644 test/fixtures/watch/error.css delete mode 100644 test/fixtures/watch/index.css delete mode 100644 test/fixtures/watch/index.js delete mode 100644 test/fixtures/watch/style.css delete mode 100644 test/helpers/compilation.js delete mode 100644 test/helpers/compiler.js delete mode 100644 test/helpers/fs.js diff --git a/package.json b/package.json index bbeaf8da..4388e118 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "postcss-loader", "version": "2.1.6", "description": "PostCSS loader for webpack", - "main": "lib/index.js", + "main": "src/index.js", "files": [ - "lib" + "src" ], "engines": { "node": ">= 6" @@ -16,21 +16,20 @@ "schema-utils": "^0.4.0" }, "devDependencies": { - "jest": "^22.0.0", + "@webpack-utilities/test": "^1.0.0-alpha.0", + "jest": "^23.0.0", "jsdoc-to-markdown": "^4.0.0", - "memory-fs": "^0.4.0", "postcss-import": "^11.0.0", "postcss-js": "^2.0.0", "standard": "^11.0.0", "standard-version": "^4.0.0", "sugarss": "^1.0.0", - "util.promisify": "^1.0.0", - "webpack": "^3.0.0" + "webpack": "^4.0.0" }, "scripts": { "lint": "standard --env jest", - "test": "jest --env=node --verbose --coverage", - "docs": "jsdoc2md lib/index.js > LOADER.md", + "test": "jest --env node --verbose --coverage", + "docs": "jsdoc2md src/*.js > LOADER.md", "clean": "rm -rf coverage test/outputs", "release": "standard-version" }, diff --git a/lib/Error.js b/src/Error.js similarity index 100% rename from lib/Error.js rename to src/Error.js diff --git a/lib/index.js b/src/index.js similarity index 100% rename from lib/index.js rename to src/index.js diff --git a/lib/options.js b/src/options.js similarity index 100% rename from lib/options.js rename to src/options.js diff --git a/lib/options.json b/src/options.json similarity index 100% rename from lib/options.json rename to src/options.json diff --git a/test/Errors.test.js b/test/Errors.test.js index da8b4cb9..718f8c9a 100644 --- a/test/Errors.test.js +++ b/test/Errors.test.js @@ -1,21 +1,41 @@ -'use strict' - -const webpack = require('./helpers/compiler') -const { loader } = require('./helpers/compilation') +const { webpack } = require('@webpack-utilities/test') describe('Errors', () => { test('Validation Error', () => { - const loader = require('../lib') + const config = { + loader: { + test: /\.css$/, + options: { + sourceMap: 1 + } + } + } + + return webpack('css/index.js', config).then((stats) => { + const { source } = stats.toJson().modules[1] - const error = () => loader.call({ query: { sourceMap: 1 } }) + // eslint-disable-next-line + const error = () => eval(source) - expect(error).toThrow() - expect(error).toThrowErrorMatchingSnapshot() + expect(error).toThrow() + + try { + error() + } catch (err) { + const message = err.message + .split('\n') + .slice(1) + .join('\n') + + expect(message).toMatchSnapshot() + } + }) }) test('Syntax Error', () => { const config = { loader: { + test: /\.css$/, options: { parser: 'sugarss' } @@ -23,9 +43,23 @@ describe('Errors', () => { } return webpack('css/index.js', config).then((stats) => { - const error = loader(stats).err + const { source } = stats.toJson().modules[1] - expect(error[0]).toMatchSnapshot() + // eslint-disable-next-line + const error = () => eval(source) + + expect(error).toThrow() + + try { + error() + } catch (err) { + const message = err.message + .split('\n') + .slice(1) + .join('\n') + + expect(message).toMatchSnapshot() + } }) }) }) diff --git a/test/__snapshots__/Errors.test.js.snap b/test/__snapshots__/Errors.test.js.snap index cba7269b..6db3e25c 100644 --- a/test/__snapshots__/Errors.test.js.snap +++ b/test/__snapshots__/Errors.test.js.snap @@ -1,18 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Errors Syntax Error 1`] = ` -[ModuleBuildError: Module build failed: Syntax Error +"Syntax Error (1:3) Unexpected separator in property > 1 | a { color: black }  |  ^  2 |  -] +" `; exports[`Errors Validation Error 1`] = ` -"PostCSS Loader Invalid Options +"ValidationError: PostCSS Loader Invalid Options options.sourceMap should be string,boolean " diff --git a/test/__snapshots__/loader.test.js.snap b/test/__snapshots__/loader.test.js.snap index b88ef9ef..97a69ae8 100644 --- a/test/__snapshots__/loader.test.js.snap +++ b/test/__snapshots__/loader.test.js.snap @@ -1,9 +1,3 @@ // 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/error.css b/test/fixtures/watch/error.css deleted file mode 100644 index 4943cb88..00000000 --- a/test/fixtures/watch/error.css +++ /dev/null @@ -1 +0,0 @@ -a { color black } diff --git a/test/fixtures/watch/index.css b/test/fixtures/watch/index.css deleted file mode 100644 index fa33ad5f..00000000 --- a/test/fixtures/watch/index.css +++ /dev/null @@ -1 +0,0 @@ -a { color: black } diff --git a/test/fixtures/watch/index.js b/test/fixtures/watch/index.js deleted file mode 100644 index 61e122b2..00000000 --- a/test/fixtures/watch/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import style from './style.css' - -export default style diff --git a/test/fixtures/watch/style.css b/test/fixtures/watch/style.css deleted file mode 100644 index 40d6c214..00000000 --- a/test/fixtures/watch/style.css +++ /dev/null @@ -1 +0,0 @@ -@import "./import"; diff --git a/test/helpers/compilation.js b/test/helpers/compilation.js deleted file mode 100644 index 2f61ffbf..00000000 --- a/test/helpers/compilation.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict' - -const loader = (stats) => { - const modules = stats.compilation.modules - - return { - err: modules.map((module) => module.errors)[1], - src: modules.map((module) => module._source._value)[1], - map: modules.map((module) => module._source._sourceMap)[1], - meta: modules.map((module) => module.meta), - warnings: modules.map((module) => module.warnings)[1] - } -} - -const loaders = (stats, i) => { - const modules = stats.compilation.modules - - return i >= 0 - ? { - err: modules.map((module) => module.errors)[i], - src: modules.map((module) => module._source._value)[i], - map: modules.map((module) => module._source._sourceMap)[i], - meta: modules.map((module) => module.meta)[i], - warning: modules.map((module) => module.warnings)[i] - } - : { - err: modules.map((module) => module.errors), - src: modules.map((module) => module._source._value), - map: modules.map((module) => module._source._sourceMap), - meta: modules.map((module) => module.meta), - warning: modules.map((module) => module.warnings) - } -} - -const assets = (stats, i) => { - const asset = (asset) => { - if (/map/.test(asset)) return false - return stats.compilation.assets[asset].sourceAndMap() - } - - const assets = Object.keys(stats.compilation.assets) - .map(asset) - .filter(Boolean) - - return i >= 0 ? assets[i] : assets -} - -const errors = (stats, i) => { - const errors = stats.compilation.errors - - return i >= 0 ? errors[i] : errors -} - -const warnings = (stats, i) => { - const warnings = stats.compilation.warnings - - return i >= 0 ? warnings[i] : warnings -} - -module.exports = { - loader, - loaders, - assets, - errors, - warnings -} diff --git a/test/helpers/compiler.js b/test/helpers/compiler.js deleted file mode 100644 index bef499a2..00000000 --- a/test/helpers/compiler.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict' - -const path = require('path') -const webpack = require('webpack') -const MemoryFS = require('memory-fs') - -module.exports = function compiler (fixture, config, options) { - config = { - devtool: config.devtool || 'sourcemap', - context: path.resolve(__dirname, '..', 'fixtures'), - entry: `./${fixture}`, - output: { - path: path.resolve( - __dirname, - `../outputs/${config.path ? config.path : ''}` - ), - filename: '[name].bundle.js' - }, - module: { - rules: config.rules || config.loader - ? [ - { - test: config.loader.test || /\.(css|sss)$/, - use: { - loader: path.resolve(__dirname, '../../lib'), - options: config.loader.options || {} - } - } - ] - : [] - }, - plugins: [ - new webpack.optimize.CommonsChunkPlugin({ - name: [ 'runtime' ], - minChunks: Infinity - }) - ].concat(config.plugins || []) - } - - options = Object.assign({ emit: false }, options) - - const compiler = webpack(config) - - if (!options.emit) compiler.outputFileSystem = new MemoryFS() - - if (options.watch) { - return new Promise((resolve, reject) => { - const watcher = compiler.watch({}, (err, stats) => { - options.watch(err, stats, () => { - watcher.close(resolve) - }) - }) - }) - } else { - return new Promise((resolve, reject) => { - return compiler.run((err, stats) => { - if (err) reject(err) - - resolve(stats) - }) - }) - } -} diff --git a/test/helpers/fs.js b/test/helpers/fs.js deleted file mode 100644 index 9c806461..00000000 --- a/test/helpers/fs.js +++ /dev/null @@ -1,38 +0,0 @@ -const path = require('path') -const promisify = require('util.promisify') - -const { - unlink: _unlink, - readFile: _readFile, - writeFile: _writeFile -} = require('fs') - -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, data) { - const file = path.join(__dirname, '../fixtures', name) - - return fs.writeFile(file, data) -} - -module.exports.copyFile = function copyFile (src, dest) { - return readFile(src) - .then((data) => writeFile(dest, data)) -} - -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 d3296840..8c8ae36d 100644 --- a/test/loader.test.js +++ b/test/loader.test.js @@ -1,13 +1,10 @@ -'use strict' - -const webpack = require('./helpers/compiler') -const { loader } = require('./helpers/compilation') -const { copyFile, deleteFile } = require('./helpers/fs') +const { webpack } = require('@webpack-utilities/test') describe('Loader', () => { test('Default', () => { const config = { loader: { + test: /\.css$/, options: { plugins: [] } @@ -15,80 +12,10 @@ describe('Loader', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src - - expect(src).toEqual('module.exports = "a { color: black }\\n"') - expect(src).toMatchSnapshot() - }) - }) - - describe('Watching', () => { - describe('Dependencies', () => { - const files = { - css: 'watch/index.css', - error: 'watch/error.css', - changed: 'watch/import.css' - } - - beforeEach(() => copyFile(files.css, files.changed)) - - afterEach(() => deleteFile(files.changed)) - - 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.error, files.changed) - }, - (stats) => { - const { err, src } = loader(stats) - - expect(src).toMatchSnapshot() - expect(err.length).toEqual(1) - - return copyFile(files.css, files.changed) - }, - (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() - } - ] - - let step = 0 - - const options = { - watch (err, stats, close) { - if (err) { - throw err - } - - steps[step](stats, close) - - step++ - } - } + const { source } = stats.toJson().modules[1] - return webpack('watch/index.js', config, options) - }) + expect(source).toEqual('module.exports = "a { color: black }\\n"') + expect(source).toMatchSnapshot() }) }) }) diff --git a/test/options/config.test.js b/test/options/config.test.js index 9bb52a31..d9025a99 100644 --- a/test/options/config.test.js +++ b/test/options/config.test.js @@ -1,25 +1,28 @@ -'use strict' - -const webpack = require('../helpers/compiler') -const { loader } = require('../helpers/compilation') +const { webpack } = require('@webpack-utilities/test') describe('Options', () => { test('Config - {Object}', () => { const config = { - loader: {} + loader: { + test: /\.css$/ + } } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] + + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"' + ) - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"') - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() }) }) test('Config - Path - {String}', () => { const config = { loader: { + test: /\.css$/, options: { config: { path: 'test/fixtures/config/postcss.config.js' } } @@ -27,16 +30,17 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a { color: black }\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual('module.exports = "a { color: black }\\n"') + expect(source).toMatchSnapshot() }) }) test('Config - Context - {Object}', () => { const config = { loader: { + test: /\.css$/, options: { config: { path: 'test/fixtures/config/postcss.config.js', @@ -47,16 +51,20 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"' + ) + + expect(source).toMatchSnapshot() }) }) test('Config - Context - {Object} - with ident', () => { const config = { loader: { + test: /\.css$/, options: { ident: 'postcss', config: { @@ -68,16 +76,20 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] + + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"' + ) - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"') - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() }) }) - test('Pass loader object to config context', () => { + test('Config – Context – Loader {Object}', () => { const config = { loader: { + test: /\.css$/, options: { config: { path: 'test/fixtures/config/context/postcss.config.js' @@ -87,11 +99,12 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const assets = stats.compilation.assets - const expectedAssetName = 'asset.txt' + const { assets } = stats.compilation + + const asset = 'asset.txt' - expect(expectedAssetName in assets).toBeTruthy() - expect(assets[expectedAssetName].source()).toBe('123') + expect(asset in assets).toBeTruthy() + expect(assets[asset].source()).toBe('123') }) }) }) diff --git a/test/options/exec.test.js b/test/options/exec.test.js index ac61490e..45716078 100644 --- a/test/options/exec.test.js +++ b/test/options/exec.test.js @@ -1,7 +1,4 @@ -'use strict' - -const webpack = require('../helpers/compiler') -const { loader } = require('../helpers/compilation') +const { webpack } = require('@webpack-utilities/test') describe('Options', () => { test('Exec - {Boolean}', () => { @@ -15,10 +12,13 @@ describe('Options', () => { } return webpack('jss/exec/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] + + expect(source).toEqual( + 'module.exports = "a {\\n color: green\\n}"' + ) - expect(src).toEqual('module.exports = "a {\\n color: green\\n}"') - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() }) }) @@ -32,9 +32,9 @@ describe('Options', () => { } return webpack('jss/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() }) }) }) diff --git a/test/options/parser.test.js b/test/options/parser.test.js index 58e3ecf4..2480744a 100644 --- a/test/options/parser.test.js +++ b/test/options/parser.test.js @@ -1,12 +1,10 @@ -'use strict' - -const webpack = require('../helpers/compiler') -const { loader } = require('../helpers/compilation') +const { webpack } = require('@webpack-utilities/test') describe('Options', () => { test('Parser - {String}', () => { const config = { loader: { + test: /\.sss$/, options: { parser: 'sugarss' } @@ -14,16 +12,17 @@ describe('Options', () => { } return webpack('sss/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a {\\n color: black\\n}\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual('module.exports = "a {\\n color: black\\n}\\n"') + expect(source).toMatchSnapshot() }) }) test('Parser - {Object}', () => { const config = { loader: { + test: /\.sss$/, options: { ident: 'postcss', parser: require('sugarss') @@ -32,10 +31,10 @@ describe('Options', () => { } return webpack('sss/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a {\\n color: black\\n}\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual('module.exports = "a {\\n color: black\\n}\\n"') + expect(source).toMatchSnapshot() }) }) }) diff --git a/test/options/plugins.test.js b/test/options/plugins.test.js index bc98ad3c..0f700b68 100644 --- a/test/options/plugins.test.js +++ b/test/options/plugins.test.js @@ -1,12 +1,10 @@ -'use strict' - -const webpack = require('../helpers/compiler') -const { loader } = require('../helpers/compilation') +const { webpack } = require('@webpack-utilities/test') describe('Options', () => { test('Plugins - {Array}', () => { const config = { loader: { + test: /\.css$/, options: { ident: 'postcss', plugins: [ require('../fixtures/config/plugin')() ] @@ -15,16 +13,20 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] + + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"' + ) - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"') - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() }) }) test('Plugins - {Object}', () => { const config = { loader: { + test: /\.css$/, options: { ident: 'postcss', plugins: require('../fixtures/config/plugin') @@ -33,16 +35,20 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] + + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"' + ) - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"') - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() }) }) test('Plugins - {Function} - {Array}', () => { const config = { loader: { + test: /\.css$/, options: { ident: 'postcss', plugins: () => [ require('../fixtures/config/plugin')() ] @@ -51,16 +57,20 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"' + ) + + expect(source).toMatchSnapshot() }) }) test('Plugins - {Function} - {Object}', () => { const config = { loader: { + test: /\.css$/, options: { ident: 'postcss', plugins: () => require('../fixtures/config/plugin')() @@ -69,10 +79,13 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] + + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"' + ) - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"') - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() }) }) }) diff --git a/test/options/sourceMap.test.js b/test/options/sourceMap.test.js index 3669127a..b321c77f 100644 --- a/test/options/sourceMap.test.js +++ b/test/options/sourceMap.test.js @@ -1,13 +1,12 @@ -'use strict' - const path = require('path') -const webpack = require('../helpers/compiler') -const { loader } = require('../helpers/compilation') +const { webpack } = require('@webpack-utilities/test') describe('Options', () => { test('Sourcemap - {Boolean}', () => { const config = { + devtool: 'sourcemap', loader: { + test: /\.css$/, options: { sourceMap: true } @@ -15,15 +14,20 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] + + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"' + ) - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n"') - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() - const map = loader(stats).map + const map = stats.compilation.modules[1]._source._sourceMap - map.file = path.relative(__dirname, map.file) - map.sources = map.sources.map((src) => path.relative(__dirname, src)) + map.file = path.posix.relative(__dirname, map.file) + map.sources = map.sources.map( + (src) => path.posix.relative(__dirname, src) + ) expect(map).toMatchSnapshot() }) @@ -32,6 +36,7 @@ describe('Options', () => { test('Sourcemap - {String}', () => { const config = { loader: { + test: /\.css$/, options: { sourceMap: 'inline' } @@ -39,10 +44,13 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] + + expect(source).toEqual( + 'module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZml4dHVyZXMvY3NzL3N0eWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxJQUFJLDJCQUFZLEVBQUUiLCJmaWxlIjoidGVzdC9maXh0dXJlcy9jc3Mvc3R5bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiYSB7IGNvbG9yOiBibGFjayB9XG4iXX0= */"' + ) - expect(src).toEqual('module.exports = "a { color: rgba(255, 0, 0, 1.0) }\\n\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZml4dHVyZXMvY3NzL3N0eWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxJQUFJLDJCQUFZLEVBQUUiLCJmaWxlIjoidGVzdC9maXh0dXJlcy9jc3Mvc3R5bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiYSB7IGNvbG9yOiBibGFjayB9XG4iXX0= */"') - expect(src).toMatchSnapshot() + expect(source).toMatchSnapshot() }) }) }) diff --git a/test/options/stringifier.test.js b/test/options/stringifier.test.js index bf94b46a..e8c37288 100644 --- a/test/options/stringifier.test.js +++ b/test/options/stringifier.test.js @@ -1,12 +1,10 @@ -'use strict' - -const webpack = require('../helpers/compiler') -const { loader } = require('../helpers/compilation') +const { webpack } = require('@webpack-utilities/test') describe('Options', () => { test('Stringifier - {String}', () => { const config = { loader: { + test: /\.css$/, options: { stringifier: 'sugarss' } @@ -14,16 +12,17 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a color: black\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual('module.exports = "a color: black\\n"') + expect(source).toMatchSnapshot() }) }) test('Stringifier - {Object}', () => { const config = { loader: { + test: /\.css$/, options: { ident: 'postcss', stringifier: require('sugarss') @@ -32,10 +31,10 @@ describe('Options', () => { } return webpack('css/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a color: black\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual('module.exports = "a color: black\\n"') + expect(source).toMatchSnapshot() }) }) }) diff --git a/test/options/syntax.test.js b/test/options/syntax.test.js index 27d152cc..45617909 100644 --- a/test/options/syntax.test.js +++ b/test/options/syntax.test.js @@ -1,12 +1,10 @@ -'use strict' - -const webpack = require('../helpers/compiler') -const { loader } = require('../helpers/compilation') +const { webpack } = require('@webpack-utilities/test') describe('Options', () => { test('Syntax - {String}', () => { const config = { loader: { + test: /\.sss$/, options: { syntax: 'sugarss' } @@ -14,16 +12,17 @@ describe('Options', () => { } return webpack('sss/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a\\n color: black\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual('module.exports = "a\\n color: black\\n"') + expect(source).toMatchSnapshot() }) }) test('Syntax - {Object}', () => { const config = { loader: { + test: /\.sss$/, options: { ident: 'postcss', syntax: require('sugarss') @@ -32,10 +31,10 @@ describe('Options', () => { } return webpack('sss/index.js', config).then((stats) => { - const src = loader(stats).src + const { source } = stats.toJson().modules[1] - expect(src).toEqual('module.exports = "a\\n color: black\\n"') - expect(src).toMatchSnapshot() + expect(source).toEqual('module.exports = "a\\n color: black\\n"') + expect(source).toMatchSnapshot() }) }) }) From 48553e2e66bfad18d532a3d6d827be3a7166bb3a Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sat, 4 Aug 2018 12:35:45 +0200 Subject: [PATCH 03/17] fix(options): improved `ValidationError` messages --- src/options.json | 18 ++++++++++++++++++ test/__snapshots__/Errors.test.js.snap | 8 +++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/options.json b/src/options.json index e4546157..956cd39c 100644 --- a/src/options.json +++ b/src/options.json @@ -11,6 +11,12 @@ "type": "object" } }, + "errorMessage": { + "properties": { + "ctx": "should be {Object} (https://github.com/postcss/postcss-loader#context-ctx)", + "path": "should be {String} (https://github.com/postcss/postcss-loader#path)" + } + }, "additionalProperties": false }, "exec": { @@ -39,5 +45,17 @@ "type": [ "string", "boolean" ] } }, + "errorMessage": { + "properties": { + "exec": "should be {Boolean} (https://github.com/postcss/postcss-loader#exec)", + "ident": "should be {String} (https://github.com/postcss/postcss-loader#plugins)", + "config": "should be {Object} (https://github.com/postcss/postcss-loader#config)", + "parser": "should be {String|Object} (https://github.com/postcss/postcss-loader#parser)", + "syntax": "should be {String|Object} (https://github.com/postcss/postcss-loader#syntax)", + "stringifier": "should be {String|Object} (https://github.com/postcss/postcss-loader#stringifier)", + "plugins": "should be {Array|Object|Function} (https://github.com/postcss/postcss-loader#plugins)", + "sourceMap": "should be {String|Boolean} (https://github.com/postcss/postcss-loader#sourcemap)" + } + }, "additionalProperties": true } diff --git a/test/__snapshots__/Errors.test.js.snap b/test/__snapshots__/Errors.test.js.snap index 6db3e25c..dedd2684 100644 --- a/test/__snapshots__/Errors.test.js.snap +++ b/test/__snapshots__/Errors.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Errors Syntax Error 1`] = ` -"Syntax Error +"Syntax Error (1:3) Unexpected separator in property @@ -14,6 +14,8 @@ exports[`Errors Syntax Error 1`] = ` exports[`Errors Validation Error 1`] = ` "ValidationError: PostCSS Loader Invalid Options -options.sourceMap should be string,boolean -" +options.sourceMap should be {String|Boolean} (https://github.com/postcss/postcss-loader#sourcemap) + + at validateOptions (/Users/Cini/Github/webpack/loaders/postcss/node_modules/@webpack-utilities/schema/src/validateOptions.js:25:11) + at Object.loader (/Users/Cini/Github/webpack/loaders/postcss/src/index.js:44:3)" `; From c38356ae7a20a5e297f3a332b31b0ee7dda51c8c Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sat, 4 Aug 2018 14:19:11 +0200 Subject: [PATCH 04/17] test(Errors): remove stacktrace from snapshot --- test/Errors.test.js | 6 +++--- test/__snapshots__/Errors.test.js.snap | 9 +-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/test/Errors.test.js b/test/Errors.test.js index 718f8c9a..5379df1d 100644 --- a/test/Errors.test.js +++ b/test/Errors.test.js @@ -23,9 +23,9 @@ describe('Errors', () => { error() } catch (err) { const message = err.message - .split('\n') - .slice(1) - .join('\n') + .split('\n\n') + .slice(1, -1) + .join('\n\n') expect(message).toMatchSnapshot() } diff --git a/test/__snapshots__/Errors.test.js.snap b/test/__snapshots__/Errors.test.js.snap index dedd2684..126692fa 100644 --- a/test/__snapshots__/Errors.test.js.snap +++ b/test/__snapshots__/Errors.test.js.snap @@ -11,11 +11,4 @@ exports[`Errors Syntax Error 1`] = ` " `; -exports[`Errors Validation Error 1`] = ` -"ValidationError: PostCSS Loader Invalid Options - -options.sourceMap should be {String|Boolean} (https://github.com/postcss/postcss-loader#sourcemap) - - at validateOptions (/Users/Cini/Github/webpack/loaders/postcss/node_modules/@webpack-utilities/schema/src/validateOptions.js:25:11) - at Object.loader (/Users/Cini/Github/webpack/loaders/postcss/src/index.js:44:3)" -`; +exports[`Errors Validation Error 1`] = `"options.sourceMap should be {String|Boolean} (https://github.com/postcss/postcss-loader#sourcemap)"`; From b728e90a4c232406df5cebb4099547579dfaa18f Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sat, 4 Aug 2018 14:20:43 +0200 Subject: [PATCH 05/17] fix(index): emit `warnings` as an instance of `{Error}` --- src/Warning.js | 14 ++++++++++ src/index.js | 8 ++++-- test/Warnings.test.js | 33 ++++++++++++++++++++++++ test/__snapshots__/Warnings.test.js.snap | 7 +++++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/Warning.js create mode 100644 test/Warnings.test.js create mode 100644 test/__snapshots__/Warnings.test.js.snap diff --git a/src/Warning.js b/src/Warning.js new file mode 100644 index 00000000..97273e63 --- /dev/null +++ b/src/Warning.js @@ -0,0 +1,14 @@ +class Warning extends Error { + constructor (warning) { + super() + + const { line, column, text } = warning + + this.name = 'LoaderWarning' + this.message = `\n(${line}:${column}) ${text}\n` + + this.stack = false + } +} + +module.exports = Warning diff --git a/src/index.js b/src/index.js index 5dc545e2..caf2a17a 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,9 @@ const validateOptions = require('schema-utils') const postcss = require('postcss') const postcssrc = require('postcss-load-config') -const SyntaxError = require('./Error') +const Warning = require('./Warning.js') +const SyntaxError = require('./Error.js') +const parseOptions = require('./options.js') /** * PostCSS Loader @@ -143,7 +145,9 @@ module.exports = function loader (css, map, meta) { return postcss(plugins) .process(css, options) .then((result) => { - result.warnings().forEach((msg) => this.emitWarning(msg.toString())) + result.warnings().forEach((warning) => { + this.emitWarning(new Warning(warning)) + }) result.messages.forEach((msg) => { if (msg.type === 'dependency') this.addDependency(msg.file) diff --git a/test/Warnings.test.js b/test/Warnings.test.js new file mode 100644 index 00000000..7c5875b7 --- /dev/null +++ b/test/Warnings.test.js @@ -0,0 +1,33 @@ +const { webpack } = require('@webpack-utilities/test') + +const plugin = (options = {}) => (css, result) => { + css.walkDecls((node) => { + node.warn(result, '') + }) +} + +describe('Warnings', () => { + test('Plugins', () => { + const config = { + loader: { + test: /\.css$/, + options: { + plugins: [ + plugin() + ] + } + } + } + + return webpack('css/index.js', config).then((stats) => { + const warning = stats.compilation.warnings[0] + + const message = warning.message + .split('\n') + .slice(1) + .join('\n') + + expect(message).toMatchSnapshot() + }) + }) +}) diff --git a/test/__snapshots__/Warnings.test.js.snap b/test/__snapshots__/Warnings.test.js.snap new file mode 100644 index 00000000..d1d876e1 --- /dev/null +++ b/test/__snapshots__/Warnings.test.js.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Warnings Plugins 1`] = ` +" +(1:5) +" +`; From 44b697459ee964c5485ad965bdfb797dcbd823e2 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sat, 4 Aug 2018 14:56:08 +0200 Subject: [PATCH 06/17] fix(index): add ast version (`meta.ast`) --- src/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index caf2a17a..dce3db7e 100644 --- a/src/index.js +++ b/src/index.js @@ -163,7 +163,13 @@ module.exports = function loader (css, map, meta) { if (!meta) meta = {} - meta.ast = { 'type': 'postcss', root: result.root } + const ast = { + type: 'postcss', + version: processor.version, + root + } + + meta.ast = ast meta.messages = result.messages if (this.loaderIndex === 0) { From 83d42b41284c13d71a62434e06bc306745574472 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sat, 4 Aug 2018 17:40:48 +0200 Subject: [PATCH 07/17] refactor(src): update code base with latest ES2015+ features --- src/Error.js | 8 ++-- src/Warning.js | 2 +- src/index.js | 59 +++++++++++++++++--------- src/options.js | 32 ++++++-------- test/__snapshots__/Errors.test.js.snap | 2 +- 5 files changed, 59 insertions(+), 44 deletions(-) diff --git a/src/Error.js b/src/Error.js index 05ea46ea..1ecf9fac 100644 --- a/src/Error.js +++ b/src/Error.js @@ -1,13 +1,13 @@ -'use strict' - class SyntaxError extends Error { constructor (err) { super(err) - this.name = 'Syntax Error' + const { line, column, reason } = err + + this.name = 'SyntaxError' this.message = '' - this.message += `${this.name} \n\n(${err.line}:${err.column}) ${err.reason}` + this.message += `${this.name} \n\n(${line}:${column}) ${reason}` this.message += `\n\n${err.showSourceCode()}\n` this.stack = false diff --git a/src/Warning.js b/src/Warning.js index 97273e63..31e97df8 100644 --- a/src/Warning.js +++ b/src/Warning.js @@ -2,7 +2,7 @@ class Warning extends Error { constructor (warning) { super() - const { line, column, text } = warning + const { text, line, column } = warning this.name = 'LoaderWarning' this.message = `\n(${line}:${column}) ${text}\n` diff --git a/src/index.js b/src/index.js index dce3db7e..e100eb54 100644 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,6 @@ -'use strict' - const path = require('path') -const loaderUtils = require('loader-utils') - -const parseOptions = require('./options') +const { getOptions } = require('loader-utils') const validateOptions = require('schema-utils') const postcss = require('postcss') @@ -42,7 +38,7 @@ const parseOptions = require('./options.js') * @return {cb} cb Result */ module.exports = function loader (css, map, meta) { - const options = Object.assign({}, loaderUtils.getOptions(this)) + const options = Object.assign({}, getOptions(this)) validateOptions(require('./options.json'), options, 'PostCSS Loader') @@ -96,16 +92,25 @@ module.exports = function loader (css, map, meta) { return postcssrc(rc.ctx, rc.path) }).then((config) => { - if (!config) config = {} + if (!config) { + config = {} + } - if (config.file) this.addDependency(config.file) + if (config.file) { + this.addDependency(config.file) + } // Disable override `to` option from `postcss.config.js` - if (config.options.to) delete config.options.to + if (config.options.to) { + delete config.options.to + } // Disable override `from` option from `postcss.config.js` - if (config.options.from) delete config.options.from + if (config.options.from) { + delete config.options.from + } let plugins = config.plugins || [] + let options = Object.assign({ from: file, map: sourceMap @@ -139,29 +144,39 @@ module.exports = function loader (css, map, meta) { css = this.exec(css, this.resource) } - if (sourceMap && typeof map === 'string') map = JSON.parse(map) - if (sourceMap && map) options.map.prev = map + if (sourceMap && typeof map === 'string') { + map = JSON.parse(map) + } + + if (sourceMap && map) { + options.map.prev = map + } return postcss(plugins) .process(css, options) .then((result) => { + let { css, map, root, processor, messages } = result + result.warnings().forEach((warning) => { this.emitWarning(new Warning(warning)) }) - result.messages.forEach((msg) => { - if (msg.type === 'dependency') this.addDependency(msg.file) + messages.forEach((msg) => { + if (msg.type === 'dependency') { + this.addDependency(msg.file) + } }) - css = result.css - map = result.map ? result.map.toJSON() : null + map = map ? map.toJSON() : null if (map) { map.file = path.resolve(map.file) map.sources = map.sources.map((src) => path.resolve(src)) } - if (!meta) meta = {} + if (!meta) { + meta = {} + } const ast = { type: 'postcss', @@ -170,7 +185,7 @@ module.exports = function loader (css, map, meta) { } meta.ast = ast - meta.messages = result.messages + meta.messages = messages if (this.loaderIndex === 0) { /** @@ -199,8 +214,12 @@ module.exports = function loader (css, map, meta) { return null }) }).catch((err) => { - if (err.file) this.addDependency(err.file) + if (err.file) { + this.addDependency(err.file) + } - return err.name === 'CssSyntaxError' ? cb(new SyntaxError(err)) : cb(err) + return err.name === 'CssSyntaxError' + ? cb(new SyntaxError(err)) + : cb(err) }) } diff --git a/src/options.js b/src/options.js index 980e9366..dc0b21bf 100644 --- a/src/options.js +++ b/src/options.js @@ -1,25 +1,21 @@ -'use strict' - -module.exports = function parseOptions (params) { - if (typeof params.plugins === 'function') { - params.plugins = params.plugins.call(this, this) +function parseOptions ({ exec, parser, syntax, stringifier, plugins }) { + if (typeof plugins === 'function') { + plugins = plugins.call(this, this) } - let plugins - - if (typeof params.plugins === 'undefined') plugins = [] - else if (Array.isArray(params.plugins)) plugins = params.plugins - else plugins = [ params.plugins ] + if (typeof plugins === 'undefined') { + plugins = [] + } else if (!Array.isArray(plugins)) { + plugins = [ plugins ] + } const options = {} - if (typeof params !== 'undefined') { - options.parser = params.parser - options.syntax = params.syntax - options.stringifier = params.stringifier - } - - const exec = params && params.exec + options.parser = parser + options.syntax = syntax + options.stringifier = stringifier - return Promise.resolve({ options: options, plugins: plugins, exec: exec }) + return Promise.resolve({ options, plugins, exec }) } + +module.exports = parseOptions diff --git a/test/__snapshots__/Errors.test.js.snap b/test/__snapshots__/Errors.test.js.snap index 126692fa..117cc8c7 100644 --- a/test/__snapshots__/Errors.test.js.snap +++ b/test/__snapshots__/Errors.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Errors Syntax Error 1`] = ` -"Syntax Error +"SyntaxError (1:3) Unexpected separator in property From f9bfaef5d346ea4d829ba6698446709c55e9bed4 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sun, 5 Aug 2018 04:25:20 +0200 Subject: [PATCH 08/17] chore(PULL_REQUEST_TEMPLATE): improve format and content --- .github/PULL_REQUEST_TEMPLATE.md | 59 +++++++++++++++++++------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f8fd00e1..db913f82 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,50 +1,63 @@ -> ℹ️ Describe the big picture of your changes here to communicate to the maintainers -why we should accept this pull request. If it fixes a bug or resolves a feature -request, be sure to link to that issue. +### Notable Changes -### `Type` ---- + -> ℹ️ What types of changes does your code introduce? +#### `Commit Message Summary (CHANGELOG)` -> _Put an `x` in the boxes that apply_ + + + +```bash +# Commit Message Body +# +# Example +BREAKING CHANGE: requires `node >= v8.0.0` +BREAKING CHANGE: `options.x` requires to be a `{Function}` now +``` + +### Type + +> ℹ️ What type of changes does your code introduce? + + + +- [ ] CI - [ ] Fix - [ ] Perf - [ ] Docs - [ ] Test +- [ ] Style +- [ ] Build - [ ] Chore - [ ] Feature - [ ] Refactor -### `SemVer` ---- +### Issues -> ℹ️ What changes to the current `semver` range does your PR introduce? +> ℹ️ What issue(s) (if any) are closed by your PR? -> _Put an `x` in the boxes that apply_ + -- [ ] Bug (:label: Patch) -- [ ] Feature (:label: Minor) -- [ ] Breaking Change (:label: Major) +- Fixes `#1` -### `Issues` ---- +### SemVer -> ℹ️ What issue (if any) are closed by your PR? +> ℹ️ What changes to the current `semver` range does your PR introduce? -> _Replace `#1` with the error number that applies_ + -- Fixes `#1` +- [ ] Fix (:label: Patch) +- [ ] Feature (:label: Minor) +- [ ] Breaking Change (:label: Major) -### `Checklist` ---- +### Checklist > ℹ️ You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. This is a reminder of what we are going to look for before merging your code. -> _Put an `x` in the boxes that apply._ + - [ ] Lint and unit tests pass with my changes -- [ ] I have added tests that prove my fix is effective/works +- [ ] I have added tests that prove my fix is effective/works (if needed) - [ ] I have added necessary documentation (if appropriate) - [ ] Any dependent changes are merged and published in downstream modules From ed054aa45d17ee910298ec4ddb7c443049cdc466 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sun, 5 Aug 2018 05:31:38 +0200 Subject: [PATCH 09/17] chore(ISSUE_TEMPLATE/BUG): move bug reports into their own template --- .github/ISSUE_TEMPLATE.md | 39 ----------------------------------- .github/ISSUE_TEMPLATE/BUG.md | 34 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 39 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/BUG.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 8e3ceb2d..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,39 +0,0 @@ -Briefly describe the issue you are experiencing (or the feature you want to see -added to the plugin). Tell us what you were trying to do and what happened -instead. Remember, this is _not_ a place to ask questions. For that, go to -http://gitter.im/postcss/postcss - -### `Details` ---- - -Describe in more detail the problem you have been experiencing, if necessary. - -### `Error (Logs|Stacks)` ---- - -Create a [gist](https://gist.github.com) which is a paste of your **full** -logs, and link them here. - -Do **not** paste your full logs here (or at least hide them by using a `
` block), as it will make this issue long and hard -to read! If you are reporting a bug, **always** include logs! - -### `Reproduction [Code]` ---- - -Please remember that, with sample code; it's easier to reproduce bug and much -faster to fix it. - -Please refer to a simple code example. - -```bash -$ git clone https://github.com// -``` - -### `Environment` ---- - -Please provide information about your environment. - -|OS|node|npm|PostCSS| -|:-:|:--:|:-:|:------:| -|[name][version]|[version]|[version]|[version]| diff --git a/.github/ISSUE_TEMPLATE/BUG.md b/.github/ISSUE_TEMPLATE/BUG.md new file mode 100644 index 00000000..76e39d50 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG.md @@ -0,0 +1,34 @@ +--- +name: 🐛 Bug +about: Report a Bug +--- + + + +### Details + + + +### Error (Logs|Stacks) + + + + + +### Reproduction (Code) + + + + + +```bash +$ git clone https://github.com// +``` + +### Environment + + + +|OS|node|npm/yarn|package| +|:-:|:--:|:-:|:------:| +|[name][version]|[version]|[version]|[version]| From 14695b1adedab38cb64adb9237cc96961290d478 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sun, 5 Aug 2018 05:42:07 +0200 Subject: [PATCH 10/17] chore(ISSUE_TEMPLATE/FEATURE): add feature request template --- .github/ISSUE_TEMPLATE/FEATURE.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/FEATURE.md diff --git a/.github/ISSUE_TEMPLATE/FEATURE.md b/.github/ISSUE_TEMPLATE/FEATURE.md new file mode 100644 index 00000000..a4e981ef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE.md @@ -0,0 +1,22 @@ +--- +name: 🌟 Feature +about: Request a feature +--- + +### Proposal + + + +### Use Case + + + +### Implementation + + + +- [ ] I'm open to work on this + - [ ] I need help/mentorship +- [ ] I'm unable to work on this + + From 72b3f5ae715f7f8fbe6de74e0a33ec484a4fa165 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Sun, 5 Aug 2018 05:45:48 +0200 Subject: [PATCH 11/17] chore(ISSUE_TEMPLATE/DOCS): add template for documentation issues --- .github/ISSUE_TEMPLATE/DOCS.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/DOCS.md diff --git a/.github/ISSUE_TEMPLATE/DOCS.md b/.github/ISSUE_TEMPLATE/DOCS.md new file mode 100644 index 00000000..079242ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/DOCS.md @@ -0,0 +1,30 @@ +--- +name: 📖 Docs +about: Report documentation related issues +--- + +### Type + + + +- [ ] Other +- [ ] Wrong +- [ ] Unclear +- [ ] Missing + +### Details + + + +### Location + + + +- [ ] README +- [ ] LICENSE +- [ ] CHANGELOG +- [ ] ISSUE_TEMPLATE + - [ ] BUG + - [ ] DOCS + - [ ] FEATURE +- [ ] PULL_REQUEST_TEMPLATE From d35c1ad5be167a7c1fee44fa75ec1f566c1c4357 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Wed, 8 Aug 2018 16:38:39 +0200 Subject: [PATCH 12/17] chore(package): update `schema-utils` v0.4.5...1.0.0 (`dependencies`) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4388e118..104dc793 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "loader-utils": "^1.1.0", "postcss": "^7.0.0", "postcss-load-config": "^2.0.0", - "schema-utils": "^0.4.0" + "schema-utils": "^1.0.0" }, "devDependencies": { "@webpack-utilities/test": "^1.0.0-alpha.0", From e99b7a14d3b20a31d8a203612c40be365ea33e41 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Wed, 8 Aug 2018 17:15:32 +0200 Subject: [PATCH 13/17] docs(LOADER): update JSDoc --- LOADER.md | 46 ----------------- docs/LOADER.md | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- src/Error.js | 10 ++++ src/Warning.js | 10 ++++ src/index.js | 55 ++++++++++++--------- src/options.js | 15 ++++++ 7 files changed, 197 insertions(+), 71 deletions(-) delete mode 100644 LOADER.md create mode 100644 docs/LOADER.md diff --git a/LOADER.md b/LOADER.md deleted file mode 100644 index 8f64d78f..00000000 --- a/LOADER.md +++ /dev/null @@ -1,46 +0,0 @@ - - -## loader(css, map) ⇒ cb -PostCSS Loader - -> Loads && processes CSS with [PostCSS](https://github.com/postcss/postcss) - -**Kind**: global function -**Returns**: cb - cb Result -**Requires**: module:path, module:loader-utils, module:schema-utils, module:postcss, module:postcss-load-config, module:Error -**Version**: 2.0.0 -**Author**: Andrey Sitnik (@ai) -**License**: MIT - -| Param | Type | Description | -| --- | --- | --- | -| css | String | Source | -| map | Object | Source Map | - - -* [loader(css, map)](#loader) ⇒ cb - * [.cb](#loader.cb) : function - * [.cb](#loader.cb) : function - - - -### loader.cb : function -**Kind**: static typedef of [loader](#loader) - -| Param | Type | Description | -| --- | --- | --- | -| null | Object | Error | -| result | String | Result (JS Module) | -| map | Object | Source Map | - - - -### loader.cb : function -**Kind**: static typedef of [loader](#loader) - -| Param | Type | Description | -| --- | --- | --- | -| null | Object | Error | -| css | String | Result (Raw Module) | -| map | Object | Source Map | - diff --git a/docs/LOADER.md b/docs/LOADER.md new file mode 100644 index 00000000..deb2d04d --- /dev/null +++ b/docs/LOADER.md @@ -0,0 +1,130 @@ +## Modules + +
+
postcss-loader
+
+
+ +## Classes + +
+
SyntaxErrorError
+
+
WarningError
+
+
+ +## Functions + +
+
loader(css, map)cb
+

PostCSS Loader

+

Loads && processes CSS with PostCSS

+
+
parseOptions(exec, parser, syntax, stringifier, plugins)Promise
+

PostCSS Options Parser

+

Transforms the loader options into a valid postcss config {Object}

+
+
+ + + +## postcss-loader +**Requires**: module:path, module:loader-utils, module:schema-utils, module:postcss, module:postcss-load-config, module:./options.js, module:./Warning.js, module:./SyntaxError.js +**Version**: 3.0.0 +**Author**: Andrey Sitnik (@ai) +**License**: MIT + + +## SyntaxError ⇐ Error +**Kind**: global class +**Extends**: Error + + +### new SyntaxError(err) +**PostCSS Syntax Error** + +Loader wrapper for postcss syntax errors + + +| Param | Type | Description | +| --- | --- | --- | +| err | Object | CssSyntaxError | + + + +## Warning ⇐ Error +**Kind**: global class +**Extends**: Error + + +### new Warning(warning) +**PostCSS Plugin Warning** + +Loader wrapper for postcss plugin warnings (`root.messages`) + + +| Param | Type | Description | +| --- | --- | --- | +| warning | Object | PostCSS Warning | + + + +## loader(css, map) ⇒ cb +**PostCSS Loader** + +Loads && processes CSS with [PostCSS](https://github.com/postcss/postcss) + +**Kind**: global function +**Returns**: cb - cb Result + +| Param | Type | Description | +| --- | --- | --- | +| css | String | Source | +| map | Object | Source Map | + + +* [loader(css, map)](#loader) ⇒ cb + * [.cb](#loader.cb) : function + * [.cb](#loader.cb) : function + + + +### loader.cb : function +**Kind**: static typedef of [loader](#loader) + +| Param | Type | Description | +| --- | --- | --- | +| null | Object | Error | +| css | String | Result (JS Module) | +| map | Object | Source Map | + + + +### loader.cb : function +**Kind**: static typedef of [loader](#loader) + +| Param | Type | Description | +| --- | --- | --- | +| null | Object | Error | +| css | String | Result (Raw Module) | +| map | Object | Source Map | + + + +## parseOptions(exec, parser, syntax, stringifier, plugins) ⇒ Promise +**PostCSS Options Parser** + +Transforms the loader options into a valid postcss config `{Object}` + +**Kind**: global function +**Returns**: Promise - PostCSS Config + +| Param | Type | Description | +| --- | --- | --- | +| exec | Boolean | Execute CSS-in-JS | +| parser | String \| Object | PostCSS Parser | +| syntax | String \| Object | PostCSS Syntax | +| stringifier | String \| Object | PostCSS Stringifier | +| plugins | Array \| Object \| function | PostCSS Plugins | + diff --git a/package.json b/package.json index 104dc793..0ebf1bbb 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "scripts": { "lint": "standard --env jest", "test": "jest --env node --verbose --coverage", - "docs": "jsdoc2md src/*.js > LOADER.md", + "docs": "jsdoc2md src/*.js > docs/LOADER.md", "clean": "rm -rf coverage test/outputs", "release": "standard-version" }, diff --git a/src/Error.js b/src/Error.js index 1ecf9fac..8c6d6a2b 100644 --- a/src/Error.js +++ b/src/Error.js @@ -1,3 +1,13 @@ +/** + * **PostCSS Syntax Error** + * + * Loader wrapper for postcss syntax errors + * + * @class SyntaxError + * @extends Error + * + * @param {Object} err CssSyntaxError + */ class SyntaxError extends Error { constructor (err) { super(err) diff --git a/src/Warning.js b/src/Warning.js index 31e97df8..6d032720 100644 --- a/src/Warning.js +++ b/src/Warning.js @@ -1,3 +1,13 @@ +/** + * **PostCSS Plugin Warning** + * + * Loader wrapper for postcss plugin warnings (`root.messages`) + * + * @class Warning + * @extends Error + * + * @param {Object} warning PostCSS Warning + */ class Warning extends Error { constructor (warning) { super() diff --git a/src/index.js b/src/index.js index e100eb54..bb576c32 100644 --- a/src/index.js +++ b/src/index.js @@ -11,33 +11,18 @@ const SyntaxError = require('./Error.js') const parseOptions = require('./options.js') /** - * PostCSS Loader + * **PostCSS Loader** * - * > Loads && processes CSS with [PostCSS](https://github.com/postcss/postcss) - * - * @author Andrey Sitnik (@ai) - * - * @license MIT - * @version 2.0.0 - * - * @requires path - * - * @requires loader-utils - * @requires schema-utils - * - * @requires postcss - * @requires postcss-load-config - * - * @requires Error + * Loads && processes CSS with [PostCSS](https://github.com/postcss/postcss) * * @method loader * - * @param {String} css Source - * @param {Object} map Source Map + * @param {String} css Source + * @param {Object} map Source Map * - * @return {cb} cb Result + * @return {cb} cb Result */ -module.exports = function loader (css, map, meta) { +function loader (css, map, meta) { const options = Object.assign({}, getOptions(this)) validateOptions(require('./options.json'), options, 'PostCSS Loader') @@ -192,9 +177,9 @@ module.exports = function loader (css, map, meta) { * @memberof loader * @callback cb * - * @param {Object} null Error - * @param {String} result Result (JS Module) - * @param {Object} map Source Map + * @param {Object} null Error + * @param {String} css Result (JS Module) + * @param {Object} map Source Map */ cb(null, `module.exports = ${JSON.stringify(css)}`, map) @@ -223,3 +208,25 @@ module.exports = function loader (css, map, meta) { : cb(err) }) } + +/** + * @author Andrey Sitnik (@ai) + * + * @license MIT + * @version 3.0.0 + * + * @module postcss-loader + * + * @requires path + * + * @requires loader-utils + * @requires schema-utils + * + * @requires postcss + * @requires postcss-load-config + * + * @requires ./options.js + * @requires ./Warning.js + * @requires ./SyntaxError.js + */ +module.exports = loader diff --git a/src/options.js b/src/options.js index dc0b21bf..fbe71369 100644 --- a/src/options.js +++ b/src/options.js @@ -1,3 +1,18 @@ +/** + * **PostCSS Options Parser** + * + * Transforms the loader options into a valid postcss config `{Object}` + * + * @method parseOptions + * + * @param {Boolean} exec Execute CSS-in-JS + * @param {String|Object} parser PostCSS Parser + * @param {String|Object} syntax PostCSS Syntax + * @param {String|Object} stringifier PostCSS Stringifier + * @param {Array|Object|Function} plugins PostCSS Plugins + * + * @return {Promise} PostCSS Config + */ function parseOptions ({ exec, parser, syntax, stringifier, plugins }) { if (typeof plugins === 'function') { plugins = plugins.call(this, this) From cf26b11166664ed57298832d637c7b4b36ea1298 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Wed, 8 Aug 2018 17:18:25 +0200 Subject: [PATCH 14/17] refactor(Warning): add `warning` property checks --- src/Warning.js | 13 ++++++++++--- test/__snapshots__/Warnings.test.js.snap | 6 +++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Warning.js b/src/Warning.js index 6d032720..2355f4f5 100644 --- a/src/Warning.js +++ b/src/Warning.js @@ -10,12 +10,19 @@ */ class Warning extends Error { constructor (warning) { - super() + super(warning) const { text, line, column } = warning - this.name = 'LoaderWarning' - this.message = `\n(${line}:${column}) ${text}\n` + this.name = 'Warning' + + this.message = `${this.name}\n\n` + + if (typeof line !== 'undefined') { + this.message += `(${line}:${column}) ` + } + + this.message += `${text}` this.stack = false } diff --git a/test/__snapshots__/Warnings.test.js.snap b/test/__snapshots__/Warnings.test.js.snap index d1d876e1..9524418a 100644 --- a/test/__snapshots__/Warnings.test.js.snap +++ b/test/__snapshots__/Warnings.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Warnings Plugins 1`] = ` -" -(1:5) -" +"Warning + +(1:5) " `; From 282d0ab6281744e045164d44bdfc0c2cc8031fa1 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Wed, 8 Aug 2018 17:19:50 +0200 Subject: [PATCH 15/17] refactor(options): remove `ident` from validation schema --- src/options.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/options.json b/src/options.json index 956cd39c..1141d84a 100644 --- a/src/options.json +++ b/src/options.json @@ -22,9 +22,6 @@ "exec": { "type": "boolean" }, - "ident": { - "type": "string" - }, "parser": { "type": [ "string", "object" ] }, @@ -48,7 +45,6 @@ "errorMessage": { "properties": { "exec": "should be {Boolean} (https://github.com/postcss/postcss-loader#exec)", - "ident": "should be {String} (https://github.com/postcss/postcss-loader#plugins)", "config": "should be {Object} (https://github.com/postcss/postcss-loader#config)", "parser": "should be {String|Object} (https://github.com/postcss/postcss-loader#parser)", "syntax": "should be {String|Object} (https://github.com/postcss/postcss-loader#syntax)", From 01da44eb23b324592756522f8776f4d672c23527 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Wed, 8 Aug 2018 19:00:22 +0200 Subject: [PATCH 16/17] refactor(Error): add `error` property checks --- src/Error.js | 22 ++++++++++++++++------ test/__snapshots__/Errors.test.js.snap | 2 +- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Error.js b/src/Error.js index 8c6d6a2b..db05aac3 100644 --- a/src/Error.js +++ b/src/Error.js @@ -9,16 +9,26 @@ * @param {Object} err CssSyntaxError */ class SyntaxError extends Error { - constructor (err) { - super(err) + constructor (error) { + super(error) - const { line, column, reason } = err + const { line, column, reason } = error this.name = 'SyntaxError' - this.message = '' - this.message += `${this.name} \n\n(${line}:${column}) ${reason}` - this.message += `\n\n${err.showSourceCode()}\n` + this.message = `${this.name}\n\n` + + if (typeof line !== 'undefined') { + this.message += `(${line}:${column}) ` + } + + this.message += `${reason}` + + const code = error.showSourceCode() + + if (code) { + this.message += `\n\n${code}\n` + } this.stack = false } diff --git a/test/__snapshots__/Errors.test.js.snap b/test/__snapshots__/Errors.test.js.snap index 117cc8c7..b3651a12 100644 --- a/test/__snapshots__/Errors.test.js.snap +++ b/test/__snapshots__/Errors.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Errors Syntax Error 1`] = ` -"SyntaxError +"SyntaxError (1:3) Unexpected separator in property From 1d496f64851ad69124bf44caa77aa3d41c98fbb0 Mon Sep 17 00:00:00 2001 From: Michael Ciniawsky Date: Wed, 8 Aug 2018 19:12:30 +0200 Subject: [PATCH 17/17] docs(README): update filename formatting --- README.md | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index f7546968..6b03ad79 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ npm i -D postcss-loader ### `Configuration` -**postcss.config.js** +**`postcss.config.js`** ```js module.exports = { parser: 'sugarss', @@ -72,7 +72,7 @@ Config lookup starts from `path.dirname(file)` and walks the file tree upwards u After setting up your `postcss.config.js`, add `postcss-loader` to your `webpack.config.js`. You can use it standalone or in conjunction with `css-loader` (recommended). Use it **after** `css-loader` and `style-loader`, but **before** other preprocessor loaders like e.g `sass|less|stylus-loader`, if you use any. -**webpack.config.js** +**`webpack.config.js`** ```js module.exports = { module: { @@ -88,7 +88,7 @@ module.exports = { > ⚠️ When `postcss-loader` is used standalone (without `css-loader`) don't use `@import` in your CSS, since this can lead to quite bloated bundles -**webpack.config.js (recommended)** +**`webpack.config.js` (recommended)** ```js module.exports = { module: { @@ -122,6 +122,7 @@ module.exports = { If you use JS styles without the [`postcss-js`][postcss-js] parser, add the `exec` option. +**`webpack.config.js`** ```js { test: /\.style.js$/, @@ -148,7 +149,7 @@ You can manually specify the path to search for your config (`postcss.config.js` > ⚠️ Note that you **can't** use a **filename** other than the [supported config formats] (e.g `.postcssrc.js`, `postcss.config.js`), this option only allows you to manually specify the **directory** where config lookup should **start** from -**webpack.config.js** +**`webpack.config.js`** ```js { loader: 'postcss-loader', @@ -173,7 +174,7 @@ You can manually specify the path to search for your config (`postcss.config.js` `postcss-loader` exposes context `ctx` to the config file, making your `postcss.config.js` dynamic, so can use it to do some real magic ✨ -**postcss.config.js** +**`postcss.config.js`** ```js module.exports = ({ file, options, env }) => ({ parser: file.extname === '.sss' ? 'sugarss' : false, @@ -185,7 +186,7 @@ module.exports = ({ file, options, env }) => ({ }) ``` -**webpack.config.js** +**`webpack.config.js`** ```js { loader: 'postcss-loader', @@ -202,7 +203,7 @@ module.exports = ({ file, options, env }) => ({ ### `Plugins` -**webpack.config.js** +**`webpack.config.js`** ```js { loader: 'postcss-loader', @@ -229,7 +230,7 @@ module.exports = ({ file, options, env }) => ({ #### `Parser` -**webpack.config.js** +**`webpack.config.js`** ```js { test: /\.sss$/, @@ -242,7 +243,7 @@ module.exports = ({ file, options, env }) => ({ #### `Syntax` -**webpack.config.js** +**`webpack.config.js`** ```js { test: /\.css$/, @@ -255,7 +256,7 @@ module.exports = ({ file, options, env }) => ({ #### `Stringifier` -**webpack.config.js** +**`webpack.config.js`** ```js { test: /\.css$/, @@ -270,7 +271,7 @@ module.exports = ({ file, options, env }) => ({ Enables source map support, `postcss-loader` will use the previous source map given by other loaders and update it accordingly, if no previous loader is applied before `postcss-loader`, the loader will generate a source map for you. -**webpack.config.js** +**`webpack.config.js`** ```js { test: /\.css/, @@ -288,7 +289,7 @@ Enables source map support, `postcss-loader` will use the previous source map gi You can set the `sourceMap: 'inline'` option to inline the source map within the CSS directly as an annotation comment. -**webpack.config.js** +**`webpack.config.js`** ```js { loader: 'postcss-loader', @@ -308,7 +309,7 @@ within the CSS directly as an annotation comment. ### `Stylelint` -**webpack.config.js** +**`webpack.config.js`** ```js { test: /\.css$/, @@ -330,9 +331,9 @@ within the CSS directly as an annotation comment. } ``` -### Autoprefixing +### `Autoprefixing` -**webpack.config.js** +**`webpack.config.js`** ```js { test: /\.css$/, @@ -361,7 +362,7 @@ This loader [cannot be used] with [CSS Modules] out of the box due to the way `css-loader` processes file imports. To make them work properly, either add the css-loader’s [`importLoaders`] option. -**webpack.config.js** +**`webpack.config.js`** ```js { test: /\.css$/, @@ -386,6 +387,7 @@ If you want to process styles written in JavaScript, use the [postcss-js] parser [postcss-js]: https://github.com/postcss/postcss-js +**`webpack.config.js`** ```js { test: /\.style.js$/, @@ -425,10 +427,11 @@ export default { [ExtractPlugin]: https://github.com/webpack-contrib/mini-css-extract-plugin -**webpack.config.js** +**`webpack.config.js`** ```js -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const devMode = process.env.NODE_ENV !== 'production'; +const devMode = process.env.NODE_ENV !== 'production' + +const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { module: { @@ -438,14 +441,14 @@ module.exports = { use: [ devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', - 'postcss-loader', + 'postcss-loader' ] } ] }, plugins: [ new MiniCssExtractPlugin({ - filename: devMode ? '[name].css' : '[name].[hash].css', + filename: devMode ? '[name].css' : '[name].[hash].css' }) ] }