Skip to content

Commit

Permalink
Babel Targets & Autoprefixer Config File Options (#107)
Browse files Browse the repository at this point in the history
* swapping order of plugins

* adding comment

* intial addition of helper for working with config file

* initial work

* linter

* moving plugins to top level

* initial work, testing is broken

* fix old tests

* adding comment

* adding tests to the config file helper

* lint bug

* test coverage upping
  • Loading branch information
jonwinton committed Nov 5, 2018
1 parent 30cf624 commit 0fc4106
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 23 deletions.
4 changes: 2 additions & 2 deletions lib/cmd/compile/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const _ = require('lodash'),
},
babelConfig = {
// force babel to resolve the preset from claycli's node modules rather than the clay install's repo
presets: [[require('@babel/preset-env'), { targets: helpers.browserslist }]]
presets: [[require('@babel/preset-env'), { targets: helpers.getConfigFileOrBrowsersList('babelTargets') }]]
},
temporaryIDs = {};

Expand Down Expand Up @@ -324,7 +324,7 @@ function buildScripts(entries, options = {}) {
babel: babelConfig,
postcss: [
cssImport(),
autoprefixer(helpers.browserslist),
autoprefixer(helpers.getConfigFileOrBrowsersList('autoprefixerOptions')),
mixins(),
nested(),
simpleVars()
Expand Down
2 changes: 1 addition & 1 deletion lib/cmd/compile/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ function compile(options = {}) {
.pipe(rename(renameFile))
.pipe(postcss([
cssImport(),
autoprefixer(helpers.browserslist),
autoprefixer(helpers.getConfigFileOrBrowsersList('autoprefixerOptions')),
mixins(),
// Simple vars must come before `nested` so that string interpolation of variables occurs before
// the nesting is parsed. This ensures being able to use variables in class names of nested selectors
Expand Down
25 changes: 20 additions & 5 deletions lib/compilation-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const format = require('date-fns/format'),
chalk = require('chalk'),
fs = require('fs-extra'),
path = require('path'),
amphoraFs = require('amphora-fs');
amphoraFs = require('amphora-fs'),
configFile = require('./config-file-helpers');

/**
* determine how long a compilation task took
Expand Down Expand Up @@ -131,15 +132,15 @@ function transformPath(prefix, destPath, shouldMinify) {
* @returns {Array}
*/
function determinePostCSSPlugins(argv) {
const config = amphoraFs.tryRequire(`${process.cwd()}/claycli.config`);
const configPlugins = configFile.getConfigValue('plugins');

if (config && config.plugins) {
if (!Array.isArray(config.plugins)) {
if (configPlugins) {
if (!Array.isArray(configPlugins)) {
console.error(`${chalk.red('Error: Plugins supplied in config file is not an array')}`);
}

// Return the array of plugins defined in the config file
return config.plugins;
return configPlugins;
} else {
return _.map(argv.plugins, (pluginName) => {
const plugin = amphoraFs.tryRequire(pluginName);
Expand All @@ -156,6 +157,19 @@ function determinePostCSSPlugins(argv) {
}
}

/**
* Given an key, grab the value from the config file
* or pull from the browserlist that's supported
*
* @param {String} key
* @returns {Object|String}
*/
function getConfigFileOrBrowsersList(key) {
const configFileValue = configFile.getConfigValue(key);

return configFileValue ? configFileValue : module.exports.browserslist;
}

module.exports.time = time;
module.exports.debouncedWatcher = _.debounce(watcher, 200);
module.exports.bucket = bucket;
Expand All @@ -165,6 +179,7 @@ module.exports.hasChanged = hasChanged;
module.exports.transformPath = transformPath;
module.exports.browserslist = { browsers: ['> 3%', 'not and_uc > 0'] }; // used by styles, and vueify, and babel/preset-env
module.exports.determinePostCSSPlugins = determinePostCSSPlugins;
module.exports.getConfigFileOrBrowsersList = getConfigFileOrBrowsersList;

// for testing
module.exports.watcher = watcher;
42 changes: 27 additions & 15 deletions lib/compilation-helpers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

const lib = require('./compilation-helpers'),
amphoraFs = require('amphora-fs'),
configFile = require('./config-file-helpers'),
mockConsole = require('jest-mock-console').default;

// Mock tryRequire
// Mocks
amphoraFs.tryRequire = jest.fn();
configFile.getConfigValue = jest.fn();

describe('compilation helpers', () => {
describe('time', () => {
Expand Down Expand Up @@ -120,51 +122,61 @@ describe('compilation helpers', () => {
});

it('uses the values passed in from the command if no config file is set', () => {
amphoraFs.tryRequire
.mockReturnValueOnce(undefined)
.mockReturnValueOnce(pluginMock);
amphoraFs.tryRequire.mockReturnValue(pluginMock);

fn({ plugins: [ 'some-val' ]});
expect(pluginMock).toHaveBeenCalled();
});

it('throws an error if the plugin cannot be found when required', () => {
amphoraFs.tryRequire
.mockReturnValueOnce(undefined)
.mockReturnValueOnce(undefined);
amphoraFs.tryRequire.mockReturnValue(undefined);

expect(() => fn({ plugins: [ 'some-val' ]})).toThrowError();
});

it('logs if the required plugin\'s invocation fails', () => {
const restoreConsole = mockConsole();

amphoraFs.tryRequire
.mockReturnValueOnce(undefined)
.mockReturnValueOnce(() => { throw new Error('foo'); });
amphoraFs.tryRequire.mockReturnValue(() => { throw new Error('foo'); });

fn({ plugins: [ 'some-val' ]});
expect(console.error).toHaveBeenCalled();
restoreConsole();
});

it ('returns the plugin array from the config file if it exists', () => {
amphoraFs.tryRequire
.mockReturnValueOnce({ plugins: [] })
.mockReturnValueOnce(pluginMock);
const restoreConsole = mockConsole();

configFile.getConfigValue.mockReturnValue([]);
amphoraFs.tryRequire.mockReturnValue(pluginMock);

fn({ plugins: [ 'some-val' ]});
expect(amphoraFs.tryRequire).toHaveBeenCalledTimes(1);
expect(amphoraFs.tryRequire).toHaveBeenCalledTimes(0);
expect(pluginMock).not.toHaveBeenCalled();
restoreConsole();
});

it ('throws an error if the config file plugins property is not an array', () => {
const restoreConsole = mockConsole();

amphoraFs.tryRequire.mockReturnValueOnce({ plugins: {} });
configFile.getConfigValue.mockReturnValue({});
fn({ plugins: [ 'some-val' ]});
expect(console.error).toHaveBeenCalled();
restoreConsole();
});
});

describe('getConfigFileOrBrowsersList', () => {
const fn = lib.getConfigFileOrBrowsersList;

it('returns a value from the config if one is found', () => {
configFile.getConfigValue.mockReturnValue({});
expect(fn('foo')).toEqual({});
});

it('returns a value defined in the file no config value is found', () => {
configFile.getConfigValue.mockReturnValue(undefined);
expect(fn('foo')).toEqual(lib.browserslist);
});
});
});
35 changes: 35 additions & 0 deletions lib/config-file-helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';

const amphoraFs = require('amphora-fs'),
CONFIG_FILENAME = 'claycli.config';
var CONFIG_FILE = getConfigFile();

/**
* Grab the config file from the working directory
* or return undefined
*
* @returns {Object|Undefined}
*/
function getConfigFile() {
return amphoraFs.tryRequire(`${process.cwd()}/${CONFIG_FILENAME}`);
}

/**
* Return a value from the config file
*
* @param {String} key
* @returns {Any}
*/
function getConfigValue(key) {
if (!CONFIG_FILE) {
return undefined;
}

return CONFIG_FILE[key];
}

module.exports.getConfigValue = getConfigValue;

// For testing
module.exports.getConfigFile = getConfigFile;
module.exports.setConfigFile = val => CONFIG_FILE = val;
50 changes: 50 additions & 0 deletions lib/config-file-helpers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict';

const lib = require('./config-file-helpers'),
amphoraFs = require('amphora-fs');

// Mock tryRequire
amphoraFs.tryRequire = jest.fn();

describe('project specific config file helpers', () => {
describe('getConfigFile', () => {
const fn = lib.getConfigFile;

it('returns undefined if the file is not found', () => {
expect(fn()).toBe(undefined);
});

it('returns a file if one is found', () => {
amphoraFs.tryRequire.mockReturnValue({});

expect(fn()).toEqual({});
});
});

describe('getConfigValue', () => {
const fn = lib.getConfigValue,
SAMPLE_CONFIG = {
babelTargets: 'some value',
autoprefixerOptions: { foo: true, bar: false }
};

beforeEach(() => {
lib.setConfigFile(SAMPLE_CONFIG);
});

it('returns undefined if the config file is not present', () => {
lib.setConfigFile(undefined);

expect(fn('babelTargets')).toBe(undefined);
});

it('returns a value from the config if it exists', () => {
expect(fn('babelTargets')).toBe('some value');
expect(fn('autoprefixerOptions')).toEqual({ foo: true, bar: false});
});

it('returns undefined if the value does not exist', () => {
expect(fn('fakeVal')).toBe(undefined);
});
});
});

0 comments on commit 0fc4106

Please sign in to comment.