우테코의 미션으로 나만의 UI 라이브러리를 만드는 미션이 있습니다.
첫 미션은 Virtual DOM을 구현하는 것이었고, 완전한 Virtual DOM을 구현해내진 못했었습니다.
그래도 렌더링된 요소 중 바뀐 요소만 렌더링 시키는 것에는 성공했었습니다.
그래서 이제 다음미션인 상태관리 부분을 구현하려했습니다.
근데 개인적으로 vDom의 구현과 jsx 파서를 구현안해보고 넘어간다는게 마음에 걸렸습니다.
(사실 다음 미션인 상태관리 구현하기는 쉬워보였습니다.)
그래서 JSX 파서를 만들어보기로 했습니다.
jsx 파서는 tagged template literal 을 이용해서 구현을 하면되었었는데요.
제가 지금까지 구현한 코드는 다음과 같습니다.
const TAGGED_TEMPLATE_LITERAL_PARAM_FLAG = "dobyParamArrIndex=";
const attachEvent = (dom, eventType, cb) => {
dom.addEventListener(eventType, cb);
};
export const jsx = (stringArr, ...paramArr) => {
const htmlStr = stringArr.reduce((acc, curr, index) => {
acc += curr;
if (paramArr[index] !== undefined) {
if (typeof paramArr[index] === "string") {
acc += paramArr[index];
} else {
acc += `${TAGGED_TEMPLATE_LITERAL_PARAM_FLAG}${index}`;
}
}
return acc;
}, "");
const $domFromHtmlString = new DOMParser()
.parseFromString(htmlStr, "text/html")
.querySelector("body").firstChild;
const domIterator = document.createNodeIterator(
$domFromHtmlString,
NodeFilter.SHOW_ALL
);
const applyAttribute = (dom, attributes) => {
for (const attribute of attributes) {
const attrName = attribute.name;
let value = attribute.nodeValue;
if (value.includes(TAGGED_TEMPLATE_LITERAL_PARAM_FLAG)) {
const realValueIndex = value.split("=")[1];
value = paramArr[realValueIndex];
}
if (attrName.startsWith("on")) {
attachEvent(dom, attrName.slice(2).toLowerCase(), value);
dom.removeAttribute(attrName);
} else {
dom.setAttribute(attrName, value);
}
}
};
while (true) {
const node = domIterator.nextNode();
if (!node) break;
console.log(node);
if (node.nodeType === Node.TEXT_NODE) {
const text = node.textContent;
if (text.includes(TAGGED_TEMPLATE_LITERAL_PARAM_FLAG)) {
const realValueIndex = text.split("=")[1];
node.textContent = paramArr[realValueIndex];
}
}
const attributes = Array.from(node.attributes ?? []);
if (attributes.length > 0) applyAttribute(node, attributes);
}
$domFromHtmlString.vDom = $domFromHtmlString;
return $domFromHtmlString;
};
tagged template literal이 인자를 받는 포맷이 있는데 그것대로 인자를 받아준후,
string 부분은 그냥 추가해주고, param 즉 ${여기값} 으로 주어진 인자들은 일단 유니크한 index로 삽입해놓습니다.
그리고 그것을 DOMParser로 DOM 객체로 뽑아낸다음.
Dom을 iteration합니다.
그러다가 유니크한 index를 만나면, paramArr의 인자에서 꺼내서 이벤트면 이벤트를 걸어주고, 아니면 속성을 set해주는 방식으로 구현을 했습니다.
이렇게 하면 일단 렌더링은 확실히됩니다!
하지만 App같은 대문자 태그들을 소문자로 변환하여 일반 <app></app> 처럼 변환된다는 점.
조건부 렌더링 처럼 ${}안에 Element가 중첩으로 되어있는 경우에 대해서는 처리되지 않고 있다는 단점이 있습니다.
오늘 마지막으로 jsx 파싱 로직을 구성하고, 리렌더링 되는 부분을 수습하고 상태관리 미션으로 넘어가야겠습니다.
앞으로 woowahan jsx 에서 많은 도움을 받을 예정인데요.
관심있으신분들은 갓-인규님께서 개발하신 코드에서 많은 영감을 받아가시길 바랍니다!
https://github.com/woowa-techcamp-2021/woowahan-jsx
GitHub - woowa-techcamp-2021/woowahan-jsx: Yet Another JSX using tagged template
Yet Another JSX using tagged template. Contribute to woowa-techcamp-2021/woowahan-jsx development by creating an account on GitHub.
github.com
'개발 > 개발 리포트' 카테고리의 다른 글
2021/10/27 : CSR에서 이미지가 다 로딩되었을때 화면에 보이기 (0) | 2021.10.28 |
---|---|
2021/10/25~26 : 나만의 UI 라이브러리 만들기 (feat. Virtual DOM, Web Component) (0) | 2021.10.27 |
2021/10/23 : 구버전 라이브러리를 사용하고 있는 사용자를 위한 설계 (0) | 2021.10.24 |
2021/10/22 : 모든 서비스는 결국 고객 중심이다. (0) | 2021.10.23 |
2021/10/21 : textarea의 link부분을 자동으로 하이퍼링크 처리하기, simple-react-query 라이브러리 배포 (1) | 2021.10.22 |