Skip to content

Commit

Permalink
fix: _JSXStyle import is not found (#724)
Browse files Browse the repository at this point in the history
* fix: _JSXStyle import is not found

* create imports on program enter

* leverage generated uid from addDefault

* remove unused imports

* remove imports for non css.resolve cases
  • Loading branch information
huozhi authored Aug 2, 2021
1 parent ffd11ca commit 2798620
Show file tree
Hide file tree
Showing 14 changed files with 111 additions and 51 deletions.
40 changes: 26 additions & 14 deletions src/_utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'path'
import { addDefault } from '@babel/helper-module-imports';
import { addDefault } from '@babel/helper-module-imports'
import * as t from '@babel/types'
import _hashString from 'string-hash'
import { SourceMapGenerator } from 'source-map'
Expand All @@ -9,8 +9,8 @@ import transform from './lib/style-transform'
import {
STYLE_ATTRIBUTE,
GLOBAL_ATTRIBUTE,
STYLE_COMPONENT_ID,
STYLE_COMPONENT,
STYLE_COMPONENT_ID,
STYLE_COMPONENT_DYNAMIC
} from './_constants'

Expand Down Expand Up @@ -258,7 +258,11 @@ export const getJSXStyleInfo = (expr, scope) => {
}
}

export const computeClassNames = (styles, externalJsxId) => {
export const computeClassNames = (
styles,
externalJsxId,
styleComponentImportName
) => {
if (styles.length === 0) {
return {
className: externalJsxId
Expand Down Expand Up @@ -297,7 +301,10 @@ export const computeClassNames = (styles, externalJsxId) => {
// _JSXStyle.dynamic([ ['1234', [props.foo, bar, fn(props)]], ... ])
const dynamic = t.callExpression(
// Callee: _JSXStyle.dynamic
t.memberExpression(t.identifier(STYLE_COMPONENT), t.identifier('dynamic')),
t.memberExpression(
t.identifier(styleComponentImportName),
t.identifier(STYLE_COMPONENT_DYNAMIC)
),
// Arguments
[
t.arrayExpression(
Expand Down Expand Up @@ -380,7 +387,12 @@ export const cssToBabelType = css => {
return t.cloneDeep(css)
}

export const makeStyledJsxTag = (id, transformedCss, expressions = []) => {
export const makeStyledJsxTag = (
id,
transformedCss,
expressions = [],
styleComponentImportName
) => {
const css = cssToBabelType(transformedCss)

const attributes = [
Expand All @@ -402,8 +414,8 @@ export const makeStyledJsxTag = (id, transformedCss, expressions = []) => {
}

return t.jSXElement(
t.jSXOpeningElement(t.jSXIdentifier(STYLE_COMPONENT), attributes),
t.jSXClosingElement(t.jSXIdentifier(STYLE_COMPONENT)),
t.jSXOpeningElement(t.jSXIdentifier(styleComponentImportName), attributes),
t.jSXClosingElement(t.jSXIdentifier(styleComponentImportName)),
[t.jSXExpressionContainer(css)]
)
}
Expand Down Expand Up @@ -622,13 +634,9 @@ export const booleanOption = opts => {
}

export const createReactComponentImportDeclaration = state => {
addDefault(
state.file.path,
typeof state.opts.styleModule === 'string'
? state.opts.styleModule
: 'styled-jsx/style',
{ nameHint: STYLE_COMPONENT}
)
return addDefault(state.file.path, state.styleModule, {
nameHint: STYLE_COMPONENT
}).name
}

export const setStateOptions = state => {
Expand All @@ -650,6 +658,10 @@ export const setStateOptions = state => {
vendorPrefixes: state.opts.vendorPrefixes
})
}
state.styleModule =
typeof state.opts.styleModule === 'string'
? state.opts.styleModule
: 'styled-jsx/style'
}

export function log(message) {
Expand Down
29 changes: 15 additions & 14 deletions src/babel-external.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import * as t from '@babel/types'

import { STYLE_COMPONENT } from './_constants'

import {
getJSXStyleInfo,
processCss,
Expand All @@ -10,7 +8,6 @@ import {
getScope,
computeClassNames,
makeStyledJsxTag,
createReactComponentImportDeclaration,
setStateOptions
} from './_utils'

Expand All @@ -23,7 +20,8 @@ export function processTaggedTemplateExpression({
splitRules,
plugins,
vendorPrefixes,
sourceMaps
sourceMaps,
styleComponentImportName
}) {
const templateLiteral = path.get('quasi')
let scope
Expand All @@ -39,7 +37,11 @@ export function processTaggedTemplateExpression({

const stylesInfo = getJSXStyleInfo(templateLiteral, scope)

const { staticClassName, className } = computeClassNames([stylesInfo])
const { staticClassName, className } = computeClassNames(
[stylesInfo],
undefined,
styleComponentImportName
)

const styles = processCss(
{
Expand All @@ -64,7 +66,7 @@ export function processTaggedTemplateExpression({
t.objectExpression([
t.objectProperty(
t.identifier('styles'),
makeStyledJsxTag(hash, css, expressions)
makeStyledJsxTag(hash, css, expressions, styleComponentImportName)
),
t.objectProperty(t.identifier('className'), className)
])
Expand Down Expand Up @@ -212,21 +214,20 @@ export const visitor = {
: process.env.NODE_ENV === 'production',
plugins: state.plugins,
vendorPrefixes,
sourceMaps
sourceMaps,
styleComponentImportName: state.styleComponentImportName
})
})
)

// When using the `resolve` helper we need to add an import
// for the _JSXStyle component `styled-jsx/style`
if (
hasJSXStyle &&
taggedTemplateExpressions.resolve.length > 0 &&
!state.hasInjectedJSXStyle &&
!path.scope.hasBinding(STYLE_COMPONENT)
) {
const useResolve =
hasJSXStyle && taggedTemplateExpressions.resolve.length > 0

if (useResolve) {
state.file.hasCssResolve = true
state.hasInjectedJSXStyle = true
createReactComponentImportDeclaration(state)
}
})

Expand Down
45 changes: 34 additions & 11 deletions src/babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import {
setStateOptions
} from './_utils'

import { STYLE_COMPONENT } from './_constants'

export default function({ types: t }) {
const jsxVisitors = {
JSXOpeningElement(path, state) {
Expand All @@ -43,7 +41,7 @@ export default function({ types: t }) {
if (
name &&
name !== 'style' &&
name !== STYLE_COMPONENT &&
name !== state.styleComponentImportName &&
(name.charAt(0) !== name.charAt(0).toUpperCase() ||
Object.values(path.scope.bindings).some(binding =>
binding.referencePaths.some(r => r === tag)
Expand Down Expand Up @@ -172,7 +170,8 @@ export default function({ types: t }) {
if (state.styles.length > 0 || externalJsxId) {
const { staticClassName, className } = computeClassNames(
state.styles,
externalJsxId
externalJsxId,
state.styleComponentImportName
)
state.className = className
state.staticClassName = staticClassName
Expand Down Expand Up @@ -224,7 +223,9 @@ export default function({ types: t }) {
) {
const [id, css] = state.externalStyles.shift()

path.replaceWith(makeStyledJsxTag(id, css))
path.replaceWith(
makeStyledJsxTag(id, css, [], state.styleComponentImportName)
)
return
}

Expand All @@ -247,7 +248,14 @@ export default function({ types: t }) {
splitRules
})

path.replaceWith(makeStyledJsxTag(hash, css, expressions))
path.replaceWith(
makeStyledJsxTag(
hash,
css,
expressions,
state.styleComponentImportName
)
)
}
}
}
Expand Down Expand Up @@ -283,9 +291,14 @@ export default function({ types: t }) {
state.hasJSXStyle = null
state.ignoreClosing = null
state.file.hasJSXStyle = false

state.file.hasCssResolve = false
setStateOptions(state)

// `addDefault` will generate unique id for the scope
state.styleComponentImportName = createReactComponentImportDeclaration(
state
)

// we need to beat the arrow function transform and
// possibly others so we traverse from here or else
// dynamic values in classNames could be incorrect
Expand All @@ -294,19 +307,29 @@ export default function({ types: t }) {
// Transpile external styles
path.traverse(externalStylesVisitor, state)
},
exit({ scope }, state) {
exit(path, state) {
// For source that didn't really need styled-jsx/style imports,
// remove the injected import at the beginning
if (!state.file.hasJSXStyle && !state.file.hasCssResolve) {
path.traverse({
ImportDeclaration(importPath) {
if (importPath.node.source.value === state.styleModule) {
importPath.remove()
}
}
})
}

if (
!(
state.file.hasJSXStyle &&
!state.hasInjectedJSXStyle &&
!scope.hasBinding(STYLE_COMPONENT)
!path.scope.hasBinding(state.styleComponentImportName)
)
) {
return
}

state.hasInjectedJSXStyle = true
createReactComponentImportDeclaration(state)
}
}
}
Expand Down
11 changes: 4 additions & 7 deletions src/macro.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import {
setStateOptions,
createReactComponentImportDeclaration
} from './_utils'
import { STYLE_COMPONENT } from './_constants'

export default createMacro(styledJsxMacro)

function styledJsxMacro({ references, state }) {
setStateOptions(state)
state.styleComponentImportName = createReactComponentImportDeclaration(state)

// Holds a reference to all the lines where strings are tagged using the `css` tag name.
// We print a warning at the end of the macro in case there is any reference to css,
Expand Down Expand Up @@ -94,15 +94,12 @@ function styledJsxMacro({ references, state }) {
: process.env.NODE_ENV === 'production',
plugins: state.plugins,
vendorPrefixes: state.opts.vendorPrefixes,
sourceMaps: state.opts.sourceMaps
sourceMaps: state.opts.sourceMaps,
styleComponentImportName: state.styleComponentImportName
})

if (
!state.hasInjectedJSXStyle &&
!path.scope.hasBinding(STYLE_COMPONENT)
) {
if (!state.hasInjectedJSXStyle) {
state.hasInjectedJSXStyle = true
createReactComponentImportDeclaration(state)
}
})
})
Expand Down
2 changes: 0 additions & 2 deletions test/babel6/snapshots/index.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,12 @@ Generated by [AVA](https://ava.li).
`import _JSXStyle from "styled-jsx/style";␊
export default class {␊
render() {␊
return <div className={"jsx-2101845350"}>␊
<p className={"jsx-2101845350"}>test</p>␊
<_JSXStyle id={"2101845350"}>{"p.jsx-2101845350{color:red;}"}</_JSXStyle>␊
</div>;␊
}␊
}`

## works with css tagged template literals in the same file
Expand Down
Binary file modified test/babel6/snapshots/index.js.snap
Binary file not shown.
Binary file modified test/babel6/snapshots/plugins.js.snap
Binary file not shown.
4 changes: 1 addition & 3 deletions test/fixtures/class.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export default class {

render () {
render() {
return (
<div>
<p>test</p>
Expand All @@ -12,5 +11,4 @@ export default class {
</div>
)
}

}
13 changes: 13 additions & 0 deletions test/fixtures/conflicts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const _JSXStyle = '_JSXStyle-literal'
export default function() {
return (
<div>
<p>test</p>
<style jsx>{`
p {
color: red;
}
`}</style>
</div>
)
}
5 changes: 5 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ test('works with dynamic element in class', async t => {
t.snapshot(code)
})

test('works with existing identifier for _JSXStyle', async t => {
const { code } = await transform('./fixtures/conflicts.js')
t.snapshot(code)
})

test('does not transpile nested style tags', async t => {
const { message } = await t.throwsAsync(() =>
transform('./fixtures/nested-style-tags.js')
Expand Down
Binary file modified test/snapshots/external.js.snap
Binary file not shown.
13 changes: 13 additions & 0 deletions test/snapshots/index.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,19 @@ Generated by [AVA](https://ava.li).
};`

## works with existing identifier for \_JSXStyle

> Snapshot 1
`import _JSXStyle2 from "styled-jsx/style";␊
export const _JSXStyle = '_JSXStyle-literal';␊
export default function () {␊
return <div className={"jsx-319553417"}>␊
<p className={"jsx-319553417"}>test</p>␊
<_JSXStyle2 id={"319553417"}>{"p.jsx-319553417{color:red;}"}</_JSXStyle2>␊
</div>;␊
}`

## works with expressions in template literals

> Snapshot 1
Expand Down
Binary file modified test/snapshots/index.js.snap
Binary file not shown.
Binary file modified test/snapshots/plugins.js.snap
Binary file not shown.

0 comments on commit 2798620

Please sign in to comment.