Repository: styled-components/babel-plugin-styled-components (js)

Issue:
CSS prop is breaking build when component comes from imported object
**Problem**

When trying to add `css` to a component that comes from a different file from inside an object, an error gets thrown with the message `Uncaught ReferenceError: Icons is not defined`. Strangely the error only occurs in the production build. In development-mode everything is working fine. Also when I move the content of the `icons.tsx` inside the `app.tsx` everything is working as expected as well.

**Setup**
```
// icons.tsx
import React from "react";

const icons = { Foo: (props: any) => <div {...props}>Foo</div> };

export default icons;
```

```
// app.tsx
import React from "react";
import { css } from "styled-components/macro";
import Icons from "./icons";

const someCss = css` background: purple;`;

const App: React.FC = () => { return <Icons.Foo css={someCss} />; };
```
Repo with an example setup: https://github.com/dlehmhus/styled-components-with-macro-example

Pull request:
preserve structure of JSX member expressions in generated ast nodes
this makes sure that other babel transformations that rename variables will be able to process the ast nodes created by this plugin

fixes #240

Patch:
diff --git a/package.json b/package.json
index 81c300a..35f6bd9 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
     "@babel/cli": "^7.4.4",
     "@babel/core": "^7.4.5",
     "@babel/plugin-proposal-class-properties": "^7.4.4",
+    "@babel/plugin-transform-modules-commonjs": "^7.10.4",
     "@babel/preset-env": "^7.4.5",
     "babel-core": "7.0.0-bridge.0",
     "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
diff --git a/src/visitors/transpileCssProp.js b/src/visitors/transpileCssProp.js
index a0bdf73..f6e36ee 100644
--- a/src/visitors/transpileCssProp.js
+++ b/src/visitors/transpileCssProp.js
@@ -16,6 +16,16 @@ const getName = (node, t) => {
   )
 }
 
+const getNameExpression = (node, t) => {
+  if (typeof node.name === 'string') return t.identifier(node.name)
+  if (t.isJSXMemberExpression(node)) {
+    return t.memberExpression(getNameExpression(node.object, t), t.identifier(node.property.name))
+  }
+  throw path.buildCodeFrameError(
+    `Cannot infer name expression from node with type "${node.type}". Please submit an issue at github.com/styled-components/babel-plugin-styled-components with your code so we can take a look at your use case!`
+  )
+}
+
 export default t => (path, state) => {
   if (!useCssProp(state)) return
   if (path.node.name.name !== 'css') return
@@ -41,6 +51,7 @@ export default t => (path, state) => {
 
   const elem = path.parentPath
   const name = getName(elem.node.name, t)
+  const nameExpression = getNameExpression(elem.node.name, t);
   const id = path.scope.generateUidIdentifier(
     'Styled' + name.replace(/^([a-z])/, (match, p1) => p1.toUpperCase())
   )
@@ -51,7 +62,7 @@ export default t => (path, state) => {
   if (TAG_NAME_REGEXP.test(name)) {
     styled = t.callExpression(importName, [t.stringLiteral(name)])
   } else {
-    styled = t.callExpression(importName, [t.identifier(name)])
+    styled = t.callExpression(importName, [nameExpression])
 
     if (bindings[name] && !t.isImportDeclaration(bindings[name].path.parent)) {
       injector = nodeToInsert =>


Test patch:
diff --git a/test/fixtures/transformed-imports-with-jsx-member-expressions/.babelrc b/test/fixtures/transformed-imports-with-jsx-member-expressions/.babelrc
new file mode 100644
index 0000000..75ba23a
--- /dev/null
+++ b/test/fixtures/transformed-imports-with-jsx-member-expressions/.babelrc
@@ -0,0 +1,8 @@
+{
+    "plugins": [
+      ["@babel/plugin-transform-modules-commonjs"],
+      [
+        "../../../src"
+      ]
+    ]
+  }
diff --git a/test/fixtures/transformed-imports-with-jsx-member-expressions/code.js b/test/fixtures/transformed-imports-with-jsx-member-expressions/code.js
new file mode 100644
index 0000000..c6e94d5
--- /dev/null
+++ b/test/fixtures/transformed-imports-with-jsx-member-expressions/code.js
@@ -0,0 +1,11 @@
+import React from "react";
+import { css } from "styled-components";
+import Icons from "./icons";
+
+const someCss = css` background: purple;`;
+
+const App1 = () => { return <Icons css={someCss} />; };
+
+const App2 = () => { return <Icons.Foo css={someCss} />; };
+
+const App3 = () => { return <Icons.Foo.Bar css={someCss} />; };
diff --git a/test/fixtures/transformed-imports-with-jsx-member-expressions/output.js b/test/fixtures/transformed-imports-with-jsx-member-expressions/output.js
new file mode 100644
index 0000000..e8fa2bd
--- /dev/null
+++ b/test/fixtures/transformed-imports-with-jsx-member-expressions/output.js
@@ -0,0 +1,42 @@
+"use strict";
+
+var _styledComponents = _interopRequireWildcard(require("styled-components"));
+
+var _react = _interopRequireDefault(require("react"));
+
+var _icons = _interopRequireDefault(require("./icons"));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
+
+const someCss = (0, _styledComponents.css)([" background:purple;"]);
+
+var _StyledIcons = (0, _styledComponents.default)(_icons.default).withConfig({
+  displayName: "code___StyledIcons",
+  componentId: "sc-1wxehft-0"
+})(["", ""], someCss);
+
+const App1 = () => {
+  return <_StyledIcons />;
+};
+
+var _StyledIconsFoo = (0, _styledComponents.default)(_icons.default.Foo).withConfig({
+  displayName: "code___StyledIconsFoo",
+  componentId: "sc-1wxehft-1"
+})(["", ""], someCss);
+
+const App2 = () => {
+  return <_StyledIconsFoo />;
+};
+
+var _StyledIconsFooBar = (0, _styledComponents.default)(_icons.default.Foo.Bar).withConfig({
+  displayName: "code___StyledIconsFooBar",
+  componentId: "sc-1wxehft-2"
+})(["", ""], someCss);
+
+const App3 = () => {
+  return <_StyledIconsFooBar />;
+};