React.js가 IE 브라우저 지원 중단했다면서요?

어떻게든 IE를 지원하려는 당신을 위한 안내서

TL;DR

  • 아직 시작하지 않았다면 늦지 않았다. 지원하지 말자고 설득해보자!
  • Polyfills을 통해 IE 8에서 지원하지 않는 구문을 동작하게 하자.
  • Getter/Setter는 금물이다.
  • IE 8을 지원하는 라이브러리 버전들에 대해 알아보자.

제목에 대한 답입니다. . 당장 React.js의 IE 8 관련 버그의 우선 순위를 낮추고, 결국엔 지원을 중단할 것이라고 밝혔습니다.

그러나 이 글은 IE 8을 지원하려는 React 개발자들을 위해 작성되었습니다.


이 글의 목적

IE 8을 지원 해야하는 개발자는 크게 아래 두가지 상황을 맞이하게 됩니다.

  1. IE 8을 지원하는 React application을 개발할 것이다.
  2. React application을 이미 개발했고 IE 8을 추가 지원해야한다.

이 글은 1번에 해당되는 개발자들은 React가 아닌 다른 방법으로 개발을 하고 2번에 해당되는 개발자들은 IE 8에 성공적으로 대응하기를 기원하며 작성되었습니다.


왜 지원을 해야하죠?

최근 6개월 동안 국내의 경우 약 4%의 유저가 여전히 IE 8 을 사용하고 있습니다. 무시해도 될만큼 적은 비율로 보이지만, 네이버에서는 아예 네이버에 최적화된 IE 8를 제공하고 있습니다. 어느 서비스에서는 IE 7, 8이 10% 가량 유지되기도 하고요. 이처럼 IE 8 지원 여부 및 이유는 서비스 별 특징에 따라 다를 수 있습니다. 즉, 글을 읽고 있는 여러분들도 언젠가 마주칠 수 있는 상황인 거죠.

Microsoft에서도 버린 IE 8, 9, 10.은 장수를 위해 가급적 우리나라에서 보지 않았으면 합니다.

혹시나? 역시나!

React 공식 튜토리얼을 이용해 간단히 한번 살펴보겠습니다.

입맛에 맞는 서버를 실행시키고 브라우저로 접속해보면, 아래와 같이 간단한 react 앱이 잘 동작합니다. 물론 모던 브라우저에서 말이죠.

Chrome v53에서 렌더링한 React Tutorial

IE 8에선 어떻게 되나 한번 볼까요?

기대를 실망시키지 않는 우리의 IE 8

…그럼 지금부터 IE 8에서도 동작하도록 패치를 해볼까요?

React Tutorial 설명

기존 babel-browser는 #158 이후에 react tutorial에서 제거되어 해당 내용을 수정하였습니다. (16.09.07)

본격적인 패치에 앞서 React Tutorial의 가장 핵심인 babel-standalone를 소개해드리겠습니다.

<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js" />

public/index.html에 포함되어 있는 위 script는 아래와 같은 “text/babel”의 type 속성 값을 가지는 script 태그의 code를 babel을 이용해 ECMAScript 5(이하 ‘ES 5’)로 transcompile 해주는 라이브러리입니다.

<script type="text/babel" src="scripts/example.js" />

결과적으로 위 example.js는 babel-standalone에 의해 ES 5로 transform되죠. 물론 현재 tutorial은 ES 5로 작성되어있지만 3rd party 라이브러리들도 같이 transform된다는 점에서 필수입니다.

참고로 babel-standalone는 babel에서 제공하는 공식 라이브러리는 아닙니다. 현재 babel에서 deprecated된 babel-browser의 대체재로 babel의 공식문서에서 소개하고 있는 라이브러리입니다.

그렇기때문에 현재로서는 어떠한 코드를 추가하더라도 IE 8에서는 동작하지 않습니다. 왜냐하면 babel에서 transform 해준 결과물은 ES 5이기 때문에 ES5 호환성에 대해서 빨간색으로 도배되어있는 IE 8은 죽었다 깨어나도 지원하지 못합니다.


Tutorial #1. es3-loader

하지만 물러설 순 없지요. ES 5를 ES 3로 transform 해주는 es3ify라는 라이브러리가 있습니다. 이를 이용해 IE 8이 지원하는 ES 3로 transform 해보도록 하죠.

지금부터는 babel-browser가 제공하는 기능을 넘어서기 때문에 webpack+babel 사용을 전제로 설명드리겠습니다. 또한 아래에서 설명하는 코드들은 기존 튜토리얼을 fork해서 만든 react-tutorial-ie8의 feature/tutorial 브랜치에서 보실 수 있습니다.

bf14bf commit과 같이 webpack 설정 파일에 post loader로 es3ify-loader를 추가해줍니다(아래 참고). 이는 babel transform이 완료된 코드에 es3ify를 이용해 다시 transform 하는 것을 의미합니다.

postLoaders: [
{
test: /\.js[x]?$/,
loaders: ['es3ify-loader']
}
]

그리고 최종 빌드된 파일 webpack.bundle.js를 index.html에 추가합니다. 이때, 이미 transform된 JS 이므로 script 태그의 type은 “text/javascript”로 수정합니다.

<script type="text/javascript" src="scripts/webpack.bundle.js" />
이 과정에서 IE 8을 애초에 지원하지 않는다고 밝힌 react@15.x와 react-dom@15.x, jQuery@3.x의 버전은 알맞은 버전으로 수정합니다. 알맞은 버전 찾는 법은 따로 설명하지 않겠습니다.

