파크로그
article thumbnail

Styled-components css prop

현재 사이드프로젝트를 진행하면서 styled-components 에서 css prop 을 사용하고 있습니다.

css prop 은 Styled components v4 부터 지원하게 되었는데요, 사실 @emotion 에서 사용하던 방식이라고 합니다.

Styled-components 와 @emotion 이 경쟁관계를 가져가면서 css prop 을 추가적으로 지원하게 된 셈인데요, HTML 태그를 명시적으로 확인할 수 있고, 태그를 단순 반복으로 생성하는 styled 방식에서 벗어나 새로운 방식을 사용해보기 위해 도입하였습니다.

// 이 코드는

<div
  css={`
    background: papayawhip;
    color: ${props => props.theme.colors.text};
  `}
/>
<Button
  css="padding: 0.5em 1em;"
/>

// 아래 코드와 동일합니다.

import styled from 'styled-components';

const StyledDiv = styled.div`
  background: papayawhip;
  color: ${props => props.theme.colors.text};
`

const StyledButton = styled(Button)`
  padding: 0.5em 1em;
`

<StyledDiv />
<StyledButton />

프로젝트에서 css prop 을 채택하여 사용하고 있는 중에, 아래와 같은 코드를 작성했었습니다.

그런데 처음 보는 에러메세지를 만났습니다.

const ObjectInterpolationMember = p => {
  const theme = useTheme()
  const color = 'red'

  return (
    <p
      css={{
        color: theme.colors[color],
      }}
    >
      H
    </p>
  )
}

 

 

ObjectProperty 의 property key 는 Identifier, StringLiteral, NumericLiteral, … 등의 타입으로 예측되는데, MemberExpression 을 받았다는 오류였습니다.

무슨 문제인지 처음엔 당황했습니다. 위 코드에서 쓰여지는 문법중 잘못된 것은 없어보였고, 다소 생소한 node type 에 대한 에러였기 때문입니다.

babel-loader 가 빌드를 실패했고, 에러가 발생한 곳은 @babel/types 이었습니다. 트랜스파일하는 과정에서 생기는 문제일 것이라 생각이 들어 css prop 을 처리하는 플러그인인 babel-plugin-styled-components 코드를 들여다 보았습니다.

 

babel-plugin-styled-components 를 통해 트랜스파일 된 코드가 babel-loader 를 통해 validate 를 거치는 과정에서 오류가 발생했고, 제가 작성한 코드는 color: theme.colors[color] 로, ObjectProperty type 입니다.

실제 오류가 났던 부분을 타고 올라가보았을때, @babel/types/lib/definitions/core.js 에서 ObjectProperty 타입을 정의하고 있고, property key 가 어떤 타입이어야 하는지를 정의해놓았습니다.

 

property.key 가 MemberExpression 이어서 생긴 문제이므로 property.key 가 어느 곳에서 MemberExpression 으로 바뀌고 있다라는 점은 추측할 수 있었고, 트랜스파일을 담당하는 파일을 찾아, css prop 을 사용하면서 ObjectExpression 을 사용했기 때문에 해당 줄 ( isObjectExpression(css) ) 부터 차례대로 읽어내려가기 시작했습니다.

 

css 프로퍼티들을 reduce 를 통해서 프로퍼티 키를 interpolations 하는 과정을 거치는데, 오류가 났던 케이스를 통해 확인해보니 property.key 를 MemberExpression 으로 보간하는 코드는 한 곳밖에 없었습니다.

 

다양한 조건으로 예외처리를 하고 있었는데, 조건문에서 예외로 처리하는 부분에서 제대로 걸러내지 못해서 생기는 오류였습니다. 오류가 났던 코드의 property.value 를 표현한 타입에 맞춰 적절한 예외코드 하나를 추가하여 에러를 제거하였습니다.

 

 

Pull Request 링크

 

code

output

 

후기

첫 오픈소스 PR 은 아닙니다, 이전에 Babel 을 사용하면서 문서를 읽다가, 문서의 링크가 깨진 것을 확인한 적이 있습니다.

글을 읽거나 영상을 볼 때 보이는 오타도 참지못하고 업로더에게 알려주고자 하는 습성이 있는데, Babel 의 웹페이지 수정은 어떻게 알려주지? 찾아보니 Github 에 오픈소스로 관리하고 있음을 확인했습니다. 평소 오픈소스에 기여해보고 싶다는 생각을 늘 갖고있었고, 꽤 큰 규모의 오픈소스의 docs 에 라도 기여를 할 수 있지 않을까 란 생각으로 오류가 나는 링크를 수정하는 PR 을 보냈었습니다.

 

PR 을 보낸지 30분도 안돼서 merge 를 시켜주었는데, 얼떨떨 하기도 하면서 비록 간단한 md 파일의 수정이었지만 오픈소스에 기여했다는 사실에 마음이 두근두근 했었던 기억이 납니다. 왜 오픈소스의 기여를 문서에서부터라도 시작해보라고 하는지 이해가 됐고, 이후엔 문서가 아닌 코드의 로직에 직접 기여를 해보고 싶다는 욕심도 생겼습니다.

 

처음 이 에러를 발견했을 때에는, 그냥 css prop 이 안정적인 emotion 으로 넘어가는게 나을까? 싶긴 했지만, 단순히 안된다고 놓기보다 어떤 것이 문제인지 내가 알 수 있고 고칠 수 있다면 기여해보고 싶다라는 생각이 들어 내부 코드를 확인하기 시작하고, 기여까지 이어졌습니다.

 

단순히 한줄의 코드로 버그를 고친 PR 이지만 css prop 이 내부적으로 어떤 과정을 거쳐 트랜스파일 되는 지 확인할 수 있었고, 자주 쓰는 라이브러리에 기여했다는 점이 무척이나 두근거렸고, 뿌듯했습니다. 

이 글을 읽으신 분들도 오픈소스에 기여한 경험을 나눠볼 수 있으면 좋겠습니다!

profile

파크로그

@파크park

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!