diff --git a/.flowconfig b/.flowconfig index 689945b..8e3973d 100644 --- a/.flowconfig +++ b/.flowconfig @@ -2,3 +2,6 @@ /node_modules/config-chain/test/broken.json /node_modules/conventional-changelog-core/test/fixtures/_malformation.json /node_modules/npmconf/test/fixtures/package.json + +[options] +module.ignore_non_literal_requires=true diff --git a/README.md b/README.md index 0568908..165c8e5 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ In contrast to [`react-css-modules`](https://github.com/gajus/react-css-modules) * [Anonymous reference](#anonymous-reference) * [Named reference](#named-reference) * [Configuration](#configuration) + * [Configurate syntax loaders](#configurate-syntax-loaders) * [Installation](#installation) * [Example transpilations](#example-transpilations) * [Anonymous `styleName` resolution](#anonymous-stylename-resolution) @@ -167,14 +168,33 @@ NODE_ENV=production ./test |Name|Description|Default| |---|---|---| -|`generateScopedName`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names)|`[path]___[name]__[local]___[hash:base64:5]`| |`context`|Must match webpack [`context`](https://webpack.github.io/docs/configuration.html#context) configuration. [`css-loader`](https://github.com/webpack/css-loader) inherits `context` values from webpack. Other CSS module implementations might use different context resolution logic.|`process.cwd()`| +|`filetypes`|Configure [postcss syntax loaders](https://github.com/postcss/postcss#syntaxes) like sugerss, LESS and SCSS. || +|`generateScopedName`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names)|`[path]___[name]__[local]___[hash:base64:5]`| Missing a configuration? [Raise an issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/new?title=New%20configuration:). > Note: > The default configuration should work out of the box with the [css-loader](https://github.com/webpack/css-loader). +### Configurate syntax loaders + +To add support for different CSS syntaxes (e.g. SCSS), perform the following two steps: + +1. Add the [postcss syntax loader](https://github.com/postcss/postcss#syntaxes) as a development dependency: + + ```bash + npm install postcss-scss --save-dev + ``` + +2. Add a filetype syntax mapping to the Babel plugin configuration + + ```json + "filetypes": { + ".scss": "postcss-scss" + } + ``` + ## Installation When `babel-plugin-react-css-modules` cannot resolve CSS module at a compile time, it imports a helper function (read [Runtime `styleName` resolution](#runtime-stylename-resolution)). Therefore, you must install `babel-plugin-react-css-modules` as a direct dependency of the project. diff --git a/package.json b/package.json index 63d421c..e12b131 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,7 @@ "postcss-modules-local-by-default": "^1.1.1", "postcss-modules-parser": "^1.1.0", "postcss-modules-scope": "^1.0.2", - "postcss-modules-values": "^1.2.2", - "postcss-scss": "^0.4.0" + "postcss-modules-values": "^1.2.2" }, "description": "Transforms styleName to className using compile time CSS module resolution.", "devDependencies": { @@ -31,7 +30,9 @@ "flow-bin": "^0.37.4", "husky": "^0.12.0", "mocha": "^3.2.0", - "semantic-release": "^6.3.5" + "semantic-release": "^6.3.5", + "postcss-less": "^0.15.0", + "postcss-scss": "^0.4.0" }, "engines": { "node": ">5.0.0" diff --git a/src/index.js b/src/index.js index f4963e0..b2b655b 100644 --- a/src/index.js +++ b/src/index.js @@ -61,7 +61,11 @@ export default ({ inherits: babelPluginJsxSyntax, visitor: { ImportDeclaration (path: Object, stats: Object): void { - if (!path.node.source.value.endsWith('.css') && !path.node.source.value.endsWith('.scss')) { + stats.opts.filetypes = stats.opts.filetypes || {}; + + const extension = path.node.source.value.lastIndexOf('.') > -1 ? path.node.source.value.substr(path.node.source.value.lastIndexOf('.')) : null; + + if (extension !== '.css' && Object.keys(stats.opts.filetypes).indexOf(extension) < 0) { return; } @@ -84,6 +88,7 @@ export default ({ } filenameMap[filename].styleModuleImportMap[styleImportName] = requireCssModule(targetResourcePath, { + filetypes: stats.opts.filetypes || {}, generateScopedName: stats.opts.generateScopedName }); }, diff --git a/src/requireCssModule.js b/src/requireCssModule.js index 9a94d2c..28e8703 100644 --- a/src/requireCssModule.js +++ b/src/requireCssModule.js @@ -14,20 +14,21 @@ import LocalByDefault from 'postcss-modules-local-by-default'; import Parser from 'postcss-modules-parser'; import Scope from 'postcss-modules-scope'; import Values from 'postcss-modules-values'; -import ScssSyntax from 'postcss-scss'; import type { StyleModuleMapType } from './types'; -const getTokens = (runner, cssSourceFilePath: string): StyleModuleMapType => { - const sourceFilePathIsScss = cssSourceFilePath.endsWith('.scss'); +const getTokens = (runner, cssSourceFilePath: string, filetypes): StyleModuleMapType => { + const extension = cssSourceFilePath.substr(cssSourceFilePath.lastIndexOf('.')); + const syntax = filetypes[extension]; const options: Object = { from: cssSourceFilePath }; - if (sourceFilePathIsScss) { - options.syntax = ScssSyntax; + if (syntax) { + // eslint-disable-next-line import/no-dynamic-require, global-require + options.syntax = require(syntax); } const lazyResult = runner @@ -44,6 +45,7 @@ const getTokens = (runner, cssSourceFilePath: string): StyleModuleMapType => { }; type OptionsType = {| + filetypes: Object, generateScopedName?: string, context?: string |}; @@ -60,7 +62,7 @@ export default (cssSourceFilePath: string, options: OptionsType): StyleModuleMap const fromDirectoryPath = dirname(from); const toPath = resolve(fromDirectoryPath, to); - return getTokens(runner, toPath); + return getTokens(runner, toPath, options.filetypes); }; const plugins = [ @@ -77,5 +79,5 @@ export default (cssSourceFilePath: string, options: OptionsType): StyleModuleMap runner = postcss(plugins); - return getTokens(runner, cssSourceFilePath); + return getTokens(runner, cssSourceFilePath, options.filetypes); }; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/actual.js b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js new file mode 100644 index 0000000..90aeb49 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js @@ -0,0 +1,3 @@ +import './bar.less'; + +
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/bar.less b/test/fixtures/react-css-modules/resolves less stylesheets/bar.less new file mode 100644 index 0000000..6586489 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/bar.less @@ -0,0 +1,3 @@ +@color: #f00; + +.a {background-color: @color;} diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/expected.js b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js new file mode 100644 index 0000000..f87c7c1 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js @@ -0,0 +1,3 @@ +import './bar.less'; + +
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/options.json b/test/fixtures/react-css-modules/resolves less stylesheets/options.json new file mode 100644 index 0000000..903f779 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/options.json @@ -0,0 +1,13 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]", + "filetypes": { + ".less": "postcss-less" + } + } + ] + ] +}