티스토리 뷰

Tip and Error

Program Upgrade (w. NW.js And Electron)

geonwoopaeng@gmail.com 2023. 7. 1. 17:50

Program Version Upgrade (w. NW.js And Electron)

현재 NW.js의 버전0.24.4를 사용 중입니다.
가장 큰 문제는 현재 jQuary, WebSQL, NW.js 옛 버전의 API 등 레거시 코드들을 사용하며 Svelte + routify변환 중에 있어 잘 동작하지 않는 부분과 routify 라이브러리가 동작하지 않아 문제였습니다.

이로 인해 1. 버전을 upgrade 2. Electron으로 대체와 같은 2가지 방법을 생각하고 있는 상황이며 문제를 해결하기에 앞서 해당 내용들(Cross-Platform Desktop Application, NW.js(node-webkit), Electron)에 대해 알아보도록 하겠습니다.

Cross-Platform Desktop Application

Cross(교차) + Platform + Desktop Application의 합성어로 다양한 플랫폼에서 사용할 수 있는 Desktop Application입니다.

사실 Cross-Platform을 구축하기 위해 Node.js를 많이 사용하는 편입니다. 보통 서버 측 애플리케이션을 구축하는 프로그래밍 프레임워크로 알려져 있지만 Slack, Visual Studio Code(IDE)등도 Node.js 데스크톱 앱을 사용한 것입니다.

 

Node.js 데스크톱 애플리케이션을 기원

2000년 초에 대부분의 소프트웨어는 상점에서 구입할 수 있는 압축 포장된 상자에 데스크톱 앱으로 제공되었으며 CD-ROM을 통해 소프트웨어를 설치하였습니다.

시간이 지나서 AJAX의 출현으로 소프트웨어를 웹/앱으로 제공하게 되었습니다. 이로인해 컴퓨터에 다운로드를 할 필요가 없으며 다양한 OS에서 실행할 수 있으며 소프트웨어를 온라인으로 제공하기 시작하였습니다.

그리고 Apple iPhone 및 Android 모바일앱의 출현등 큰 사건들이 있었지만 2000년대 이후 가장 크게 달라진 점은 OS 중 가장 강력한 Windows 약화로 인해 Mac OS 및 Linux에서도 작동하는 데스크톱 앱을 개발해야 되었습니다.

일반적으로 데스크톱 앱은 C, C++ 및 C#과 같은 프로그래밍 언어를 이용하여 개발하였지만 NW.js 및 Electron등의 등장으로 Node.js를 가지고 기존 웹/앱을 만드는 데 사용되는 것과 동일한 코드로 빌드하고 Windows, Mac OS 및 Linux에서 작동하는 데스크톱 앱을 Html, Css, JavaScript를 사용하여 쉽게 개발할 수 있게 되었습니다.

 

NW.js 및 Electron의 기원

2011년 Roger Wang은 Intel의 Open Source Technology Center에서 WebKit(당시 Safari, Konqueror 및 Google Chrome 뒤에 있는 브라우저 엔진)과 Node.js을 결합하는 방법을 찾아내어 내부에서 실행되는 JavaScript 코드에서 Node.js 모듈에 액세스할 수 있도록 하였습니다. (node-webkit)

2012년 Cheng Zhao라는 대학생이 node-webkit 작업을 위해 Intel 인턴으로 Node.jsWebkit이 결합된 방식을 변경 및 내부 아키텍처 개선을 Roger과 협력하였습니다. 코드가 발전함에 따라 node-webkitNode.js 모듈에서 데스크탑 앱을 위한 프레임워크가 되었습니다.

2012년 12월 cheng Zhao는 Intel을 떠나 GitHub의 계약직으로 GitHub의 Atom 편집기를 Chromium Embedded Framework 및 기본 JavaScript 바인딩에 node-webkit을 사용하게 하려 했지만 어려움이 있어 그들은 Atom용 기본 쉘인 Atom Shell을 만들게 되었고 추 후 node-webkitNW.jsAtom ShellElectron으로 개발되어 많은 사랑을 받고 있습니다.

NW.jsElectron 모두 Chromium, Node.js, API 요소를 가지고 있어 용어를 알고 가도록 하겠습니다.

Chromium : Google에서 만든 Google 브라우저 Chrome에서 사용하는 오픈 소스 라이브러리

Node.js : 서버에서 JavaScript를 작성하고 파일 시스템 및 네트워크에 액세스 하기 위한 도구 (컴퓨터도 서버)

