- 기존 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가 서로 데이터를 전달할 수 있게 되었다! 기본 로직을 파악했으니 보안과 설계에 유의하며 마이그레이션을 진행해야겠다.