diff --git a/docs/configuration.md b/docs/configuration.md index 72b2925..3fd911b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -208,7 +208,7 @@ Default configuration: { postcss: { // Default plugins - plugins: ['autoprefixer'], + plugins: ['autoprefixer', ['another-postcss-plugin',{ foo: 'bar'}]], // Stops the build if an error is found failOnError: true } diff --git a/package-lock.json b/package-lock.json index 66a38d8..9dce1a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@netcentric/fe-build", - "version": "5.1.2", + "version": "5.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@netcentric/fe-build", - "version": "5.1.2", + "version": "5.1.3", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.26.7", @@ -101,15 +101,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", @@ -150,15 +141,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.25.9", "license": "MIT", @@ -178,15 +160,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.26.3", "license": "MIT", @@ -202,15 +175,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.3", "license": "MIT", @@ -1263,15 +1227,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.25.9", "license": "MIT", @@ -1478,15 +1433,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "license": "MIT", @@ -2836,15 +2782,6 @@ "node": ">=8" } }, - "node_modules/babel-plugin-istanbul/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/babel-plugin-jest-hoist": { "version": "29.6.3", "license": "MIT", @@ -2870,15 +2807,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", @@ -5196,15 +5124,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/makeerror": { "version": "1.0.12", "license": "BSD-3-Clause", diff --git a/utils/getPlugins.js b/utils/getPlugins.js new file mode 100644 index 0000000..fb83499 --- /dev/null +++ b/utils/getPlugins.js @@ -0,0 +1,17 @@ +module.exports = function getPlugins(plugins = []) { + return plugins + .filter(Boolean) + .map(function (entry) { + if (Array.isArray(entry)) { + const [pluginName, pluginOptions] = entry; + const pluginModule = require(pluginName); + const pluginFn = pluginModule.default || pluginModule; + return pluginFn(pluginOptions); + } else if (typeof entry === 'string') { + const pluginModule = require(entry); + return pluginModule.default || pluginModule; + } else { + throw new Error(`Invalid plugin entry: ${JSON.stringify(entry)}`); + } + }); +}; \ No newline at end of file diff --git a/utils/getPlugins.test.js b/utils/getPlugins.test.js new file mode 100644 index 0000000..59bbc9f --- /dev/null +++ b/utils/getPlugins.test.js @@ -0,0 +1,52 @@ +process.argv.push('--quiet'); + +describe('Test getPlugins.js', () => { + beforeEach(() => { + jest.resetModules(); + }); + + it('Should load a plugin from string', () => { + jest.mock('postcss-fe-build-test-a', () => () => 'mocked-plugin-a', { virtual: true }); + + const getPlugins = require('./getPlugins'); + const plugins = ['postcss-fe-build-test-a']; + const result = getPlugins(plugins); + + expect(result).toHaveLength(1); + expect(result[0]()).toBe('mocked-plugin-a'); + }); + + it('Should load a plugin from [plugin, options] format', () => { + jest.mock('postcss-fe-build-test-b', () => ({ + default: (opts) => `mocked-plugin-b:${JSON.stringify(opts)}` + }), { virtual: true }); + + const getPlugins = require('./getPlugins'); + const plugins = [['postcss-fe-build-test-b', { extractAll: false }]]; + const result = getPlugins(plugins); + + expect(result).toHaveLength(1); + expect(result[0]).toBe('mocked-plugin-b:{"extractAll":false}'); + }); + + + it('Should ignore falsy values in plugin list', () => { + jest.mock('postcss-fe-build-test-c', () => () => 'mocked-plugin-a', { virtual: true }); + + const getPlugins = require('./getPlugins'); + const plugins = [null, undefined, false, 'postcss-fe-build-test-c']; + const result = getPlugins(plugins); + + expect(result).toHaveLength(1); + expect(result[0]()).toBe('mocked-plugin-a'); + }); + + it('Should throw on invalid plugin entry', () => { + const getPlugins = require('./getPlugins'); + + const invalidPlugins = [{ foo: 'bar' }, 123, true]; + invalidPlugins.forEach(plugin => { + expect(() => getPlugins([plugin])).toThrow('Invalid plugin entry'); + }); + }); +}); diff --git a/utils/renderPostcss.js b/utils/renderPostcss.js index 4ac449c..a1561db 100644 --- a/utils/renderPostcss.js +++ b/utils/renderPostcss.js @@ -1,16 +1,15 @@ const postcss = require('postcss'); const { log } = require('./log'); +const getPlugins = require('./getPlugins'); module.exports = function renderPostcss(input, outFile, config, cb) { const { plugins, failOnError } = config.postcss; try { // try to dynamic load of postcss plugins - /* eslint-disable */ - const runPlugins = plugins.map(plugin => require(plugin)); - const map = config.general.isProduction ? false : { inline: true, prev: input.sourceMap } ; + const runPlugins = getPlugins(plugins); + const map = config.general.isProduction ? false : { inline: true, prev: input.sourceMap }; - /* eslint-enable */ // run postcss plugins at sass output postcss(runPlugins).process(input.css.toString(), { from: outFile, map }) .then((result) => { @@ -29,7 +28,11 @@ module.exports = function renderPostcss(input, outFile, config, cb) { } // success and return - log(__filename, `Postcss applied ${plugins.join(',')} - `, input.destFile, 'success'); + log(__filename, + `PostCSS applied: ${plugins.map(ent => (Array.isArray(ent) ? ent[0] : ent)).join(', ')}`, + input.destFile, + 'success'); + return cb(result); }); } catch (error) {