API : 애플리케이션 프로그램 인터페이스로 라이브러리와 함께 사용할 수 있는 기능 세트

JavaScript 컨텍스트 : JavaScript 코드에 제공할 환경 정보들을 모아놓은 객체

 

NW.js(node-webkit)

: HTML, CSSJavaScript로 데스크톱 앱을 구축하기 위한 프레임 워크
(V8의 공통 사용을 통해 Chromium의 브라우저 엔진과 Node.js(프로그래밍 프레임워크)의 조합)

동작

웹/앱과 NW.js 데스크톱 앱을 같이 보면서 NW.js의 동작의 큰 틀을 알아보겠습니다.

[웹/앱]

클라이언트가 웹 페이지 요청 및 API 요청을 하고 서버에서 코드 실행 후 해당 데이터를 클라이언트에 다시 제공하는 형태입니다.

[NW.js]

NW.js 앱에서 앱 창은 내장된 웹 브라우저와 비슷하지만 웹 페이지 내부의 코드가 컴퓨터 리소스에 액세스 할 수 있고 서버 측 코드도 실행할 수 있습니다. 즉, 클라이언트와 서버의 코드를 동일한 위치에서 실행시킬 수 있습니다.

내부적으로 보면 다음과 같이 작동을 합니다.

  • Node.js는 OS 작업을 처리
    임베디드 웹 브라우저의 콘텍스트를 통해 Node.js를 사용.
  • Blink(Chromium Rendering Engine)는 앱의 프런트엔드 랜더링 처리
  • Node.jsBlink는 V8을 통해 JavaScript를 실행
    1. Node.jsChromium을 로드하여 둘 다 V8 엔진에 로드된 JavaScript 콘텍스트를 갖는다.
    2. Node.jsJavaScript 콘텍스트는 모듈, 프로세스 및 요구 사항과 같은 전역 객체 및 기능을 노출한다.
    3. ChromiumJavaScript 컨텍스트는 창, 문서 및 콘솔과 같은 전역 객체 및 기능을 노출한다.

기능

  • OS에 대한 기본 UI 및 API 생성 및 액세스를 위한 JavaScript API: 창 제어, 메뉴 항목 추가, 파일 읽기/쓰기 등
  • 앱 내에서 Node.js를 사용하고 npm을 통해 Node.js 모듈의 라이브러리 설치하고 사용가능
  • 단일 코드베이스에서 각 OS에 대한 앱의 실행 파일을 빌드할 수 있음

간단 구현

NW.js로 감싸주고 nw-builder로 실행 파일까지 만들어주는 간단한 구현 과정입니다.

  1. 파일 구조
📦NumberBaseballGame
┣ 📜package.json
┗ 📦src
  ┣ 📂js
  ┃ ┣ 📜ballstrike.js
  ┃ ┣ 📜comnum.js
  ┃ ┗ 📜playgame.js
  ┣ 📜index.html
  ┣ 📜index.js
  ┗ 📜package.json
  1. NW.js 및 nw-builder 설치
npm install -D nw@0.77.0-sdk nw-builder
  1. src 외부 package.json의 script 변경
{
  "scripts": {
    "dev:nw": "nw src/",
    "prod:nw": "nwbuild --platforms win32,win64,osx64,linux32,linux64 --buildDir dist/ src/"
  }
}
  1. src 내부 package.json의 script 변경
{
    "main": "index.html",
    ...
    "window": {
      // NW.js 공식 Docs의 Manifest format
      "title": "NumberBaseballGame",
      "toolbar": true,
      "width": 1000,
      "height": 1000,
      "min_width": 1000,
      "min_height": 1000,
  },
}
  1. 메인 html src 변경
<!DOCTYPE html>
<html lang="kr">
  <script type="module" src="index.js"></script>
</html>

전체 파일 링크

문제

NW.js 최신 버전 + nw-builder 최신 버전으로 사용하다 보니 다음과 같은 에러가 발생하였습니다.

nw에러

에러 메시지를 보면 다음과 같습니다.

Error: package.json not found in srcDir file glob patterns

'package.json에서 srcDir 파일 glob 패턴을 찾지 못했다'라고 되어 있는데 우선 glob 패턴에 대해서 알아야 했습니다.

glob 패턴은 과거 리눅스 운영체제에서 한 번에 여러 개의 파일을 찾을 때 사용해 온 패턴 매칭 기법이지만 현재는 많은 프로그래밍 언어에서 지원합니다.
즉, * 사용입니다.