그리고나서 IE 8에서 어떻게 되는지 볼까요?

야호! 아까보다는 훨씬 양호!

네 아직 갈 길이 남았습니다. 하지만 기존에 있던 오류들은 많이 사라졌네요.


Tutorial #2. babel-polyfill

위에서 본 오류에 따르면 1419번째 줄, 다시 말해 아래 구문에서 오류가 나는 것으로 보이는군요.

svgElements.forEach(function (nodeName) {
markupWrap[nodeName] = svgWrap;
shouldWrap[nodeName] = true;
});

아주 단순한 문제입니다. IE 8은 말그대로 forEach method를 모르고 있습니다. 그렇다면 당연히 해당 method를 정의해주면 해결되겠습니다. 이때 바로 polyfill이 필요하게 됩니다. polyfill은 모던 브라우저에서만 지원되는 기능을 올드 브라우저에서도 동작하게끔 도와주는 역할을 합니다. 방금 위에서 사용한 es3ify나 Media Query를 쓸 수 있게 도와주는 respond.js를 생각해보시면 되겠네요.

d56a24 commit과 같이 babel-polyfill을 package.json과 webpack 설정 파일에 추가해주면 tutorial application이 IE 8에서 잘 동작하는 것을 확인할 수 있습니다.

드디어 동작하는 Tutorial Application!
만약 babel-polyfill의 크기가 부담스럽다면 babel-polyfill에서 실질적인 polyfill역할을 담당하는 core-js를 필요한 부분만 활용하면 됩니다. 자세한 방법은 지난 번에 퍼블리시된 SPA 스크립트 용량 어디까지 줄일 수 있을까? ES2015(ES6) 와 commonjs 부분을 참고해주세요.

축하합니다!

이렇게 첫 번째 IE 8 지원을 마쳤습니다.


Real World #1. 내가 만났던 오류와 polyfill을 통한 대처

지금까지는 간단한 예제로 IE 8 대응 방법을 살펴보았는데요. 실제로 만나게 될 오류들은 훨씬 다양합니다. 제가 만났던 오류들과 해결을 위한 대응은 다음과 같습니다. 구체적인 내용은 해당 라이브러리의 링크를 참고해주세요.

현재 Production에서 사용 중인 polyfill은 console-polyfill, es5-shim, es6-promise, fetch-ie8 입니다.

Real World #2 Getter/Setter 절대 금물

ES6의 getter와 setter를 사용할 경우 babel에서는 Object.defineProperty을 이용하여 transform을 합니다. 하지만 해당 구문을 IE 8에서는 DOM Object에서만 사용할 수 있게 규정하게 두어서 항상 오류가 발생합니다.

해당 오류는 CommentBox 이름을 수정하는 기능을 추가한 abce88 commit을 참고하시면 됩니다. ES 6와 Getter/Setter를 이용하여 해당 오류를 발생하는 예제입니다.

Getter/Setter는 위와 같은 에러나 Exception thrown and not caught 같은 무서운 에러를 뿜어냅니다.
__proto__ 를 통한 상속도 IE < 10 에서는 지원되지 않으므로 금물입니다.

Real World #3 IE 8 지원을 위한 라이브러리 버전

실제 어플리케이션 개발을 하다보면 node 라이브러리들을 많이 쓰게 되는데요, 각 라이브러리들의 browser support를 항상 확인하고, 실제 build된 코드도 읽어보는 습관을 들이는 것이 좋습니다. IE 8 지원 시에 쓸 수 있는 라이브러리들 버전 몇 가지 공유드리겠습니다.


Real World #4 react 0.14의 span

react < 15에서는 text에 기본적으로 span 태그가 붙으면서 css가 깨지는 경우가 많습니다. 관련 내용을 퍼블리셔 혹은 xml 담당에게 전달하여 예기치 않은 스타일 충돌 및 깨짐을 방지하세요. 퍼블리셔와 협업하는 방법은 추후에 더 자세히 알아보도록 하지요.

v15에는 이 커밋이 포함되어 더 이상 span이 생성되지 않습니다.

FAQ

  • Q: flow 써도 되나요? A: 네 잘됩니다. 영향없어요.
  • Q: 오 얼마나 걸리셨나요? A: 시간보다는 practice가 없어서 하나하나 빌드 & 테스트하면서 rewrite했습니다. 🙊🙊

글을 정리하며..

지금까지 제가 경험했던 IE 8 이슈와 대응 방법에 대해 공유드렸습니다…만 아직도 늦지 않았습니다. react로 꼭 IE 8을 지원하셔야 하나요? 농담입니다. 사실 아무리 이해를 잘하고 적용을 잘해도 결국엔 올드 브라우저들에 대한 지원이 조금씩 사라지면 같이 쓸모없어질 능력(!)이라 아쉽지만, 한번쯤은 경험해도 나쁘진 않은 것 같습니다. Redux 관련해서는 부수적으로 설명해야할 것들이 많아져서 일부러 제외했지만, 혹시나 궁금하시다면 댓글 혹은 @catm1nt에 남겨주세요.


긴 글 읽어주셔서 감사합니다. 도움이 되셨다면 공유, 댓글, 추천, 구독 부탁드리겠습니다. react-tutorial-ie8 프로젝트에 Production에서 만나는 IE 8 관련 이슈를 계속 업데이트할 예정이니 Star 부탁드립니다.