반응형
- 키워드: vue to react migration, iframe, postMessage, contentWindow, window.parent
- 상황
- Vue2로 작성된 프로젝트가 있다.
- 프로젝트의 복잡성, 인수인계, 유지보수 등을 고려하여 React로 migration하기로 결정했다.
- 한 번에 옮기기엔 거대한 프로젝트이므로, 기존 로직을 유지하면서 점진적으로 migration하고자 한다.
- 해결 과정
- 기존 Vue 로직을 그대로 유지하면서 migration하는 방법은 iframe을 이용하는 것이다.
React 프로젝트를 새로 만들어 특정한 기능을 만든 후, 해당 기능만 Vue에서 iframe으로 가져오면 된다. - Vue와 React 프로젝트를 development mode로 실행할 경우, 각각 :8080(Vue) :3000(React) port를 사용한다.
- 먼저 부모 프로젝트인 Vue에서 iframe HTML을 작성한다. id는 'iframeExample'으로 하고, src는 자식 프로젝트인 localhost:3000으로 한다.
iframe의 width는 100%로 설정했지만, height는 100%, 'auto'로 설정할 수 없으므로 일단 비워둔다.
<!-- parent.vue --> <iframe id="iframeExample" width="100%" src="http://localhost:3000" />
- 자식 프로젝트인 React에서도 iframe 관련 로직을 작성한다.
// child.tsx useEffect(() => { window.parent.postMessage(document.body.scrollHeight, 'http://localhost:8080'); }, []);
부모 프로젝트에서 iframe을 통해 자식이 load되었을 경우, 'window.parent.postMessage'로 부모 window 객체에 접근한 후 통신을 할 수 있다. 위의 코드에서는 부모에게 document.body.scrollHeight 정보를 전송한다. - 부모 프로젝트인 Vue에서 해당 message를 수신한다. 그리고 3단계에서 설정하지 못한 height를 직접 설정한다.
// parent.vue mounted() { window.addEventListener('message', function (e) { if (e.origin === 'http://localhost:3000') { console.log('child -> parent:', e.data); document.getElementById('iframeExample').style.height = e.data + 'px'; } }); }
- 부모 프로젝트에서도 마찬가지로 자식에게 message를 보낼 수 있다. 이 때는 contentWindow로 자식 window 객체에 접근한다.
// parent.vue function sendChildMessage() { document.getElementById('iframeExample').contentWindow.postMessage( 'sent message from parent', // 자식에게 필요한 정보(ex> access_token)들을 전송 'http://localhost:3000' ); }
- 부모에서 전송한 message를 자식이 수신한다.
// child.tsx function receiveMessage(e: MessageEvent) { if (e.origin === 'http://localhost:8080') { console.log('parent -> child', e.data) } } window.addEventListener('message', receiveMessage);
- 지금까지 진행한 코드는 아래와 같다.
Vue:
// parent.vue(port 8080) mounted() { window.addEventListener('message', function (e) { if (e.origin === 'http://localhost:3000') { console.log('child -> parent:', e.data); document.getElementById('iframeExample').style.height = e.data + 'px'; } }); } ... function sendChildMessage() { document.getElementById('iframeExample').contentWindow.postMessage( 'sent message from parent', 'http://localhost:3000' ); } ... <iframe id="iframeExample" width="100%" src="http://localhost:3000" />
React:
// child.tsx(port 3000) useEffect(() => { if (window.top?.length) { // NOTE: iframe 으로 사용하지 않는 경우 console error 방지 window.parent.postMessage(document.body.scrollHeight, 'http://localhost:8080'); } function receiveMessage(e: MessageEvent) { if (e.origin === 'http://localhost:8080') { console.log('parent -> child', e.data) } } window.addEventListener('message', receiveMessage); return () => { window.removeEventListener('message', receiveMessage); } }, []);
- 이제 Vue와 React가 서로 데이터를 전달할 수 있게 되었다! 기본 로직을 파악했으니 보안과 설계에 유의하며 마이그레이션을 진행해야겠다.
- 기존 Vue 로직을 그대로 유지하면서 migration하는 방법은 iframe을 이용하는 것이다.
반응형
'프론트엔드' 카테고리의 다른 글
gitbook-cli cb.apply error 해결하기 (1) | 2022.06.18 |
---|---|
ESLint custom rule(plugin) 만들기 (0) | 2022.06.12 |
JENNIFER Front로 웹사이트 모니터링하기 (0) | 2022.05.22 |
package.json에서 yarn resolutions 적용하기 (0) | 2022.05.21 |
safari, iPhone 예외 상황 대응하기(Navigation Gestures, new Date) (0) | 2022.04.21 |