그래서 경로를 잘 찾지 못하고 있다고 판단이 되어 nw-builder를 사용하는 부분에서 경로를 잘 설정하고 명령어에 오류가 있을 수 있어 공식 문서를 보면서 시도해 봤지만 잘 되지 않았습니다.

고민을 했지만 stackoverflow 및 블로그 어디에도 다양한 정보들이 없었습니다. 그래서 차선책으로 nw-builder가 크게 바뀌기 전 버전을 사용해 보니 문제가 해결되었습니다.

진짜 최신이 가장 좋은 것이다라는 생각을 많이 하였는데 안정적인 버전이 더 좋은 것 같다고 느끼게 되었습니다.

 

Electron

: JavaScript, HtmlCss로 데스크톱 앱을 구축하는 데 사용할 수 있는 라이브러리

구성 요소

App : Node.js 로드, Chromium 콘텐츠 모듈 로드, libuv 액세스와 같이 Electron 시작 시 로드해야 하는 코드 처리하는 파일 모음

Browser : JavaScript 엔진 초기화, UI 상호 작용, 각 OS별 바인딩과 같은 프런트엔드 부분과 상호작용을 처리하는 파일 모음

Renderer : Electron의 렌더러 프로세스에서 실행되는 코드용 파일

Common : 앱을 실행하기 위한 기본 및 렌더러 프로세스에서 모두 사용하는 유틸리티 코드 + Node.js의 이벤트 루프에 대한 메시징을 Chromium의 이벤트 루프에 통합하는 코드

동작

Chromium 소스 코드와 앱 간의 명확한 분리 하여 Chromium 구성 요소를 더 쉽게 업그레이드하고 소스 코드에서 Electron을 컴파일하는 것이 훨씬 간단하게 합니다.
조금 더 자세히 말하면 Electron은 백엔드 코드의 JavaScript 상태를 프런트엔드 앱 창의 상태와 별도로 유지하여 Node.jsChromiumJavaScript 콘텍스트를 처리합니다.
(Node.js 모듈은 백엔드에 대한 별도의 프로세스에서 작동한다는 점에 주의하며 백엔드와 앱 창 간의 데이터 공유가 프로세스 간 통신 또는 메시지 전달을 통해 처리되는 이유입니다.)

간단 구현

electron로 감싸주고 electron-builder로 실행 파일까지 만들어주는 간단한 구현 과정입니다.

  1. 파일 구조
📦NumberBaseballGame
┣ 📜package.json
┗ 📦src
  ┣ 📂js
  ┃ ┣ 📜ballstrike.js
  ┃ ┣ 📜comnum.js
  ┃ ┗ 📜playgame.js
  ┣ 📜index.html
  ┣ 📜index.js
  ┗ 📜package.json
  1. electronelectron-builder 설치
npm install -D electron electron-builder
  1. src 외부 package.json의 script 변경
{
  "scripts": {
    "dev:electron": "electron main.js",
    "prod:electron": "electron-builder --win portable --x64"
  }
}
  1. src 외부 main.js 구현
const { app, BrowserWindow } = require('electron');

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    heigth: 600,
  });
  mainWindow.loadFile('./src/index.html');
}

app.whenReady().then(() => {
  createWindow();
});

전체 파일 링크

 

NW.js VS Electron

앱 실행 처리 방법

NW.js
: 데스크톱 앱의 백엔드 및 프런트엔드 부분은 Node.jsChromium 이벤트 루프를 통합하고 JavaScript 콘텍스트를 Node.js에서 Chromium으로 복사함으로써 상태를 공유
=> 백엔드, 프런트엔드 동일한 JavaScript 콘텍스트 참조

Electron
: 상태를 공유하기 위해 백엔드의 ipcMain 모듈 와 프런트엔드의 ipcRenderer 모듈을 거쳐 기본 프로세스와 렌더러 프로세스의 JavaScript 콘텍스트가 분리되어 유지되지만 데이터는 명시적인 방식으로 프로세스 간에 전송될 수 있습니다.
=> 백엔드, 프런트엔드 각각 모듈을 거치며 JavaScript 콘텍스트 분리 but 데이터 공유

Node.js 작동

NW.js
: 임베디드 웹 브라우저의 콘텍스트를 통해 Node.js를 사용
=> Node.js의 API 및 브라우저의 JavaScript 네임스페이스(ex. WebSocket)와 관련된 API 메서드에 모두 액세스 하는 JavaScript 파일을 스크립트할 수 있다.
(이 방법은 NW.jsNode.jsBlink 렌더링 엔진JavaScript 네임스페이스를 병합하고 두 가지의 기본 이벤트 루프를 병합하여 공유 콘텍스트에서 작동하고 상호 작용할 수 있도록 하는 방식으로 가능합니다.)

