반응형
- 키워드: clone css, cloneNode, insertRule, cssText, emotion, CSSOM
- 상황
- @emotion 라이브러리가 만들어주는 style tag를 복사하는 작업을 하고자한다.
- @emotion 라이브러리가 만들어주는 style tag를 복사하는 작업을 하고자한다.
- 해결 과정
- emotion이 만든 style tag는 'data-emotion' attribute를 갖고 있음을 확인했다.
따라서 style tag 중, data-emotion 속성을 가진 tag를 복사하면 될 것이다.
hasAttribute와 cloneNode를 활용해 emotion style tag를 복사했다.const emotionStyleTags = Array.prototype.filter.call(document.getElementsByTagName('style'), (style) => style.hasAttribute('data-emotion'), ) const emotionStyleTagClones = emotionStyleTags.map((tag) => tag.cloneNode(true));
이제 복사한 tag를 원하는 위치에 복사하면 된다.
emotionStyleTagClones.forEach((tag) => { document.head.appendChild(tag); });
- 하지만 build를 하고 development 환경이 아닌 production 환경으로 실행하니 위 로직이 정상 작동하지 않았다.
emotion github 코드를 통해 원인을 찾아보니 production 환경에서 css rule을 insert하는 로직이 다르다는 것을 발견했다.
https://github.com/emotion-js/emotion/blob/main/packages/sheet/src/index.js#L141
production 환경일 경우 성능 최적화를 위해 sheet.insertRule(rule, sheet.cssRules.length) 을 사용하고, 아니면 tag.appendChild(document.createTextNode(rule))를 사용한다. - tag를 그대로 clone하지 않고 cssRule을 복사하도록 변경한다.
복사 과정에서 rule.cssText와 insertRule 함수를 사용했다.
let clonedStyleElement: HTMLStyleElement | null = null; const emotionStyleElements = Array.prototype.filter.call(document.getElementsByTagName('style'), (style) => style.hasAttribute('data-emotion'), ); const emotionStyleRules = emotionStyleElements .map((style) => Array.prototype.map.call(style.sheet.rules, (rule: CSSStyleRule) => rule.cssText)) .flat() as string[]; ... clonedStyleElement = document.createElement('style'); clonedStyleElement.setAttribute('id', 'clone'); clonedStyleElement.setAttribute('type', 'text/css'); document.head.appendChild(clonedStyleElement); emotionStyleRules.forEach((rule) => { clonedStyleElement?.sheet?.insertRule(rule); });
- 이 포스트는 emotion 관련 style tag를 위주로 설명했지만, 다른 경우에도 cssText, insertRule를 이용해 style을 복사할 수 있을 것이다.
- emotion이 만든 style tag는 'data-emotion' attribute를 갖고 있음을 확인했다.
반응형
'프론트엔드' 카테고리의 다른 글
카이스트 SPARCS 2023 StartUp Hackathon 준우승 수상 후기 (1) | 2023.01.30 |
---|---|
Google Calendar API로 공휴일 연동하기 (0) | 2022.11.21 |
mailjet으로 mail Template UI 구성하기 (0) | 2022.11.21 |
ADR 문서로 의사결정 기록하기 (0) | 2022.10.31 |
map, area tag로 간단하게 페이지 개발하기 (0) | 2022.10.14 |