울면서개발하기
JAVA SCRIPT / NEXACRO

넥사크로 화면을 Vue 로 옮기기 — 스크립트는 그대로 두고 변환기로

· 2026년 10월 25일 다시 씀

넥사크로 17 로 만든 개인 ERP(VERA)를 Vue 3 로 옮겼다. 결론부터 말하면 화면은 Vue 로 그리고, 업무 로직은 넥사크로 스크립트를 한 줄도 고치지 않고 그대로 돌린다. 화면 233장 가운데 229장을 이렇게 옮겼고, 화면 스크립트를 손으로 고친 곳은 없다.

  • AS-IS: Nexacro 17 (넥사크로 N 17) + Spring Boot
  • TO-BE: Vue 3 + 직접 만든 넥사크로 호환 런타임(이하 Nx) + Spring Boot 3
  • 실제 화면: https://erp.victory.sarl/

먼저 라이선스부터 봤다

넥사크로 SDK 의 자바스크립트 라이브러리는 두 갈래로 나뉜다. 설치 폴더의 라이선스 고지문(Nexacro N public license readme) 기준으로 정리하면 이렇다.

구분 하는 일 라이선스
component (nexacrolib\component) 그리드·콤보·데이터셋 같은 부품의 동작 BSD 3-Clause. 저작권 고지만 남기면 고쳐 쓰고 배포할 수 있다
framework (nexacrolib\framework, resources) 화면 그리기·이벤트·통신·창 관리 엔진 소스는 보이지만, 정식 구매자가 사용 허가서 범위 안에서만 수정·사용할 수 있다

그래서 처음엔 “component 는 옮겨 오고, framework 가 하던 렌더링과 통신만 새로 만들면 되겠다”고 생각했다. 라이선스 조건은 버전·계약에 따라 다를 수 있으니, 같은 일을 하려면 자기가 가진 SDK 의 고지문과 계약서를 직접 확인해야 한다.

실제로 새로 만든 것

막상 해 보니 framework 가 하던 일은 렌더링과 통신만이 아니었다. 아래를 모두 새로 만들었고, framework 소스는 한 줄도 가져오지 않았다. 동작만 넥사크로와 같게 맞췄다.

  • 화면 그리기: Nx 컴포넌트 29종. API 모양은 넥사크로 그대로(set_*, this.div.form.x 같은 접근)
  • 좌표 배치: left·right·45%·"stt_x:10"(다른 컴포넌트 기준 배치) 같은 넥사크로 배치 규칙
  • 이벤트 순서: xfdl 에 적힌 처리기, addEventHandler·insertEventHandler 로 붙인 처리기의 실행 순서까지
  • 폼 생명주기: 스크립트 실행 → oninit → 공통 onload → 화면 onload
  • 거래와 콜백: transaction 을 서버 API 로 보내고, 오류 코드(-1 등)와 콜백 호출을 원본대로
  • 팝업과 창: 모달·모덜리스, 메뉴 창 이동·크기·최대화
  • 그리드 식: expr: 식 엔진, 머리 정렬, 체크, 트리, 셀 편집기
  • 셸 전역: 전역 데이터셋, 메뉴 열기, 세션 타이머, 재로그인

열쇠는 변환기

화면을 사람이 옮기지 않는다. 변환기(xfdl2vue)가 xfdl 을 읽어서 두 파일로 나눈다.

  • .vue: 배치. 넥사크로 태그를 Nx 컴포넌트로 바꾸고, 좌표·이벤트 이름은 그대로 둔다
  • .xjs: 스크립트. 원문에서 include 줄과 인자 타입 표기만 지운다

xfdl 을 변환기로 .vue 와 .xjs 로 나누고, 브라우저의 Nx 런타임이 스크립트를 실행해 Spring Boot 3 와 기존 MyBatis 매퍼를 거쳐 같은 DB 를 쓰는 구조

서버도 레거시의 서비스 규칙과 MyBatis 매퍼를 그대로 쓴다. AS-IS 화면을 고치면 변환기를 다시 돌리기만 하면 된다.

버튼 하나를 예로 들면 변환 전후가 이렇다.

<!-- xfdl (넥사크로 원본) -->
<Button id="btn_search" text="조회"
  right="15" top="8" width="52" height="24"
  onclick="btn_search_onclick"/>
<!-- .vue (변환 결과) -->
<NxButton id="btn_search" text="조회"
  right="15" top="8" width="52" height="24"
  @onclick="(o, e) => h('btn_search_onclick')(o, e)" />

h(...) 는 Nx 런타임이 그 화면의 스크립트에서 같은 이름의 함수를 찾아 주는 도우미다. 스크립트 쪽은 넥사크로 원문 그대로다.

// .xjs (원문 그대로, 일부 생략)
this.fn_search = function () {
  this.submit({
    id: "accountList",
    url: "acc.accountList",
    transaction: {
      id: "selectAccountList",
      recvDataset: "ds_list"
    },
    callback: function (svcId, errCode, errMsg) { /* ... */ }
  });
};

여기서 this.submit 은 넥사크로 기본 API 가 아니라 원래 프로젝트의 공통 함수다. 공통 함수도 원본 스크립트를 그대로 가져와 같은 런타임 위에서 돈다.

결과

  • 변환한 화면 229장 (233장 중 4장은 전용 부품으로 따로 만들었다)
  • 손으로 고친 화면 스크립트 0줄. 보안 때문에 재로그인 함수 하나만 런타임 쪽에서 덮어썼다
  • Nx 런타임 단위 시험 155개. 기대값은 넥사크로 원본의 동작
  • AS-IS 와 TO-BE 가 같은 DB 를 함께 쓴다

빠진 기능이 있으면 화면마다 고치지 않고 Nx 한 곳에서 고친다. 한 번 고치면 229개 화면이 함께 좋아진다. 고정 콤보 목록(85곳)이나 그리드 머리 정렬이 그렇게 한 번에 해결됐다.

덤: 화면 디자이너

원본이 계속 xfdl 이라서 화면 디자이너도 만들 수 있었다. 변환된 실제 화면 위에서 끌어서 옮기고 손잡이로 크기를 바꾸면, 바뀐 속성만 xfdl 사본에 써 넣고(공백·줄 끝·스크립트는 그대로) 그 화면만 다시 변환한다. 45%, "stt_x:10" 같은 원본 배치 규칙도 그대로 쓴다. 공개된 곳(https://erp.victory.sarl/designer)에서는 보기 전용이다.

정리

원본은 계속 xfdl 이고, Vue 는 변환기가 만드는 결과물이다. 검증된 업무 로직은 그대로 두고 화면 기술만 바꾸므로 업무 로직을 다시 검증할 필요가 없다. 남은 일은 Jasper 출력물, 운영 디자이너 저장, 아직 못 만든 넥사크로 API 다.

다시 쓰며 바로잡은 점

  • 원문은 발표 자료 그림만 있었다. 그림 속 글과 코드를 글자로 옮기고, 예제의 화면·서비스 이름은 일반적인 이름으로 바꿨다
  • 라이선스 설명에 “버전·계약에 따라 다를 수 있으니 직접 확인”을 덧붙였다