Electron
: Chromium과 함께 Node.js를 사용하지만 Node.jsChromium의 이벤트 루프를 함께 결합하는 대신 Node.jsnode_bindings 기능을 사용합니다.
=> 소스 코드의 사용자 정의 수정 및 후속 컴파일 없이 ChromiumNode.js 구성 요소를 쉽게 업데이트할 수 있습니다.

 

추가 정보 요약

사실 Node.jsChromium의 연결이 가장 중요한 부분이라고 생각이 됩니다.

추가적인 정보에 대한 요약이 궁금하시면 해당 링크를 보는 것이 좋습니다.

  • NW.js에서 Node.jsBlink는 여러 창 간에 데이터를 공유하는 데 사용할 수 있는 JavaScript 콘텍스트를 공유합니다.
  • 이러한 JavaScript 상태 공유는 동일한 NW.js 앱에 대한 여러 앱 창이 동일한 상태를 공유할 수 있음을 의미합니다.
  • NW.js는 맞춤 바인딩이 있는 컴파일된 Chromium 버전을 사용하는 반면 ElectronChromium의 API를 사용하여 Node.jsChromium과 통합합니다.
  • Electron은 프런트엔드와 백엔드 사이에 별도의 JavaScript 콘텍스트를 가지고 있습니다.
  • Electron 앱에서 프런트 엔드와 백 엔드 간에 상태를 공유하려면 ipcMainipcRenderer API를 통해 전달되는 메시지를 사용해야 합니다.

 

마치며

결국 많은 상황을 본 결과 NW.js만 버전 업을 하기로 하였습니다.
Electron으로의 변환, NW.js와 관련된 nw-builder의 버전 업들은 현재 프로그램에서 연관되고 최신 버전에서 사용하지 않은 것들을 사용하고 있고 현재 개인당 한 가지의 서비스를 개발하고 있어 인원적인 측면으로도 시간적인 측면으로도 여유가 없어서 NW.js 버전 업만 하기로 결정을 하게 되었습니다.

그리고 해당 내용에 대해 발표도 같이 준비를 하는데 논문 파듯이 너무 깊게 발표 준비를 하여 많은 시간을 할애하는 저를 발견했습니다.
이 부분에 대해서 조언을 받고 간단 구현 -> 간단 설명 -> 필요하면 깊은 설명으로 틀을 잡았습니다. (사실 간단 구현 -> 간단 설명만 해도 충분한 것 같습니다.)

또한 버전 업그레이드 관련에 생각을 하면서 연관된 프로그램의 각자 버전이 너무 중요하고 무조건 최신 버전이 중요한 것이 아니라 프로그램이 안전하게 돌아가는 버전이 중요하다는 것을 알게 되는 경험이었습니다. 그러나 NW.js와 nw-builder에 관한 내용이 많이 없어 힘들었습니다. (Document를 보는 능력이 조금 성장해서 좋았다 ㅎㅎ)

NW.js 버전을 업그레이드하여 CheckList를 바탕으로 테스트를 하고 build 한 내용들을 package로 잘 감싸서 사용자들이 잘 사용할 수 있게 만들어야겠습니다.
(추 후 업그레이드할 때마다 CheckList를 바탕으로 직접 테스트하는 수고를 덜기 위해 테스트 코드도 작성해보고 싶습니다.)

마지막으로 이러한 과정을 통해 많은 문제가 있었지만 생각하는 시간을 줄이고 행동하는 시간을 늘리게 되는 좋은 경험이었고 다음 스탭을 나아가기 위해 행동해야겠습니다.

긴 글 읽어주셔서 감사합니다.

 

Ref

https://livebook.manning.com/book/cross-platform-desktop-applications/chapter-1/207
https://livebook.manning.com/book/cross-platform-desktop-applications/chapter-6/1
https://github.com/electron/electron/issues/5172#issuecomment-210697670
http://tangiblejs.com/posts/nw-js-and-electron-compared-2016-edition
https://freecontent.manning.com/how-does-node-js-work-with-nw-js-and-electron/
https://docs.nwjs.io/en/latest/For%20Users/Advanced/JavaScript%20Contexts%20in%20NW.js/#concept-of-javascript-context
https://www.electronjs.org/

반응형
공지사항
최근에 올라온 글