diff --git a/src/index.js b/src/index.js index db5c40e..7ddf39e 100644 --- a/src/index.js +++ b/src/index.js @@ -66,6 +66,32 @@ const createContext = (ctx) => { return ctx } +// prefers require, checks for ERR_REQUIRE_ESM, which is still experimental, but often works when called synchronous +const requireOrImport = filepath => { + try { + return require(filepath) + } catch (error) { + // importing ECMAScript modules from CommonJS does not work, so load it using dynamic import(...) + if (error.code === 'ERR_REQUIRE_ESM') { + return import(filepath).then(mod => mod.default) + } + throw error + } +} + +// prefers import, which won't work in sync mode +const importOrRequire = async filepath => { + try { + return (await import(filepath)).default + } catch (error) { + // Node.js 10 does not support dynamic import(...) and throws 'Error: Not supported' + if (error.message === 'Not supported') { + return require(filepath) + } + throw error + } +} + const addTypeScriptLoader = (options = {}, loader) => { const moduleName = 'postcss' @@ -81,14 +107,19 @@ const addTypeScriptLoader = (options = {}, loader) => { `.${moduleName}rc.ts`, `.${moduleName}rc.js`, `.${moduleName}rc.cjs`, + `.${moduleName}rc.mjs`, `${moduleName}.config.ts`, `${moduleName}.config.js`, - `${moduleName}.config.cjs` + `${moduleName}.config.cjs`, + `${moduleName}.config.mjs` ], loaders: { ...options.loaders, '.yaml': (filepath, content) => yaml.parse(content), '.yml': (filepath, content) => yaml.parse(content), + '.js': requireOrImport, + '.cjs': requireOrImport, + '.mjs': requireOrImport, '.ts': loader } } diff --git a/test/js.test.js b/test/js.test.js index e5bb6b7..9fbef83 100644 --- a/test/js.test.js +++ b/test/js.test.js @@ -70,7 +70,7 @@ test('postcss.config.js - {Object} - Process SSS', () => { }) }) -describe('postcss.config.js - {Array} - Load Config', () => { +describe('postcss.config.js (CommonJS) - {Array} - Load Config', () => { const ctx = { parser: true, syntax: true @@ -88,27 +88,59 @@ describe('postcss.config.js - {Array} - Load Config', () => { expect(typeof config.plugins[1]).toBe('object') expect(config.file) - .toEqual(path.resolve('test/js/array', 'postcss.config.js')) + .toEqual(path.resolve('test/js/array/cjs-in-js', 'postcss.config.js')) } test('Async', () => { - return postcssrc(ctx, 'test/js/array').then(expected) + return postcssrc(ctx, 'test/js/array/cjs-in-js').then(expected) }) test('Sync', () => { - const config = postcssrc.sync(ctx, 'test/js/array') + const config = postcssrc.sync(ctx, 'test/js/array/cjs-in-js') expected(config) }) }) -test('postcss.config.js - {Array} - Process CSS', () => { +describe('postcss.config.cjs - {Array} - Load Config', () => { + const ctx = { + parser: true, + syntax: true + } + + const expected = (config) => { + expect(config.options.parser).toEqual(require('sugarss')) + expect(config.options.syntax).toEqual(require('sugarss')) + expect(config.options.map).toEqual(false) + expect(config.options.from).toEqual('./test/js/array/fixtures/index.css') + expect(config.options.to).toEqual('./test/js/array/expect/index.css') + + expect(config.plugins.length).toEqual(2) + expect(typeof config.plugins[0]).toBe('object') + expect(typeof config.plugins[1]).toBe('object') + + expect(config.file) + .toEqual(path.resolve('test/js/array/cjs', 'postcss.config.cjs')) + } + + test('Async', () => { + return postcssrc(ctx, 'test/js/array/cjs').then(expected) + }) + + test('Sync', () => { + const config = postcssrc.sync(ctx, 'test/js/array/cjs') + + expected(config) + }) +}) + +test('postcss.config.js (CommonJS) - {Array} - Process CSS', () => { const ctx = { parser: false, syntax: false } - return postcssrc(ctx, 'test/js/array').then((config) => { + return postcssrc(ctx, 'test/js/array/cjs').then((config) => { return postcss(config.plugins) .process(fixture('js/array', 'index.css'), config.options) .then((result) => { @@ -117,14 +149,14 @@ test('postcss.config.js - {Array} - Process CSS', () => { }) }) -test('postcss.config.js - {Array} - Process SSS', () => { +test('postcss.config.js (CommonJS) - {Array} - Process SSS', () => { const ctx = { from: './test/js/array/fixtures/index.sss', parser: true, syntax: false } - return postcssrc(ctx, 'test/js/array').then((config) => { + return postcssrc(ctx, 'test/js/array/cjs').then((config) => { return postcss(config.plugins) .process(fixture('js/array', 'index.sss'), config.options) .then((result) => { @@ -132,3 +164,35 @@ test('postcss.config.js - {Array} - Process SSS', () => { }) }) }) + +describe('postcss.config.mjs - {Array} - Load Config', () => { + const ctx = { + parser: true, + syntax: true + } + + const expected = (config) => { + expect(config.options.parser).toEqual(require('sugarss')) + expect(config.options.syntax).toEqual(require('sugarss')) + expect(config.options.map).toEqual(false) + expect(config.options.from).toEqual('./test/js/array/fixtures/index.css') + expect(config.options.to).toEqual('./test/js/array/expect/index.css') + + expect(config.plugins.length).toEqual(2) + expect(typeof config.plugins[0]).toBe('object') + expect(typeof config.plugins[1]).toBe('object') + + expect(config.file) + .toEqual(path.resolve('test/js/array/mjs', 'postcss.config.mjs')) + } + + test('Async', () => { + return postcssrc(ctx, 'test/js/array/mjs').then(expected) + }) + + xtest('Sync', () => { + const config = postcssrc.sync(ctx, 'test/js/array/mjs') + + expected(config) + }) +}) diff --git a/test/js/array/postcss.config.js b/test/js/array/cjs-in-js/postcss.config.js similarity index 100% rename from test/js/array/postcss.config.js rename to test/js/array/cjs-in-js/postcss.config.js diff --git a/test/js/array/cjs/postcss.config.cjs b/test/js/array/cjs/postcss.config.cjs new file mode 100644 index 0000000..dd76557 --- /dev/null +++ b/test/js/array/cjs/postcss.config.cjs @@ -0,0 +1,14 @@ +module.exports = function (ctx) { + return { + parser: ctx.parser ? 'sugarss' : false, + syntax: ctx.syntax ? 'sugarss' : false, + map: ctx.map ? 'inline' : false, + from: './test/js/array/fixtures/index.css', + to: './test/js/array/expect/index.css', + plugins: [ + require('postcss-import')(), + require('postcss-nested')(), + ctx.env === 'production' ? require('cssnano')() : false + ] + } +} diff --git a/test/js/array/esm-in-js/package.json b/test/js/array/esm-in-js/package.json new file mode 100644 index 0000000..6990891 --- /dev/null +++ b/test/js/array/esm-in-js/package.json @@ -0,0 +1 @@ +{"type": "module"} diff --git a/test/js/array/esm-in-js/postcss.config.js b/test/js/array/esm-in-js/postcss.config.js new file mode 100644 index 0000000..47194ce --- /dev/null +++ b/test/js/array/esm-in-js/postcss.config.js @@ -0,0 +1,18 @@ +import postcssImport from 'postcss-import' +import postcssNested from 'postcss-nested' +import cssnano from 'cssnano' + +export default function (ctx) { + return { + parser: ctx.parser ? 'sugarss' : false, + syntax: ctx.syntax ? 'sugarss' : false, + map: ctx.map ? 'inline' : false, + from: './test/js/array/fixtures/index.css', + to: './test/js/array/expect/index.css', + plugins: [ + postcssImport(), + postcssNested(), + ctx.env === 'production' ? cssnano() : false + ] + } +} diff --git a/test/js/array/mjs/postcss.config.mjs b/test/js/array/mjs/postcss.config.mjs new file mode 100644 index 0000000..47194ce --- /dev/null +++ b/test/js/array/mjs/postcss.config.mjs @@ -0,0 +1,18 @@ +import postcssImport from 'postcss-import' +import postcssNested from 'postcss-nested' +import cssnano from 'cssnano' + +export default function (ctx) { + return { + parser: ctx.parser ? 'sugarss' : false, + syntax: ctx.syntax ? 'sugarss' : false, + map: ctx.map ? 'inline' : false, + from: './test/js/array/fixtures/index.css', + to: './test/js/array/expect/index.css', + plugins: [ + postcssImport(), + postcssNested(), + ctx.env === 'production' ? cssnano() : false + ] + } +} diff --git a/test/js/object/postcss.config.mjs b/test/js/object/postcss.config.mjs new file mode 100644 index 0000000..18035ed --- /dev/null +++ b/test/js/object/postcss.config.mjs @@ -0,0 +1,14 @@ +export default function (ctx) { + return { + parser: ctx.parser ? 'sugarss' : false, + syntax: ctx.syntax ? 'sugarss' : false, + map: ctx.map ? 'inline' : false, + from: './test/js/object/fixtures/index.css', + to: './test/js/object/expect/index.css', + plugins: { + 'postcss-import': {}, + 'postcss-nested': {}, + cssnano: ctx.env === 'production' ? {} : false + } + } +}