Skip to content

Commit b83fc85

Browse files
authored
Implement the plugin as a babel macro (#142)
1 parent a66bb0e commit b83fc85

33 files changed

+2074
-267
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ minimizes the runtime cost of css-in-js dramatically by parsing your styles with
4343
- [vue styled](https://github.com/tkh44/emotion/tree/master/docs/vue-styled.md)
4444

4545
- [Usage with CSS Modules](https://github.com/tkh44/emotion/tree/master/docs/css-modules.md)
46+
- [Usage with babel-macros](https://github.com/tkh44/emotion/tree/master/docs/babel-macros.md)

docs/babel-macros.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
## Usage with babel-macros
2+
3+
Instead of using the emotion's babel plugin, you can use emotion with [`babel-macros`](https://github.com/kentcdodds/babel-macros). Add `babel-macros` to your babel config and import whatever you want from emotion but add `/macro` to the end. The macro is currently the same as inline mode. Currently every API except for the css prop is supported by the macro.
4+
5+
```jsx
6+
import styled from 'emotion/react/macro'
7+
import { css, keyframes, fontFace, injectGlobal, flush, hydrate } from 'emotion/macro'
8+
import vueStyled from 'emotion/vue/macro'
9+
```
10+
11+
For some context, check out this [issue](https://github.com/facebookincubator/create-react-app/issues/2730).

macro.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./lib/macro')

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
"lib",
1111
"react",
1212
"server.js",
13-
"vue.js",
14-
"dist/DO-NOT-USE.min.js"
13+
"vue",
14+
"dist/DO-NOT-USE.min.js",
15+
"macro.js"
1516
],
1617
"scripts": {
1718
"build": "babel src -d lib",
@@ -44,6 +45,7 @@
4445
"babel-core": "^6.24.1",
4546
"babel-eslint": "^7.2.3",
4647
"babel-jest": "^20.0.3",
48+
"babel-macros": "^0.5.2",
4749
"babel-preset-env": "^1.5.1",
4850
"babel-preset-flow": "^6.23.0",
4951
"babel-preset-react": "^6.24.1",

react/macro.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('../lib/react/macro')

src/babel-utils.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { keys } from './utils'
2+
import forEach from '@arr/foreach'
3+
4+
export function getIdentifierName (path, t) {
5+
const parent = path.findParent(p => p.isVariableDeclarator())
6+
return parent && t.isIdentifier(parent.node.id) ? parent.node.id.name : ''
7+
}
8+
9+
export function getRuntimeImportPath (path, t) {
10+
const binding = path.scope.getBinding(path.node.name)
11+
if (!t.isImportDeclaration(binding.path.parentPath)) {
12+
throw binding.path.buildCodeFrameError(
13+
'the emotion macro must be imported with es modules'
14+
)
15+
}
16+
const importPath = binding.path.parentPath.node.source.value
17+
return importPath.match(/(.*)\/macro/)[1]
18+
}
19+
20+
export function buildMacroRuntimeNode (path, state, importName, t) {
21+
const runtimeImportPath = getRuntimeImportPath(path, t)
22+
if (state.emotionImports === undefined) state.emotionImports = {}
23+
if (state.emotionImports[runtimeImportPath] === undefined) { state.emotionImports[runtimeImportPath] = {} }
24+
if (state.emotionImports[runtimeImportPath][importName] === undefined) {
25+
state.emotionImports[runtimeImportPath][
26+
importName
27+
] = path.scope.generateUidIdentifier(path.node.name)
28+
}
29+
return state.emotionImports[runtimeImportPath][importName]
30+
}
31+
32+
export function addRuntimeImports (state, t) {
33+
if (state.emotionImports === undefined) return
34+
forEach(keys(state.emotionImports), importPath => {
35+
const importSpecifiers = []
36+
forEach(keys(state.emotionImports[importPath]), importName => {
37+
const identifier = state.emotionImports[importPath][importName]
38+
if (importName === 'default') {
39+
importSpecifiers.push(t.importDefaultSpecifier(identifier))
40+
} else {
41+
importSpecifiers.push(
42+
t.importSpecifier(identifier, t.identifier(importName))
43+
)
44+
}
45+
})
46+
state.file.path.node.body.unshift(
47+
t.importDeclaration(importSpecifiers, t.stringLiteral(importPath))
48+
)
49+
})
50+
state.emotionImports = undefined
51+
}

0 commit comments

Comments
 (0)