본문 바로가기

Client/Vue

[Vue] 외부 js에서 vue function() 호출(3)

오랜만에 다시 포스팅을 하는데, 긴 숙원인 외부 js 파일에서 vue 함수를 호출해야 하는 상황에서의 해결법을 작성해보려 한다.
이전 포스팅들에서도 몇가지 방법으로 시도를 했었는데, 이번 포스팅은 첫 번째 글의 방법을 보완한 방법으로, 참고를 원할 경우 첫 번째 글을 보고 오는것도 괜찮을 것 같다.

 

[vue] 외부 js에서 vue fucntion() 호출

vue 프레임 워크를 사용해서 프로젝트를 진행하다 보니, api 연동 등으로 인해 vue 파일 내 스크립트 코드가 아니라 .js 파일을 작성해서 개발을 진행해야 하는 경우가 생겼는데, js 파일 내 함수에

asang-developer.tistory.com

 

[Vue] 외부 js에서 vue 함수 호출(2)

이전에 외부 js에서 vue 함수 호출 관련 포스팅을 한 적이 있었는데, 당시에는 vue 파일의 script내 mounted 위치에서 js 파일을 setAttribute 처리하는 형식으로 vue 파일에 js 를 import 하는 방식으로 굳이

asang-developer.tistory.com

* 항상 말하지만 해당 블로그는 개인적인 기록용 블로그로, 절대적인 방법이나 원리를 설명하는 전문 포스팅이 아니며 미래의 필자를 위해 기록해두는 목적이 대부분임을 방문자들께서 염두에 두고 글을 읽어주시길 바랍니다.

 

이전 포스팅들에 이어 이번 포스팅에서는 plugin 을 활용하는 방법을 기록하려 한다.

전의 두 포스팅을 작성 할 땐 지금보다도 더 vue 구조에 대한 이해도도 낮았고, 구조적으로도 신경 쓸 여력이 별로 없어서 모로가도 서울만 가면 된다 마인드로 어쨌든 돌아가면 장땡이라는 식의 방법을 썼는데, 시간이 조금 지나니 plugin을 활용하는게 내가 원하는 기대효과를 볼 수 있겠다는 판단이 들어 실행에 옮기게 되었다.

그리고 결과적으로 확실히 현재 프로젝트에선 해당 방법이 간결하고 유지보수도 이전보다 용이해진 결과를 얻을 수 있었다고 생각한다. 실제로 그럴지는 또 시간이 지나야 알겠지만, 아무튼.

필자가 작업중인 프로젝트에서 외부 js를 호출부터 callback 처리 및 js 호출 구조 흐름을 간단히 작성하면
          vue function -> 외부 api 호출 -> 내부 js로 callback 후 return 값 가공 -> vue fucntion에서 process 마무리
이렇게 되는데, 그림으로 그려보면 대충 아래처럼 표현할 수 있다.

Api.js=외부 js / Connect.js=callback 처리를 위한 프로젝트 내 js

 

자, 이제 vue 에서 외부 js를 거쳐 다시 vue function 을 호출하는데 필요한 준비물(?) 은 아래와 같다.

  • public/index.html
  • public/js(폴더생략가능)/connect.js (파일명 자유)
  • src/main.js
  • src/plugins(폴더생략가능)/connectPlugin.js(파일명 자유)
  • src/(대충 프로젝트 경로)/myExample.vue (vue component 파일)

index.html / main.js 파일은 기본적으로 생성되는 파일이고, 당연하게도 vue 프로젝트니 뭔가 작업중인 vue 파일이 필요하다.

따로 생성해야 할 파일은 callback 처리를 받을 js 파일과, vue 내에서 전역 함수 역할을 할 plugin 파일 두 개면 충분!
어차피 js랑 plugin 둘 다 import해서 사용할 예정이고, plugin은 src(vue 프로젝트) 폴더 내에만 있으면 어디 있든 상관이 없으니 경로는 자유롭게 설정하도록 하자. 다만, 보통 프로그램 구조의 정돈을 위해서? 성격별 폴더로 분류 해두면 나중에 plugin을 추가한다든지 할 때 정리가 편하다.

코드를 보기 전에 흐름도를 간단하게 그려보면 아래처럼 볼 수 있다.

프로그램 흐름도

큰 흐름을 보자면 index.html 에서 script 파일을 등록해두고, 호출과 callback 처리는 plugin에서 처리한다. vue 파일에서는 main.js에 전역으로 등록해둔 plugin함수를 호출하기만 하면 된다.

아래부터는 코드

<!DOCTYPE html>
<html lang="ko">
  <head></head>
  <body>
    ...
    <script type="text/javascript" src="(외부 js 경로)/Api.js"></script>
    <script type="text/javascript" src="/js/connect.js"></script>    
  </body>
</html>

[ index.html ]
index.html 에서는 위에서 설명한 것 처럼 vue 에서 js 함수를 사용할 수 있도록 javascript 파일을 import 해준다.

const connectPlugin = {};
connectPlugin.install = function(Vue)
{
    // api function 호출 함수
    Vue.prototype.$_callApiAction = function() {
    	apiAction();	// 호출 할 api function
    }
    
    // callback 처리 함수
    Vue.prototype.$_callbackApiAction = function(value) {
    	/* callback 처리 진행 */
    }

}
export default connectPlugin;

