From 4c6b8319299cbc8b51507e287d041a59d87f3ce8 Mon Sep 17 00:00:00 2001 From: Johan de Koning Date: Fri, 9 Dec 2016 12:34:17 +0100 Subject: [PATCH 01/10] Make syntax parser configurable --- package.json | 1 + src/index.js | 7 ++++++- src/requireCssModule.js | 16 ++++++++++++---- .../resolves less stylesheets/actual.js | 3 +++ .../resolves less stylesheets/bar.css | 1 + .../resolves less stylesheets/expected.js | 3 +++ .../resolves less stylesheets/options.json | 13 +++++++++++++ 7 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/actual.js create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/bar.css create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/expected.js create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/options.json diff --git a/package.json b/package.json index bf7b051..f010f4e 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "babel-types": "^6.19.0", "generic-names": "^1.0.2", "postcss": "^5.2.6", + "postcss-less": "^0.15.0", "postcss-modules": "^0.5.2", "postcss-modules-extract-imports": "^1.0.1", "postcss-modules-local-by-default": "^1.1.1", diff --git a/src/index.js b/src/index.js index 0d49ae1..da45225 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; } @@ -82,6 +86,7 @@ export default ({ } styleModuleImportMap[styleImportName] = requireCssModule(targetResourcePath, { + filetypes: stats.opts.filetypes || {}, generateScopedName: stats.opts.generateScopedName }); }, diff --git a/src/requireCssModule.js b/src/requireCssModule.js index f7cfd86..90b3af6 100644 --- a/src/requireCssModule.js +++ b/src/requireCssModule.js @@ -19,14 +19,22 @@ 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) { + if (syntax) { + // eslint-disable-next-line import/no-dynamic-require, global-require, no-console + // const parser = require(syntax); + + // eslint-disable-next-line import/no-dynamic-require, global-require, no-console + // console.log(parser); + + // eslint-disable-next-line import/no-dynamic-require, global-require options.syntax = ScssSyntax; } @@ -74,5 +82,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..e8df246 --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js @@ -0,0 +1,3 @@ +import './bar.css'; + +
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/bar.css b/test/fixtures/react-css-modules/resolves less stylesheets/bar.css new file mode 100644 index 0000000..077f6dd --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/bar.css @@ -0,0 +1 @@ +a {} 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..f24ac6d --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js @@ -0,0 +1,3 @@ +import './bar.css'; + +
; 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" + } + } + ] + ] +} From 8a1a37dc5a44918978bed25087a440c15ae09d9f Mon Sep 17 00:00:00 2001 From: Johan de Koning Date: Fri, 9 Dec 2016 13:12:09 +0100 Subject: [PATCH 02/10] Make syntax parser configurable --- .flowconfig | 3 +++ package.json | 8 ++++---- src/requireCssModule.js | 12 +++--------- .../resolves less stylesheets/actual.js | 2 +- .../resolves less stylesheets/bar.css | 1 - .../resolves less stylesheets/bar.less | 3 +++ .../resolves less stylesheets/expected.js | 2 +- 7 files changed, 15 insertions(+), 16 deletions(-) delete mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/bar.css create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/bar.less 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/package.json b/package.json index f010f4e..138bbd0 100644 --- a/package.json +++ b/package.json @@ -9,14 +9,12 @@ "babel-types": "^6.19.0", "generic-names": "^1.0.2", "postcss": "^5.2.6", - "postcss-less": "^0.15.0", "postcss-modules": "^0.5.2", "postcss-modules-extract-imports": "^1.0.1", "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": { @@ -32,7 +30,9 @@ "flow-bin": "^0.36.0", "husky": "^0.11.9", "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/requireCssModule.js b/src/requireCssModule.js index 90b3af6..5624a4d 100644 --- a/src/requireCssModule.js +++ b/src/requireCssModule.js @@ -14,7 +14,6 @@ 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'; @@ -28,14 +27,8 @@ const getTokens = (runner, cssSourceFilePath: string, filetypes): StyleModuleMap }; if (syntax) { - // eslint-disable-next-line import/no-dynamic-require, global-require, no-console - // const parser = require(syntax); - - // eslint-disable-next-line import/no-dynamic-require, global-require, no-console - // console.log(parser); - // eslint-disable-next-line import/no-dynamic-require, global-require - options.syntax = ScssSyntax; + options.syntax = require(syntax); } const lazyResult = runner @@ -52,6 +45,7 @@ const getTokens = (runner, cssSourceFilePath: string, filetypes): StyleModuleMap }; type OptionsType = {| + filetypes: Object, generateScopedName?: string |}; @@ -65,7 +59,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 = [ diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/actual.js b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js index e8df246..90aeb49 100644 --- a/test/fixtures/react-css-modules/resolves less stylesheets/actual.js +++ b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js @@ -1,3 +1,3 @@ -import './bar.css'; +import './bar.less';
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/bar.css b/test/fixtures/react-css-modules/resolves less stylesheets/bar.css deleted file mode 100644 index 077f6dd..0000000 --- a/test/fixtures/react-css-modules/resolves less stylesheets/bar.css +++ /dev/null @@ -1 +0,0 @@ -a {} 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 index f24ac6d..f87c7c1 100644 --- a/test/fixtures/react-css-modules/resolves less stylesheets/expected.js +++ b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js @@ -1,3 +1,3 @@ -import './bar.css'; +import './bar.less';
; From ce0303e9c1bc80fb5f2259c546ef11f597e6aeea Mon Sep 17 00:00:00 2001 From: Pierre Criulanscy Date: Sun, 18 Dec 2016 14:48:51 +0100 Subject: [PATCH 03/10] fix: handle multiple file import with dynamic resolution (fixes #7 #11 #13 #14 #17) (#12) * fix: added escape hatch when testing attribute that do not have a name property (#11) * fix: object expression generated on dynamic resolution now use quote to escape properties' name (#14) * fix: getClassName now works as expected when multiple file use runtime resolution * fix: getClassName now works as expected when multiple file use runtime resolution --- package.json | 2 +- src/createObjectExpression.js | 2 +- src/index.js | 55 ++++++++++++------- src/resolveStringLiteral.js | 2 +- .../actual.js | 7 +++ .../bar.css | 1 + .../expected.js | 7 +++ .../options.json | 10 ++++ .../actual.js | 8 +++ .../bar.css | 1 + .../expected.js | 17 ++++++ .../foo.css | 1 + .../options.json | 10 ++++ .../actual.js | 9 ++- .../bar.css | 2 +- .../expected.js | 16 ++++-- .../foo.css | 1 + 17 files changed, 119 insertions(+), 32 deletions(-) create mode 100644 test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js create mode 100644 test/fixtures/react-css-modules/does not throw error if attribute has no name property/bar.css create mode 100644 test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js create mode 100644 test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json create mode 100644 test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/foo.css diff --git a/package.json b/package.json index 138bbd0..1b71b5c 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "build": "rm -fr ./dist && NODE_ENV=production babel ./src --out-dir ./dist --source-maps && npm run build-helper", "lint": "eslint ./src", "precommit": "npm run test", - "test": "NODE_ENV=development npm run lint && npm run build && mocha --compilers js:babel-register && flow" + "test": "NODE_ENV=development npm run lint && npm run build && NODE_ENV=test mocha --compilers js:babel-register && flow" }, "version": "1.0.0" } diff --git a/src/createObjectExpression.js b/src/createObjectExpression.js index 765340d..802a033 100644 --- a/src/createObjectExpression.js +++ b/src/createObjectExpression.js @@ -25,7 +25,7 @@ const createObjectExpression = (t: BabelTypes, object: Object): ObjectExpression properties.push( t.objectProperty( - t.identifier(name), + t.identifier('\'' + name + '\''), newValue ) ); diff --git a/src/index.js b/src/index.js index da45225..1c80b0d 100644 --- a/src/index.js +++ b/src/index.js @@ -16,24 +16,22 @@ export default ({ }: { types: BabelTypes }) => { - let styleModuleImportMap; - let importedHelperIndentifier; - let styleModuleImportMapIdentifier; + const filenameMap = {}; - const setupFileForRuntimeResolution = (path) => { + const setupFileForRuntimeResolution = (path, filename) => { const programPath = path.findParent((parentPath) => { return parentPath.isProgram(); }); - importedHelperIndentifier = programPath.scope.generateUidIdentifier('getClassName'); - styleModuleImportMapIdentifier = programPath.scope.generateUidIdentifier('styleModuleImportMap'); + filenameMap[filename].importedHelperIndentifier = programPath.scope.generateUidIdentifier('getClassName'); + filenameMap[filename].styleModuleImportMapIdentifier = programPath.scope.generateUidIdentifier('styleModuleImportMap'); programPath.unshiftContainer( 'body', t.importDeclaration( [ t.importDefaultSpecifier( - importedHelperIndentifier + filenameMap[filename].importedHelperIndentifier ) ], t.stringLiteral('babel-plugin-react-css-modules/dist/browser/getClassName') @@ -49,12 +47,14 @@ export default ({ 'const', [ t.variableDeclarator( - styleModuleImportMapIdentifier, - createObjectExpression(t, styleModuleImportMap) + filenameMap[filename].styleModuleImportMapIdentifier, + createObjectExpression(t, filenameMap[filename].styleModuleImportMap) ) ] ) ); + // eslint-disable-next-line + // console.log('setting up', filename, util.inspect(filenameMap,{depth: 5})) }; return { @@ -69,13 +69,15 @@ export default ({ return; } + const filename = stats.file.opts.filename; const targetFileDirectoryPath = dirname(stats.file.opts.filename); const targetResourcePath = resolve(targetFileDirectoryPath, path.node.source.value); let styleImportName: string; if (path.node.specifiers.length === 0) { - styleImportName = 'random-' + Math.random(); + // eslint-disable-next-line no-process-env + styleImportName = process.env.NODE_ENV === 'test' ? 'random-test' : 'random-' + Math.random(); } else if (path.node.specifiers.length === 1) { styleImportName = path.node.specifiers[0].local.name; } else { @@ -85,15 +87,16 @@ export default ({ throw new Error('Unexpected use case.'); } - styleModuleImportMap[styleImportName] = requireCssModule(targetResourcePath, { + filenameMap[filename].styleModuleImportMap[styleImportName] = requireCssModule(targetResourcePath, { filetypes: stats.opts.filetypes || {}, generateScopedName: stats.opts.generateScopedName }); }, - JSXElement (path: Object): void { + JSXElement (path: Object, stats: Object): void { + const filename = stats.file.opts.filename; const styleNameAttribute = path.node.openingElement.attributes .find((attribute) => { - return attribute.name.name === 'styleName'; + return typeof attribute.name !== 'undefined' && attribute.name.name === 'styleName'; }); if (!styleNameAttribute) { @@ -101,21 +104,33 @@ export default ({ } if (t.isStringLiteral(styleNameAttribute.value)) { - resolveStringLiteral(path, styleModuleImportMap, styleNameAttribute); + resolveStringLiteral( + path, + filenameMap[filename].styleModuleImportMap, + styleNameAttribute + ); return; } if (t.isJSXExpressionContainer(styleNameAttribute.value)) { - if (!importedHelperIndentifier) { - setupFileForRuntimeResolution(path); + if (!filenameMap[filename].importedHelperIndentifier) { + setupFileForRuntimeResolution(path, filename); } - - replaceJsxExpressionContainer(t, styleNameAttribute, importedHelperIndentifier, styleModuleImportMapIdentifier); + replaceJsxExpressionContainer( + t, + styleNameAttribute, + filenameMap[filename].importedHelperIndentifier, + filenameMap[filename].styleModuleImportMapIdentifier + ); } }, - Program () { - styleModuleImportMap = {}; + Program (path: Object, stats: Object): void { + const filename = stats.file.opts.filename; + + filenameMap[filename] = { + styleModuleImportMap: {} + }; } } }; diff --git a/src/resolveStringLiteral.js b/src/resolveStringLiteral.js index 580be36..47800a3 100644 --- a/src/resolveStringLiteral.js +++ b/src/resolveStringLiteral.js @@ -11,7 +11,7 @@ import type { export default (path: Object, styleModuleImportMap: StyleModuleImportMapType, styleNameAttribute: JSXAttribute): void => { const classNameAttribute = path.node.openingElement.attributes .find((attribute) => { - return attribute.name.name === 'className'; + return typeof attribute.name !== 'undefined' && attribute.name.name === 'className'; }); const resolvedStyleName = getClassName(styleNameAttribute.value.value, styleModuleImportMap); diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js new file mode 100644 index 0000000..4e99b7b --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/actual.js @@ -0,0 +1,7 @@ +import './bar.css'; + +const props = { + foo: 'bar' +}; + +
; diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/bar.css b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/bar.css new file mode 100644 index 0000000..5512dae --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/bar.css @@ -0,0 +1 @@ +.a {} diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js new file mode 100644 index 0000000..5d797f4 --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/expected.js @@ -0,0 +1,7 @@ +import './bar.css'; + +const props = { + foo: 'bar' +}; + +
; diff --git a/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json new file mode 100644 index 0000000..6f54db7 --- /dev/null +++ b/test/fixtures/react-css-modules/does not throw error if attribute has no name property/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]" + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js new file mode 100644 index 0000000..f284d12 --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js @@ -0,0 +1,8 @@ +import bar from './bar.css'; +import './foo.css'; + +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; + +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css new file mode 100644 index 0000000..794d0af --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css @@ -0,0 +1 @@ +.a-b {} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js new file mode 100644 index 0000000..41d4f3e --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js @@ -0,0 +1,17 @@ +import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; +import bar from './bar.css'; +import './foo.css'; + +const _styleModuleImportMap = { + 'bar': { + 'a-b': 'bar__a-b' + }, + 'random-test': { + 'a-b': 'foo__a-b' + } +}; +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; + +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css new file mode 100644 index 0000000..794d0af --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css @@ -0,0 +1 @@ +.a-b {} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json new file mode 100644 index 0000000..6f54db7 --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + [ + "../../../../src", + { + "generateScopedName": "[name]__[local]" + } + ] + ] +} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js index 21c0bae..f284d12 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/actual.js @@ -1,5 +1,8 @@ -import foo from './bar.css'; +import bar from './bar.css'; +import './foo.css'; -const styleNameValue = 'a'; +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; -
; +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/bar.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/bar.css index 5512dae..794d0af 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/bar.css +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/bar.css @@ -1 +1 @@ -.a {} +.a-b {} diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js index dcc41ef..41d4f3e 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js @@ -1,11 +1,17 @@ import _getClassName from 'babel-plugin-react-css-modules/dist/browser/getClassName'; -import foo from './bar.css'; +import bar from './bar.css'; +import './foo.css'; const _styleModuleImportMap = { - foo: { - a: 'bar__a' + 'bar': { + 'a-b': 'bar__a-b' + }, + 'random-test': { + 'a-b': 'foo__a-b' } }; -const styleNameValue = 'a'; +const styleNameBar = 'bar.a-b'; +const styleNameFoo = 'a-b'; -
; +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/foo.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/foo.css new file mode 100644 index 0000000..794d0af --- /dev/null +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/foo.css @@ -0,0 +1 @@ +.a-b {} From 1fdd2088023135838ead85da4e6f24c8e48ca1de Mon Sep 17 00:00:00 2001 From: Pierre Criulanscy Date: Mon, 19 Dec 2016 11:52:28 +0100 Subject: [PATCH 04/10] fix: generate className when using runtime resolution (#18) (#19) * fix: added escape hatch when testing attribute that do not have a name property (#11) * fix: object expression generated on dynamic resolution now use quote to escape properties' name (#14) * fix: getClassName now works as expected when multiple file use runtime resolution * fix: getClassName now works as expected when multiple file use runtime resolution * fix: className attribute is now correctly generated when using runtime resolution (#18) --- src/index.js | 1 + src/replaceJsxExpressionContainer.js | 33 ++++++++++++++----- .../actual.js | 2 +- .../bar.css | 0 .../expected.js | 4 +-- .../foo.css | 0 .../options.json | 0 .../expected.js | 4 +-- 8 files changed, 31 insertions(+), 13 deletions(-) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/actual.js (72%) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/bar.css (100%) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/expected.js (68%) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/foo.css (100%) rename test/fixtures/react-css-modules/{uses getClassName to resolve non-literal styleName bis => uses getClassName to resolve non-literal styleName (with already existing className)}/options.json (100%) diff --git a/src/index.js b/src/index.js index 1c80b0d..b2b655b 100644 --- a/src/index.js +++ b/src/index.js @@ -119,6 +119,7 @@ export default ({ } replaceJsxExpressionContainer( t, + path, styleNameAttribute, filenameMap[filename].importedHelperIndentifier, filenameMap[filename].styleModuleImportMapIdentifier diff --git a/src/replaceJsxExpressionContainer.js b/src/replaceJsxExpressionContainer.js index 1eb0b45..3faf4e6 100644 --- a/src/replaceJsxExpressionContainer.js +++ b/src/replaceJsxExpressionContainer.js @@ -5,16 +5,33 @@ import BabelTypes, { Identifier } from 'babel-types'; -export default (t: BabelTypes, styleNameAttribute: JSXAttribute, importedHelperIndentifier: Identifier, styleModuleImportMapIdentifier: Identifier): void => { +export default (t: BabelTypes, path: Object, styleNameAttribute: JSXAttribute, importedHelperIndentifier: Identifier, styleModuleImportMapIdentifier: Identifier): void => { const expressionContainerValue = styleNameAttribute.value; + const classNameAttribute = path.node.openingElement.attributes + .find((attribute) => { + return typeof attribute.name !== 'undefined' && attribute.name.name === 'className'; + }); + const classNameAttributeValue = classNameAttribute ? classNameAttribute.value.value : ''; + + if (classNameAttribute) { + path.node.openingElement.attributes.splice(path.node.openingElement.attributes.indexOf(classNameAttribute), 1); + } + + const styleNameExpression = t.callExpression( + importedHelperIndentifier, + [ + expressionContainerValue.expression, + styleModuleImportMapIdentifier + ] + ); styleNameAttribute.value = t.jSXExpressionContainer( - t.callExpression( - importedHelperIndentifier, - [ - expressionContainerValue.expression, - styleModuleImportMapIdentifier - ] - ) + classNameAttribute ? + t.binaryExpression( + '+', + t.stringLiteral(classNameAttributeValue + ' '), + styleNameExpression + ) : styleNameExpression ); + styleNameAttribute.name.name = 'className'; }; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/actual.js similarity index 72% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/actual.js index f284d12..cb49c7a 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/actual.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/actual.js @@ -5,4 +5,4 @@ const styleNameBar = 'bar.a-b'; const styleNameFoo = 'a-b';
; -
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/bar.css similarity index 100% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/bar.css rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/bar.css diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js similarity index 68% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js index 41d4f3e..e9f288f 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/expected.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/expected.js @@ -13,5 +13,5 @@ const _styleModuleImportMap = { const styleNameBar = 'bar.a-b'; const styleNameFoo = 'a-b'; -
; -
; +
; +
; diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/foo.css similarity index 100% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/foo.css rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/foo.css diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/options.json similarity index 100% rename from test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName bis/options.json rename to test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName (with already existing className)/options.json diff --git a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js index 41d4f3e..336e388 100644 --- a/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js +++ b/test/fixtures/react-css-modules/uses getClassName to resolve non-literal styleName/expected.js @@ -13,5 +13,5 @@ const _styleModuleImportMap = { const styleNameBar = 'bar.a-b'; const styleNameFoo = 'a-b'; -
; -
; +
; +
; From 0a407c64b3634e2dd33f372ede12b9a129d87dee Mon Sep 17 00:00:00 2001 From: Chris Gaudreau Date: Thu, 22 Dec 2016 05:40:05 -0400 Subject: [PATCH 05/10] feat: improve error messages (#21) --- src/getClassName.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/getClassName.js b/src/getClassName.js index f7f9e1c..214d5b6 100644 --- a/src/getClassName.js +++ b/src/getClassName.js @@ -22,11 +22,11 @@ const getClassNameForNamespacedStyleName = (styleName: string, styleModuleImport } if (!styleModuleImportMap[importName]) { - throw new Error('Import does not exist.'); + throw new Error('CSS module import does not exist.'); } if (!styleModuleImportMap[importName][moduleName]) { - throw new Error('Module does not exist.'); + throw new Error('CSS module does not exist.'); } return styleModuleImportMap[importName][moduleName]; @@ -53,7 +53,7 @@ export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportM const styleModuleMap: StyleModuleMapType = styleModuleImportMap[styleModuleImportMapKeys[0]]; if (!styleModuleMap[styleName]) { - throw new Error('Module cannot be resolved.'); + throw new Error('CSS module cannot be resolved.'); } return styleModuleMap[styleName]; From 178119dd85b08b69569e24d41c63a3f10880fb90 Mon Sep 17 00:00:00 2001 From: Johan de Koning Date: Fri, 9 Dec 2016 12:34:17 +0100 Subject: [PATCH 06/10] Make syntax parser configurable --- package.json | 1 + src/requireCssModule.js | 11 +++++++++++ .../resolves less stylesheets/actual.js | 4 ++++ .../resolves less stylesheets/bar.css | 1 + .../resolves less stylesheets/expected.js | 4 ++++ 5 files changed, 21 insertions(+) create mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/bar.css diff --git a/package.json b/package.json index 1b71b5c..3d0ce97 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "babel-types": "^6.19.0", "generic-names": "^1.0.2", "postcss": "^5.2.6", + "postcss-less": "^0.15.0", "postcss-modules": "^0.5.2", "postcss-modules-extract-imports": "^1.0.1", "postcss-modules-local-by-default": "^1.1.1", diff --git a/src/requireCssModule.js b/src/requireCssModule.js index 5624a4d..d38eb9e 100644 --- a/src/requireCssModule.js +++ b/src/requireCssModule.js @@ -27,8 +27,19 @@ const getTokens = (runner, cssSourceFilePath: string, filetypes): StyleModuleMap }; if (syntax) { +<<<<<<< 0a407c64b3634e2dd33f372ede12b9a129d87dee // eslint-disable-next-line import/no-dynamic-require, global-require options.syntax = require(syntax); +======= + // eslint-disable-next-line import/no-dynamic-require, global-require, no-console + // const parser = require(syntax); + + // eslint-disable-next-line import/no-dynamic-require, global-require, no-console + // console.log(parser); + + // eslint-disable-next-line import/no-dynamic-require, global-require + options.syntax = ScssSyntax; +>>>>>>> Make syntax parser configurable } const lazyResult = runner diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/actual.js b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js index 90aeb49..f1f6405 100644 --- a/test/fixtures/react-css-modules/resolves less stylesheets/actual.js +++ b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js @@ -1,3 +1,7 @@ +<<<<<<< 0a407c64b3634e2dd33f372ede12b9a129d87dee import './bar.less'; +======= +import './bar.css'; +>>>>>>> Make syntax parser configurable
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/bar.css b/test/fixtures/react-css-modules/resolves less stylesheets/bar.css new file mode 100644 index 0000000..077f6dd --- /dev/null +++ b/test/fixtures/react-css-modules/resolves less stylesheets/bar.css @@ -0,0 +1 @@ +a {} diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/expected.js b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js index f87c7c1..18d2717 100644 --- a/test/fixtures/react-css-modules/resolves less stylesheets/expected.js +++ b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js @@ -1,3 +1,7 @@ +<<<<<<< 0a407c64b3634e2dd33f372ede12b9a129d87dee import './bar.less'; +======= +import './bar.css'; +>>>>>>> Make syntax parser configurable
; From 7f914808ef31c2b1c53ad7e6d91c0845d326e276 Mon Sep 17 00:00:00 2001 From: Johan de Koning Date: Sun, 25 Dec 2016 04:57:47 +0100 Subject: [PATCH 07/10] Merged upstream --- package.json | 1 - src/requireCssModule.js | 11 ----------- .../resolves less stylesheets/actual.js | 4 ---- .../resolves less stylesheets/bar.css | 1 - .../resolves less stylesheets/expected.js | 4 ---- 5 files changed, 21 deletions(-) delete mode 100644 test/fixtures/react-css-modules/resolves less stylesheets/bar.css diff --git a/package.json b/package.json index 3d0ce97..1b71b5c 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "babel-types": "^6.19.0", "generic-names": "^1.0.2", "postcss": "^5.2.6", - "postcss-less": "^0.15.0", "postcss-modules": "^0.5.2", "postcss-modules-extract-imports": "^1.0.1", "postcss-modules-local-by-default": "^1.1.1", diff --git a/src/requireCssModule.js b/src/requireCssModule.js index d38eb9e..5624a4d 100644 --- a/src/requireCssModule.js +++ b/src/requireCssModule.js @@ -27,19 +27,8 @@ const getTokens = (runner, cssSourceFilePath: string, filetypes): StyleModuleMap }; if (syntax) { -<<<<<<< 0a407c64b3634e2dd33f372ede12b9a129d87dee // eslint-disable-next-line import/no-dynamic-require, global-require options.syntax = require(syntax); -======= - // eslint-disable-next-line import/no-dynamic-require, global-require, no-console - // const parser = require(syntax); - - // eslint-disable-next-line import/no-dynamic-require, global-require, no-console - // console.log(parser); - - // eslint-disable-next-line import/no-dynamic-require, global-require - options.syntax = ScssSyntax; ->>>>>>> Make syntax parser configurable } const lazyResult = runner diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/actual.js b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js index f1f6405..90aeb49 100644 --- a/test/fixtures/react-css-modules/resolves less stylesheets/actual.js +++ b/test/fixtures/react-css-modules/resolves less stylesheets/actual.js @@ -1,7 +1,3 @@ -<<<<<<< 0a407c64b3634e2dd33f372ede12b9a129d87dee import './bar.less'; -======= -import './bar.css'; ->>>>>>> Make syntax parser configurable
; diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/bar.css b/test/fixtures/react-css-modules/resolves less stylesheets/bar.css deleted file mode 100644 index 077f6dd..0000000 --- a/test/fixtures/react-css-modules/resolves less stylesheets/bar.css +++ /dev/null @@ -1 +0,0 @@ -a {} diff --git a/test/fixtures/react-css-modules/resolves less stylesheets/expected.js b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js index 18d2717..f87c7c1 100644 --- a/test/fixtures/react-css-modules/resolves less stylesheets/expected.js +++ b/test/fixtures/react-css-modules/resolves less stylesheets/expected.js @@ -1,7 +1,3 @@ -<<<<<<< 0a407c64b3634e2dd33f372ede12b9a129d87dee import './bar.less'; -======= -import './bar.css'; ->>>>>>> Make syntax parser configurable
; From c929f9e3ace70c8f25d5fcf04fca75a63541ad24 Mon Sep 17 00:00:00 2001 From: Johan de Koning Date: Sun, 25 Dec 2016 05:23:00 +0100 Subject: [PATCH 08/10] Updated the configuration section of the readme file --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 989af4f..76cc7ff 100644 --- a/README.md +++ b/README.md @@ -168,12 +168,32 @@ NODE_ENV=production ./test |Name|Description|Default| |---|---|---| |`generateScopedName`|Refer to [Generating scoped names](https://github.com/css-modules/postcss-modules#generating-scoped-names)|N/A (delegates default resolution to [postcss-modules](https://github.com/css-modules/postcss-modules))| +|`filetypes`|Configure [postcss syntax loaders](https://github.com/postcss/postcss#syntaxes) like sugerss, LESS and SCSS. |Optional. If not configured, only css is supported. 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). +### Configure syntax loaders + +Out of the box, only css files are supported. To add for example support for SCSS, perform the following two steps: + +1. Add the [postcss syntax loader](https://github.com/postcss/postcss#syntaxes) as dev 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. From d43e9b7423f1661cfa09d99a507c8c59eee2509f Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Fri, 6 Jan 2017 15:08:15 +0200 Subject: [PATCH 09/10] docs: improve wording --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 8623125..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) @@ -176,24 +177,23 @@ Missing a configuration? [Raise an issue](https://github.com/gajus/babel-plugin- > Note: > The default configuration should work out of the box with the [css-loader](https://github.com/webpack/css-loader). -### Configure syntax loaders +### Configurate syntax loaders -Out of the box, only css files are supported. To add for example support for SCSS, perform the following two steps: +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 dev dependency: - -```bash -npm install postcss-scss --save-dev -``` - -2. Add a filetype syntax mapping to the babel plugin configuration - -```json -"filetypes": { - ".scss": "postcss-scss" -} -``` +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 From 945a0626343c3f2fbba7371a8c4b5ab5cfbe4bde Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Fri, 6 Jan 2017 15:10:30 +0200 Subject: [PATCH 10/10] fix: add a missing comma --- src/requireCssModule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requireCssModule.js b/src/requireCssModule.js index a107a16..28e8703 100644 --- a/src/requireCssModule.js +++ b/src/requireCssModule.js @@ -46,7 +46,7 @@ const getTokens = (runner, cssSourceFilePath: string, filetypes): StyleModuleMap type OptionsType = {| filetypes: Object, - generateScopedName?: string + generateScopedName?: string, context?: string |};