diff --git a/README.md b/README.md index 5dc7c798c..f112de2bd 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ Optionally, add the `linaria/babel` preset to your Babel configuration at the en } ``` +See [Configuration](/docs/CONFIGURATION.md) to customize how Linaria processes your files. + ## Syntax Linaria can be used with any framework, with additional helpers for React. The basic syntax looks like this: @@ -123,7 +125,7 @@ Dynamic styles will be applied using CSS custom properties (aka CSS variables) a - [API and usage](/docs/API.md) - [Client APIs](/docs/API.md#client-apis) - [Server APIs](/docs/API.md#server-apis) -- [Configuring Babel](/docs/BABEL_PRESET.md) +- [Configuration](/docs/CONFIGURATION.md) - [Dynamic styles with `css` tag](/docs/DYNAMIC_STYLES.md) - [Theming](/docs/THEMING.md) - [Critical CSS extraction](/docs/CRITICAL_CSS.md) diff --git a/docs/BABEL_PRESET.md b/docs/BABEL_PRESET.md deleted file mode 100644 index abf1ec637..000000000 --- a/docs/BABEL_PRESET.md +++ /dev/null @@ -1,23 +0,0 @@ -# `linaria/babel` preset - -The preset pre-processes and evaluates the CSS. The bundler plugins use this preset under the hood. You also might want to use this preset if you import the components outside of the files handled by your bundler, such as on your server or in unit tests. - -To use this preset, add `linaria/babel` to your Babel configuration at the end of the presets list: - -`.babelrc`: - -```diff -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-react", -+ "linaria/babel" - ] -} -``` - -## Options - -* `evaluate: boolean` (default: `true`) - Enabling this will evaluate dynamic expressions in the CSS. You need to enable this if you want to use imported variables in the CSS or interpolate other components. Enabling this also ensures that your styled components wrapping other styled components will have the correct specificity and override styles properly. -* `displayName: boolean` (default: `false`) - Enabling this will add a display name to generated class names, e.g. `.Title_abcdef` instead of `.abcdef'. It is disabled by default to generate smaller CSS files. -* `ignore: RegExp` (default: `/node_modules/`) - If you specify a regex here, files matching the regex won't be processed, i.e. the matching files won't be transformed with Babel during evaluation. If you need to transpile certain modules under `/node_modules/`, it's recommended to do it on a module by module basis for faster transforms, e.g. `ignore: /node_modules[\/\\](?!some-module|other-module)/`. diff --git a/docs/BUNDLERS_INTEGRATION.md b/docs/BUNDLERS_INTEGRATION.md index ec841eaff..6671a9bb2 100644 --- a/docs/BUNDLERS_INTEGRATION.md +++ b/docs/BUNDLERS_INTEGRATION.md @@ -86,7 +86,7 @@ The loader accepts the following options: - `sourceMap: boolean` (default: `false`) - Setting this option to `true` will include source maps for the generated CSS so that you can see where source of the class name in devtools. We recommend to enable this only in development mode because the sourcemap is inlined into the CSS files. - `cacheDirectory: string` (default: `'.linaria-cache'`) - Path to the directory where the loader will output the intermediate CSS files. You can pass a relative or absolute directory path. Make sure the directory is inside the working directory for things to work properly. **You should add this directory to `.gitignore` so you don't accidentally commit them.** -In addition to the above options, the loader also accepts all the options accepted by the [babel preset](/docs/BABEL_PRESET.md). +In addition to the above options, the loader also accepts all the options supported in the [configuration file](/docs/CONFIGURATION.md). You can pass options to the loader like so: diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md new file mode 100644 index 000000000..5c57091b8 --- /dev/null +++ b/docs/CONFIGURATION.md @@ -0,0 +1,51 @@ +# Configuration + +Linaria can be customized using a JavaScript, JSON or YAML file. This can be in form of: + +- `linaria.config.js` JS file exporting the object (recommended). +- `linaria` property in a `package.json` file. +- `.linariarc` file with JSON or YAML syntax. +- `.linariarc.json`, `.linariarc.yaml`, `.linariarc.yml`, or `.linariarc.js` file. + +Example `linaria.config.js`: + +```js +module.exports = { + evaluate: true, + displayName: false, +} +``` + +## Options + +- `evaluate: boolean` (default: `true`): + + Enabling this will evaluate dynamic expressions in the CSS. You need to enable this if you want to use imported variables in the CSS or interpolate other components. Enabling this also ensures that your styled components wrapping other styled components will have the correct specificity and override styles properly. + +- `displayName: boolean` (default: `false`): + + Enabling this will add a display name to generated class names, e.g. `.Title_abcdef` instead of `.abcdef'. It is disabled by default to generate smaller CSS files. + +- `ignore: RegExp` (default: `/node_modules/`): + + If you specify a regex here, files matching the regex won't be processed, i.e. the matching files won't be transformed with Babel during evaluation. If you need to compile certain modules under `/node_modules/`, it's recommended to do it on a module by module basis for faster transforms, e.g. `ignore: /node_modules[\/\\](?!some-module|other-module)/`. + +## `linaria/babel` preset + +The preset pre-processes and evaluates the CSS. The bundler plugins use this preset under the hood. You also might want to use this preset if you import the components outside of the files handled by your bundler, such as on your server or in unit tests. + +To use this preset, add `linaria/babel` to your Babel configuration at the end of the presets list: + +`.babelrc`: + +```diff +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react", ++ "linaria/babel" + ] +} +``` + +The babel preset can accept the same options supported by the configuration file, however it's recommended to use the configuration file directly. diff --git a/docs/LINTING.md b/docs/LINTING.md index 120c1c3f0..599c03627 100644 --- a/docs/LINTING.md +++ b/docs/LINTING.md @@ -29,6 +29,8 @@ Here's the example `.stylelintrc` configuration file: Please refer to the [official stylelint documentation](https://stylelint.io/user-guide/configuration/) for more info about configuration. +The preprocessor will use the [options from the configuration file](/docs/CONFIGURATION.md) for processing your files. + ### Linting your files Add the following to your `package.json` scripts: diff --git a/package.json b/package.json index 38e36b126..d424582a7 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-transform-modules-commonjs": "^7.1.0", "@babel/register": "^7.0.0", + "cosmiconfig": "^5.0.7", "loader-utils": "^1.1.0", "mkdirp": "^0.5.1", "postcss": "^7.0.5", diff --git a/src/babel/evaluate.js b/src/babel/evaluate.js index 17eafd3f4..9bfbee3b5 100644 --- a/src/babel/evaluate.js +++ b/src/babel/evaluate.js @@ -1,5 +1,7 @@ /* @flow */ +import type { Options as PluginOptions } from './extract'; + const generator = require('@babel/generator').default; const babel = require('@babel/core'); const Module = require('./module'); @@ -59,7 +61,7 @@ module.exports = function evaluate( t: any, filename: string, transformer?: (text: string) => { code: string }, - options?: { ignore?: RegExp } + options?: PluginOptions ) { const requirements = []; @@ -159,6 +161,7 @@ module.exports = function evaluate( return babel.transformSync(text, { caller: { name: 'linaria', evaluate: true }, filename: this.filename, + presets: [[require.resolve('./index'), options]], plugins: [ // Include this plugin to avoid extra config when using { module: false } for webpack '@babel/plugin-transform-modules-commonjs', @@ -166,7 +169,6 @@ module.exports = function evaluate( // We don't support dynamic imports when evaluating, but don't wanna syntax error // This will replace dynamic imports with an object that does nothing require.resolve('./dynamic-import-noop'), - [require.resolve('./extract'), { evaluate: true }], ], }); }; diff --git a/src/babel/extract.js b/src/babel/extract.js index cf3cd41c1..051f24521 100644 --- a/src/babel/extract.js +++ b/src/babel/extract.js @@ -168,20 +168,12 @@ type State = {| |}; export type Options = { - displayName?: boolean, - evaluate?: boolean, - ignore?: RegExp, + displayName: boolean, + evaluate: boolean, + ignore: RegExp, }; -module.exports = function extract(babel: any, options: Options = {}) { - // Set some defaults for options - options = { - displayName: false, - evaluate: true, - ignore: /node_modules/, - ...options, - }; - +module.exports = function extract(babel: any, options: Options) { const { types: t } = babel; return { diff --git a/src/babel/index.js b/src/babel/index.js index b78c5f56e..664b0b0a0 100644 --- a/src/babel/index.js +++ b/src/babel/index.js @@ -1,4 +1,21 @@ +const cosmiconfig = require('cosmiconfig'); + +const explorer = cosmiconfig('linaria'); + module.exports = function linaria(context, options) { + // Load configuration file + const result = explorer.searchSync(); + + // Set some defaults for options + // eslint-disable-next-line no-param-reassign + options = { + displayName: false, + evaluate: true, + ignore: /node_modules/, + ...(result ? result.config : null), + ...options, + }; + return { plugins: [[require('./extract'), options]], }; diff --git a/src/rollup.js b/src/rollup.js index 34c60f71c..c4b4a2962 100644 --- a/src/rollup.js +++ b/src/rollup.js @@ -6,10 +6,11 @@ const { createFilter } = require('rollup-pluginutils'); const transform = require('./transform'); const slugify = require('./slugify'); -type RollupPluginOptions = PluginOptions & { +type RollupPluginOptions = { include?: string | string[], exclude?: string | string[], sourceMap?: boolean, + ...$Shape, }; module.exports = function linaria({ diff --git a/src/stylelint/preprocessor.js b/src/stylelint/preprocessor.js index f8920ea91..c4cc9ddf5 100644 --- a/src/stylelint/preprocessor.js +++ b/src/stylelint/preprocessor.js @@ -16,9 +16,7 @@ function preprocessor() { let result; try { - result = transform(filename, input, { - evaluate: true, - }); + result = transform(filename, input); } catch (e) { // Ignore parse errors return ''; diff --git a/src/transform.js b/src/transform.js index 605614b46..4c15ac6d3 100644 --- a/src/transform.js +++ b/src/transform.js @@ -36,7 +36,7 @@ const STYLIS_DECLARATION = 1; module.exports = function transform( filename: string, content: string, - options: PluginOptions, + options: $Shape, inputSourceMap?: Object, outputFilename?: string ): Result { diff --git a/website/linaria.config.js b/website/linaria.config.js new file mode 100644 index 000000000..fab2cc816 --- /dev/null +++ b/website/linaria.config.js @@ -0,0 +1,3 @@ +module.exports = { + displayName: process.env.NODE_ENV !== 'production', +}; diff --git a/yarn.lock b/yarn.lock index 5da58d0b4..08a46d6d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2040,6 +2040,13 @@ call-me-maybe@^1.0.1: resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -2047,6 +2054,13 @@ caller-path@^0.1.0: dependencies: callsites "^0.2.0" +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" @@ -2586,6 +2600,16 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +cosmiconfig@^5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.7.tgz#39826b292ee0d78eda137dfa3173bd1c21a43b04" + integrity sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + cp-file@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-6.0.0.tgz#f38477ece100b403fcf780fd34d030486beb693e" @@ -4243,6 +4267,14 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + import-lazy@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" @@ -4466,6 +4498,11 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" @@ -5172,6 +5209,14 @@ js-yaml@^3.7.0: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.9.0: + version "3.12.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" + integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"