Issue
vue 페이지들을 관할하는 app과 jsp에 vue 컴포넌트를 심기 위해 구현한 eappCommonContainer로 2개의 vueapp이 존재합니다.
const app: any = createApp(App);
app.use(store(app))
.use(router)
.use(common)
.provide(key, app.config.globalProperties)
.use(VueCookies)
.directive('lazy', imageLazyLoading)
.mount('#webapp');
window.app = app;
const eappCommonContainer = createApp(CommonContainer);
// 기존 app의 state에 접근하기 위해 injection key 제공
eappCommonContainer.use(store(app)).use(router).**use(common)**.use(VueCookies).mount('#eapp-common-container');
common.js 에 선언되어있는 window 프로퍼티에서 state를 변경하는 로직이 존재합니다.
export const common = {
install: (app) => {
window.openCommonPopup = (params) => {
const { dispatch } = app.config.globalProperties.$store;
**dispatch('getCommonPopup', params);**
};
}
}
eappCommonContainer에 선언되어있는 CommonPopup의 경우 getCommonPopup action으로 할당될 popupInfo의 변화를 통해 팝업을 여는 로직을 수행합니다.
<template>
<GuidePopup v-if="isOpen" hide-default-button />
</template>
<script setup lang="ts">
import { computed, inject, watch } from 'vue';
import { useStore } from 'vuex';
import { usePopup } from '@/hooks/common';
import GuidePopup from '@/components/popup/GuidePopup.vue';
const { state } = useStore();
const { isOpen, open, close } = usePopup();
**const popupInfo = computed(() => state.commonPopupInfo);**
watch(popupInfo, () => {
open();
});
</script>
window 프로퍼티에 state의 변화를 주는 로직이 있고, 해당 state의 변화를 관찰하는 로직이 app 컴포넌트 내부에 있다면 정상동작하지 않습니다.
watchEffect(() => {
if (filterName.value) {
itemList.value = feedList.value.filter((feed) => feed.pushTitle.includes(filterName.value));
} else {
itemList.value = feedList.value;
}
});
window.getMessageBox = () => {
const { $store } = app.config.globalProperties;
$store.dispatch('getMessageBox');
};
Trouble Shooting
- app use(common) → window 함수 등록
- eappCommonContainer use(common) → window 함수 덮어쓰기
- window 함수가 CommonContainer store를 참조
- app 컴포넌트의 watch 미반응
- injection key로 app store 공유
main.ts 를 보면 use(common)을 통해 CommonContainer 생성 시 window 프로퍼티가 overide되게 됩니다.
따라서 window 프로퍼티에 선언되어있는 함수 내부의 action은 app의 action이 아닌 common container의 action을 가리키게 됩니다.
window.getMessageBox 함수가 호출되어서 getMessageBox 로 feedList를 변경하여도 알림함.vue가 바라보고 있는 feedList는 app의 vueapp, 변경된 feedList는 CommonContainer의 vueapp 이기 때문에 아무 동작을 하지 않습니다.
따라서 commonContainer의 use(common)을 제거해주어야 합니다.
하지만 이러면 또다른 문제가 생깁니다. window.openCommonPopup 의 경우 app의 state를 변경하게 되고, CommonPopup.vue 의 state의 경우 CommonContainer의 state를 바라보고 있어 아까와는 정 반대의 이유로 동작하지 않게 됩니다.
위 문제를 해결하려면 두가지 방법이 있습니다.
- CommonContainer에서 사용하는
common.js를 따로 생성합니다. - app의 store injection key를 사용해 CommonContainer 내부의 컴포넌트도 강제로 app의 state를 사용하도록 유도합니다.
jsp 페이지는 계속 vue 로 전환 중에 있었고, 언젠가는 사라질 로직을 위해 common.js를 새로 만드는 것 보다는 추후 삭제하기 용이하도록 하기 위해 2번의 방법으로 진행하였습니다.
코드는 다음과 같습니다.
export const key: InjectionKey<ComponentCustomProperties> = Symbol();
const app: any = createApp(App);
app.use(store(app))
.use(router)
.use(common)
.provide(key, app.config.globalProperties)
.use(VueCookies)
.directive('lazy', imageLazyLoading)
.mount('#webapp');
window.app = app;
const eappCommonContainer = createApp(CommonContainer);
// 기존 app의 state에 접근하기 위해 injection key 제공
eappCommonContainer.use(store(app)).use(router)**.provide(key, app.config.globalProperties).use(VueCookies)**.mount('#eapp-common-container');
<template>
<GuidePopup v-if="isOpen" hide-default-button />
</template>
<script setup lang="ts">
import { computed, inject, watch } from 'vue';
import { usePopup } from '@/hooks/common';
** import { key } from '@/main';
** import GuidePopup from '@/components/popup/GuidePopup.vue';
const { isOpen, open, close } = usePopup();
** const { $store } = inject(key)!; // eapp store 사용
**
const popupInfo = computed(() => $store.state.commonPopupInfo);
watch(popupInfo, () => {
open();
});
</script>