[connectPlugin.js]
plugin 에서는 외부 api를 호출할 함수와 callback 처리를 진행할 함수를 등록해줬다.
외부 api 호출은 vue 파일 내에서 진행해도 되지만, 필자는 call 과 callback 처리를 한 파일에서 확인하고 싶어서 위와 같이 작성했다.
* plugin 네이밍($_functionName) 은 vue 에서 지향하는 형식으로 작성했으며, 개인 취향대로 작성해도 무방 할 것이다. plugin에 대한 상세 설명은 공식 페이지에 친절하게 적혀있으므로 참고하도록 하자.

import ConnectPlugin from './plugins/ConnectPlugin';
Vue.use(ConnectPlugin);

// #app 은 App.vue 파일에 등록한 component name (name: 'app')
var vm = new Vue({ ... }).$mount('#app');
// vm 을 window.app 에 등록해줘야 프로젝트 내 js 에서 vue 프로젝트를 찾을 수 있다.
window.app = vm;

[main.js]
main.js 에서 plugin 을 전역으로 등록해준다. 함께 vue 프로젝트도 window.app 에 등록해서 이후 connect.js(프로젝트 내 js 파일) 에서 root 를 찾을 수 있도록 하자.

function connection(key, value) {
    /* function 외부에서 root 설정 시 app 이 mount 되기 이전에 script 처리가 되므로
    window.app을 불러오지 못할 수 있음 */
    var root = window.app.$root;
    
    if(key=="myResultKey") {
        root.$_callbackApiAction(value);
    }
}

[connect.js]
위에 말했던 것 처럼 root 는 함수 호출시에 등록해주도록 한다.

필자의 프로젝트같은 경우 외부 js에서 callback 시 key 와 value 를 전달받기 때문에 (Listener 로 사용) key 값에 따라 적절한 가공 처리 후 plugin 으로 추가적으로 필요한 paramater를 전달하거나, return value 를 그냥 plugin에서 처리하거나 한다.
이건 개발자의 취향에 따라, api의 return 방식에 따라 처리하면 될 것으로 보인다. connect.js 에 function 을 여러개 등록해서 api function callback 에 각 대응하는 로직을 작성하는 방법도 있을 것이다.

<template>
<div>
    <button @click="$_callApiAction()">Call Action</button>
    <button @click="otherWayCall()">Other Way Call Action</button>
</div>
</template>

<script>
export default {
	...
    methods: {
    	otherWayCall() {
        	this.$_callApiAction();
        }
    }
}
</acript>

[MyExample.vue]
이제 최종이자, 처리의 시작인 vue 파일에서는 어떤 방법이든 plugin 에 등록한 함수를 호출하면 된다.
위처럼 html 내에서 바로 호출해도 되고, script 내에서 this 객체를 이용해 호출해도 된다. 여기서부터 프로세스가 시작되어서 plugin 의 callback 에서 끝나는 구조.

기존에는 app.vue 파일에 ref를 지정해주고, 각 vue 파일에서 connect.js 파일을 mounted 될 때 등록해주어야 했는데, plugin을 활용하는 방향으로 진행하니 기본 세팅이나 흐름도가 확실히 간결해졌다.
이후 로직이 바뀌어야 할 경우에도 vue 파일을 따로 찾아가서 수정 할 필요 없이 plugin 파일 내 코드만 변경하면 되기 때문에 유지보수도 용이할 것으로 예상된다.

사실 가장 큰 장점이라고 느껴지는건 기존에는 connect.js에서 호출할 vue 함수의 component 구조에 따라 root.$children[0].$refs.contents ... ... 로 callback 처리를 진행 할 function 의 경로를 찾아갔어야 했고, 앞서 언급한 것 처럼 component 구조가 변경이 되면 callback function을 찾지 못해서 processing 이 정상적으로 처리되지 않을 가능성이 있었는데, 이 부분이 깔끔하게 해결됐다는 점!
100% 확신할 수는 없지만 아무래도 root 에 전역으로 선언되어 있으니 우려하는 일은 발생하지 않을 것 같다는 기대가 든다.

참고로 나는 callback 함수에서 데이터 처리 후 추가적인 작업이 필요 없었기 때문에 (return 값을 다시 vue component에서 활용해서 화면에 출력해야 한다든지 하는 경우) plugin에서 후처리를 진행한 후 process를 끝냈지만 외부에서 return 받은 데이터를 다시 vue 화면에 출력해야 하는 등 데이터를 활용해야 할 경우엔 추가적인 작업이 필요하겠지 싶다.
그치만 이미 vue 프로젝트 내부로 다시 돌아왔으니 해결 방안은 많지 않을까 싶다. 가공처리 한 result 값을 plugin에서 vuex storage 에 데이터를 저장해 component 에서 활용한다든지?

아무튼 어찌 하다 보니 하나의 주제로 세 번이나 포스팅을 작성했는데, 결론적으로 꽤 만족스러운 방법을 찾은 것 같아서 기뻤다. 이상 끝.