From 8ac17dd8b015dca26585473c70d8ef31a78e1399 Mon Sep 17 00:00:00 2001 From: Giuseppe Gurgone Date: Sun, 28 May 2017 08:36:48 +0200 Subject: [PATCH] Add plugins options --- readme.md | 43 +++++++++++++++++++++++++++++- src/_utils.js | 8 +++--- src/babel-external.js | 2 +- src/babel.js | 10 ++++--- test/__snapshots__/index.js.snap | 18 +++++++++++++ test/__snapshots__/plugins.js.snap | 13 +++++++++ test/fixtures/plugins/options.js | 1 + test/index.js | 9 ++++++- test/plugins.js | 30 +++++++++++++-------- 9 files changed, 112 insertions(+), 22 deletions(-) create mode 100644 test/__snapshots__/plugins.js.snap create mode 100644 test/fixtures/plugins/options.js diff --git a/readme.md b/readme.md index 48a4bdbc..66ed0965 100644 --- a/readme.md +++ b/readme.md @@ -121,7 +121,7 @@ Styles can be preprocessed via plugins. Plugins are regular JavaScript modules that export a simple function with the following signature: ```js -(css: string) => string +(css: string, settings: Object) => string ``` Basically they accept a CSS string in input, optionally modify it and finally return it. @@ -147,6 +147,47 @@ Plugins are applied in definition order left to right before styles are scoped. N.B. when applying the plugins styled-jsx replaces template literals expressions with placeholders e.g. `%%styledjsxexpression_ExprNumber%%` because otherwise CSS parsers would get invalid CSS. +#### Plugin options and settings + +Users can set plugin options by registering a plugin as an array that contains +the plugin path and an options object. + +```json +{ + "plugins": [ + [ + "styled-jsx/babel", + { + "plugins": [ + ["my-styled-jsx-plugin-package", { "exampleOption": true }] + ], + "sourceMaps": true + } + ] + ] +} +``` + +Each plugin receives a `settings` object as second argument which contains +the babel and user options: + +```js +export default (css, settings) => { /* ... */ } +``` + +The `settings` object has the following shape: + +```js +{ + sourceMaps: true, + + // user options + options: { + exampleOption: true + } +} +``` + ### Targeting The Root Notice that the parent `
` above also gets a `data-jsx` attribute. We do this so that diff --git a/src/_utils.js b/src/_utils.js index b0ff4162..556d47cf 100644 --- a/src/_utils.js +++ b/src/_utils.js @@ -217,7 +217,7 @@ export const addSourceMaps = (code, generator, filename) => `/*@ sourceURL=${filename} */` ].join('\n') -export const combinePlugins = plugins => { +export const combinePlugins = (plugins, opts) => { if (!plugins) { return css => css } @@ -231,14 +231,12 @@ export const combinePlugins = plugins => { ) } - const env = typeof window === 'undefined' ? 'compile' : 'runtime' - return plugins .map((plugin, i) => { let options = {} if (Array.isArray(plugin)) { - plugin = plugin[0] options = plugin[1] || {} + plugin = plugin[0] } // eslint-disable-next-line import/no-dynamic-require @@ -256,7 +254,7 @@ export const combinePlugins = plugins => { return { plugin: p, settings: { - env, + ...opts, options } } diff --git a/src/babel-external.js b/src/babel-external.js index 4c4914db..88bc400c 100644 --- a/src/babel-external.js +++ b/src/babel-external.js @@ -158,7 +158,7 @@ const callVisitor = (visitor, path, state) => { const { opts } = file visitor(path, { validate: opts.validate, - sourceMaps: opts.sourceMaps, + sourceMaps: state.opts.sourceMaps || opts.sourceMaps, sourceFileName: opts.sourceFileName, file, plugins diff --git a/src/babel.js b/src/babel.js index b0e16598..afc0b951 100644 --- a/src/babel.js +++ b/src/babel.js @@ -37,7 +37,7 @@ const callExternalVisitor = (visitor, path, state) => { const { opts } = file visitor(path, { validate: true, - sourceMaps: opts.sourceMaps, + sourceMaps: state.opts.sourceMaps || opts.sourceMaps, sourceFileName: opts.sourceFileName, file, plugins @@ -295,7 +295,9 @@ export default function({ types: t }) { // We replace styles with the function call const [id, css, loc] = state.styles.shift() - const useSourceMaps = Boolean(state.file.opts.sourceMaps) + const useSourceMaps = Boolean( + state.opts.sourceMaps || state.file.opts.sourceMaps + ) let transformedCss if (useSourceMaps) { @@ -338,7 +340,9 @@ export default function({ types: t }) { state.file.hasJSXStyle = false state.imports = [] if (!plugins) { - plugins = combinePlugins(state.opts.plugins) + plugins = combinePlugins(state.opts.plugins, { + sourceMaps: state.opts.sourceMaps || state.file.opts.sourceMaps + }) } }, exit({ node, scope }, state) { diff --git a/test/__snapshots__/index.js.snap b/test/__snapshots__/index.js.snap index ffb119df..bac0e894 100644 --- a/test/__snapshots__/index.js.snap +++ b/test/__snapshots__/index.js.snap @@ -1,5 +1,23 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`generates source maps (babel options) 1`] = ` +"import _JSXStyle from 'styled-jsx/style'; +export default (() =>
+

