Skip to content

Commit e3829d2

Browse files
authored
fix css prop transpilation for stable server-side rendering (#225)
* run the css prop transpiler before other transforms * fix css prop in ssr mode
1 parent 57322cc commit e3829d2

File tree

11 files changed

+400
-101
lines changed

11 files changed

+400
-101
lines changed

src/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,15 @@ export default function({ types: t }) {
1010
return {
1111
inherits: syntax,
1212
visitor: {
13-
JSXAttribute(path, state) {
14-
transpileCssProp(t)(path, state)
13+
Program(path, state) {
14+
path.traverse(
15+
{
16+
JSXAttribute(path, state) {
17+
transpileCssProp(t)(path, state)
18+
},
19+
},
20+
state
21+
)
1522
},
1623
CallExpression(path, state) {
1724
displayNameAndId(t)(path, state)

src/utils/detectors.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ export const isValidTopLevelImport = x =>
1010

1111
const localNameCache = {}
1212

13-
const importLocalName = (name, state) => {
13+
export const importLocalName = (name, state, bypassCache = false) => {
1414
const cacheKey = name + state.file.opts.filename
1515

16-
if (localNameCache[cacheKey]) {
16+
if (!bypassCache && localNameCache[cacheKey]) {
1717
return localNameCache[cacheKey]
1818
}
1919

@@ -45,7 +45,9 @@ const importLocalName = (name, state) => {
4545
},
4646
},
4747
})
48+
4849
localNameCache[cacheKey] = localName
50+
4951
return localName
5052
}
5153

src/visitors/transpileCssProp.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Most of this code was taken from @satya164's babel-plugin-css-prop
22
// @see https://github.com/satya164/babel-plugin-css-prop
33
import { addDefault } from '@babel/helper-module-imports'
4+
import { importLocalName } from '../utils/detectors'
45
import { useCssProp } from '../utils/options'
56

67
const getName = (node, t) => {
@@ -9,9 +10,7 @@ const getName = (node, t) => {
910
return `${getName(node.object, t)}.${node.property.name}`
1011
}
1112
throw path.buildCodeFrameError(
12-
`Cannot infer name from node with type "${
13-
node.type
14-
}". 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!`
13+
`Cannot infer name 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!`
1514
)
1615
}
1716

@@ -20,27 +19,36 @@ export default t => (path, state) => {
2019
if (path.node.name.name !== 'css') return
2120

2221
const program = state.file.path
22+
2323
// state.customImportName is passed through from styled-components/macro if it's used
2424
// since the macro also inserts the import
25-
let importName = state.customImportName
26-
// Insert import if it doesn't exist yet
25+
let importName =
26+
state.customImportName || t.identifier(importLocalName('default', state))
27+
2728
const { bindings } = program.scope
28-
if (!importName || !bindings[importName.name]) {
29-
importName = addDefault(path, 'styled-components', {
30-
nameHint: importName ? importName.name : 'styled',
29+
30+
// Insert import if it doesn't exist yet
31+
if (!bindings[importName.name]) {
32+
addDefault(path, 'styled-components', {
33+
nameHint: 'styled',
3134
})
35+
36+
importName = t.identifier(importLocalName('default', state, true))
3237
}
33-
if (!state.customImportName) state.customImportName = importName
3438

3539
const elem = path.parentPath
3640
const name = getName(elem.node.name, t)
3741
const id = path.scope.generateUidIdentifier(
3842
'Styled' + name.replace(/^([a-z])/, (match, p1) => p1.toUpperCase())
3943
)
4044

41-
const styled = t.callExpression(importName, [
42-
/^[a-z]/.test(name) ? t.stringLiteral(name) : t.identifier(name),
43-
])
45+
let styled
46+
47+
if (/^[a-z]/.test(name)) {
48+
styled = t.memberExpression(importName, t.identifier(name))
49+
} else {
50+
styled = t.callExpression(importName, [t.identifier(name)])
51+
}
4452

4553
let css
4654

test/fixtures/transpile-css-prop-add-import/output.js

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
"use strict";
22

3-
function _templateObject() {
4-
var data = _taggedTemplateLiteral(["\n width: 35em;\n "]);
5-
6-
_templateObject = function _templateObject() {
7-
return data;
8-
};
9-
10-
return data;
11-
}
12-
13-
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
14-
153
Object.defineProperty(exports, "__esModule", {
164
value: true
175
});
@@ -27,7 +15,18 @@ var _config = _interopRequireDefault(require("../../../config"));
2715

2816
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
2917

30-
// @flow
18+
function _templateObject() {
19+
var data = _taggedTemplateLiteral(["\n width: 35em;\n "]);
20+
21+
_templateObject = function _templateObject() {
22+
return data;
23+
};
24+
25+
return data;
26+
}
27+
28+
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
29+
3130
var _default = function _default() {
3231
return <_StyledDiv>
3332
<_Card.default>
@@ -43,4 +42,4 @@ var _default = function _default() {
4342

4443
exports["default"] = _default;
4544

46-
var _StyledDiv = (0, _styledComponents["default"])("div")(_templateObject());
45+
var _StyledDiv = _styledComponents["default"].div(_templateObject());

test/fixtures/transpile-css-prop-add-require/.babelrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2+
"presets": [["@babel/preset-env", { "modules": "commonjs" }]],
23
"plugins": [
3-
"transform-es2015-modules-commonjs",
44
[
55
"../../../src",
66
{
@@ -12,4 +12,4 @@
1212
}
1313
]
1414
]
15-
}
15+
}

test/fixtures/transpile-css-prop-add-require/output.js

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,30 @@
33
Object.defineProperty(exports, "__esModule", {
44
value: true
55
});
6+
exports["default"] = void 0;
67

7-
var _styledComponents = require("styled-components");
8+
var _styledComponents = _interopRequireDefault(require("styled-components"));
89

9-
var _styledComponents2 = _interopRequireDefault(_styledComponents);
10+
var _react = _interopRequireDefault(require("react"));
1011

11-
var _react = require("react");
12+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
1213

13-
var _react2 = _interopRequireDefault(_react);
14+
function _templateObject() {
15+
var data = _taggedTemplateLiteral(["\n width: 35em;\n "]);
1416

15-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17+
_templateObject = function _templateObject() {
18+
return data;
19+
};
1620

17-
// @flow
18-
exports.default = () => <_StyledDiv />;
21+
return data;
22+
}
1923

20-
var _StyledDiv = (0, _styledComponents2.default)("div")`
21-
width: 35em;
22-
`;
24+
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
25+
26+
var _default = function _default() {
27+
return <_StyledDiv />;
28+
};
29+
30+
exports["default"] = _default;
31+
32+
var _StyledDiv = _styledComponents["default"].div(_templateObject());
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"presets": ["@babel/preset-env"],
3+
"plugins": [
4+
[
5+
"../../../src",
6+
{
7+
"ssr": true,
8+
"displayName": true,
9+
"transpileTemplateLiterals": true,
10+
"minify": true,
11+
"cssProp": true
12+
}
13+
]
14+
]
15+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import styled from 'styled-components'
2+
3+
/**
4+
* control
5+
*/
6+
7+
const Thing = styled.div`
8+
color: red;
9+
`
10+
11+
const Thing2 = styled(Thing)`
12+
background: blue;
13+
`
14+
15+
/*
16+
* Basic fixtures
17+
*/
18+
19+
const StaticString = p => <p css="flex: 1;">A</p>
20+
21+
const StaticTemplate = p => (
22+
<p
23+
css={`
24+
flex: 1;
25+
`}
26+
>
27+
A
28+
</p>
29+
)
30+
31+
const ObjectProp = p => <p css={{ color: 'blue' }}>A</p>
32+
33+
const NoChildren = p => <p css="flex: 1;" />
34+
35+
const CssHelperProp = p => (
36+
<p
37+
css={css`
38+
color: blue;
39+
`}
40+
>
41+
A
42+
</p>
43+
)
44+
45+
/*
46+
* Dynamic prop
47+
*/
48+
49+
const CustomComp = p => <Paragraph css="flex: 1">H</Paragraph>
50+
51+
const DynamicProp = p => <p css={props.cssText}>H</p>
52+
53+
const LocalInterpolation = p => (
54+
<p
55+
css={`
56+
background: ${props.bg};
57+
`}
58+
>
59+
H
60+
</p>
61+
)
62+
63+
const FuncInterpolation = p => (
64+
<p
65+
css={`
66+
color: ${props => props.theme.a};
67+
`}
68+
>
69+
H
70+
</p>
71+
)
72+
73+
const radius = 10
74+
const GlobalInterpolation = p => (
75+
<p
76+
css={`
77+
border-radius: ${radius}px;
78+
`}
79+
>
80+
H
81+
</p>
82+
)
83+
84+
const LocalCssHelperProp = p => (
85+
<p
86+
css={css`
87+
color: ${p.color};
88+
`}
89+
>
90+
A
91+
</p>
92+
)
93+
94+
const DynamicCssHelperProp = p => (
95+
<p
96+
css={css`
97+
color: ${props => props.theme.color};
98+
`}
99+
>
100+
A
101+
</p>
102+
)
103+
104+
const CustomCompWithDot = p => <Button.Ghost css="flex: 1">H</Button.Ghost>
105+
106+
const NestedCompWithDot = p => (
107+
<Button.Ghost.New css="flex: 1">H</Button.Ghost.New>
108+
)

0 commit comments

Comments
 (0)