test

+

woot

+ <_JSXStyle styleId={188072295} css={\\"p[data-jsx=\\\\\\"188072295\\\\\\"]{color:red}\\\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJzb3VyY2UtbWFwcy5qcyIsInNvdXJjZXNDb250ZW50IjpbXX0= */\\\\n/*@ sourceURL=source-maps.js */\\"} /> +
);" +`; + +exports[`generates source maps (plugin options) 1`] = ` +"import _JSXStyle from 'styled-jsx/style'; +export default (() =>
+

test

+

woot

+ <_JSXStyle styleId={188072295} css={\\"p[data-jsx=\\\\\\"188072295\\\\\\"]{color:red}\\\\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsImZpbGUiOiJzb3VyY2UtbWFwcy5qcyIsInNvdXJjZXNDb250ZW50IjpbXX0= */\\\\n/*@ sourceURL=source-maps.js */\\"} /> +
);" +`; + exports[`generates source maps 1`] = ` "import _JSXStyle from 'styled-jsx/style'; export default (() =>
diff --git a/test/__snapshots__/plugins.js.snap b/test/__snapshots__/plugins.js.snap new file mode 100644 index 00000000..d71c9954 --- /dev/null +++ b/test/__snapshots__/plugins.js.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`applies plugins 1`] = ` +"import _JSXStyle from 'styled-jsx/style'; +import styles from './styles'; +const color = 'red'; + +export default (() =>
+

test

+ <_JSXStyle styleId={4216192053} css={\`span[data-jsx=\\"4216192053\\"].\${color}[data-jsx=\\"4216192053\\"]{color:\${otherColor}}\`} /> + <_JSXStyle styleId={styles.__scopedHash} css={styles.__scoped} /> +
);" +`; diff --git a/test/fixtures/plugins/options.js b/test/fixtures/plugins/options.js new file mode 100644 index 00000000..d0c4376d --- /dev/null +++ b/test/fixtures/plugins/options.js @@ -0,0 +1 @@ +export default (css, settings) => settings.options.test diff --git a/test/index.js b/test/index.js index 905a9b77..52668f5c 100644 --- a/test/index.js +++ b/test/index.js @@ -40,13 +40,20 @@ test('works with global styles', async t => { t.snapshot(code) }) -test('generates source maps', async t => { +test('generates source maps (babel options)', async t => { const { code } = await transform('./fixtures/source-maps.js', { sourceMaps: true }) t.snapshot(code) }) +test('generates source maps (plugin options)', async t => { + const { code } = await _transform('./fixtures/source-maps.js', { + plugins: [[plugin, { sourceMaps: true }]] + }) + t.snapshot(code) +}) + test('mixed global and scoped', async t => { const { code } = await transform('./fixtures/mixed-global-scoped.js') t.snapshot(code) diff --git a/test/plugins.js b/test/plugins.js index fcdbb66e..09e9956e 100644 --- a/test/plugins.js +++ b/test/plugins.js @@ -3,23 +3,21 @@ import test from 'ava' // Ours import babelPlugin from '../src/babel' -import {combinePlugins} from '../src/_utils' +import { combinePlugins } from '../src/_utils' import _transform from './_transform' -import read from './_read' import testPlugin1 from './fixtures/plugins/plugin' import testPlugin2 from './fixtures/plugins/another-plugin' -const transform = (file, opts = {}) => ( +const transform = (file, opts = {}) => _transform(file, { plugins: [ [ babelPlugin, - {plugins: [require.resolve('./fixtures/plugins/another-plugin')]} + { plugins: [require.resolve('./fixtures/plugins/another-plugin')] } ] ], ...opts }) -) test('combinePlugins returns an identity function when plugins is undefined', t => { const test = 'test' @@ -49,13 +47,24 @@ test('combinePlugins throws if loaded plugins are not functions', t => { }) test('combinePlugins works with a single plugin', t => { - const plugins = combinePlugins([ - require.resolve('./fixtures/plugins/plugin') - ]) + const plugins = combinePlugins([require.resolve('./fixtures/plugins/plugin')]) t.is(testPlugin1('test'), plugins('test')) }) +test('combinePlugins works with options', t => { + const expectedOption = 'my-test' + const plugins = combinePlugins([ + [ + require.resolve('./fixtures/plugins/options'), + { + test: expectedOption + } + ] + ]) + t.is(plugins(''), expectedOption) +}) + test('combinePlugins applies plugins left to right', t => { const plugins = combinePlugins([ require.resolve('./fixtures/plugins/plugin'), @@ -66,7 +75,6 @@ test('combinePlugins applies plugins left to right', t => { }) test('applies plugins', async t => { - const {code} = await transform('./fixtures/with-plugins.js') - const out = await read('./fixtures/with-plugins.out.js') - t.is(code, out.trim()) + const { code } = await transform('./fixtures/with-plugins.js') + t.snapshot(code) })