돌아온 앱 만들기 시리즈, 그 두 번째!

Hot reload!


링크

① 데스크탑 앱 만들기 #1 - Vite2 + Vue3 + Electron

② 데스크탑 앱 만들기 #2 - Hot reload

③ 데스크탑 앱 만들기 #3 - ipcMain, ipcRenderer(예정)

 

 자, 데크스탑 앱 만들기 두 번째 Hot reload 기능 구현하기입니다. Electron도 Web처럼 프론트와 백엔드로 나누어져 있습니다. 백엔드는 main.js(또는 background.js)에 해당하고, 프론트는 src안에 있는 파일들입니다.

 

 백엔드 코드가 바뀔 때는 앱 자체가 꺼졌다가 다시 실행되고, 프론트 코드가 바뀔때는 바로바로 적용될 수 있게 만들어볼게요.

 


 먼저 백엔드입니다.

 

1. 백엔드 리로드

 백엔드 리로드 기능을 구현하기 위해 라이브러리가 여러 가지 있지만 저는 2021년 11월 11일 현재 2-알파 버전인 electron-reload를 쓰도록 하겠습니다.

npm install --save-dev electron-reload
//or
yarn add -D electron-reload

 설치 이후 백엔드에 해당하는 main.js파일을 엽니다

 

/main.js

const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')

// 이부분을 넣어주세요!!
require('electron-reload')(__dirname, {
  electron: path.join(__dirname, 'node_modules', '.bin', 'electron'),
})
// 여기까지!!

function createWindow() {
  // ... 코드생략

 이제 electron-reload 라이브러리가 electron이 자리 잡고 있는 저 경로를 바라보고 변경이 일어날 때마다 앱을 껐다가 다시 켜줍니다.

 

 백엔드는 끝났습니다. 간단하죠?

 


2. 프론트 핫 리로드

 백엔드는 껐다 켜주는 수준이면 프론트는 확실히 핫하게 리로드해줍니다. vite를 쓰는 이유가 바로 이거지 않겠습니까? 그럼 설정 들어갑니다.

 

 먼저 기본적인 로직은 이렇습니다. 현재는 npm run start(또는 yarn start)를 하면 프론트 코드들이 build 되어서 /dist폴더에 묶어져서 들어갑니다. 그래서 /src에 있는 파일을 수정을 해도 변경이 되었는지 Electron이 알아챌 방법이 없죠.

/main.js

function createWindow() {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 1000,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
  });

  // and load the index.html of the app.
  // mainWindow.loadFile("./dist/index.html");
  // 여기부터
  if (process.env.NODE_ENV === 'production') {
    mainWindow.loadFile('./dist/index.html')
  } else {
    mainWindow.loadURL('http://localhost:3000')
  }
  // 여기까지 코드 삽입!

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()
}

 여기서 NODE_ENV 환경변수를 이용합니다. 개발환경에서는 Electron이 build되어 있는 파일을 바라보는 게 아니라 vite가 실행되고 있는 URL을 바라보게 해서 수정될 때 적용되게 만드는 겁니다.

 

/vite.config.js

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
const path = require("path");

// https://vitejs.dev/config/
export default defineConfig({
  base: process.env.NODE_ENV === "production" ? path.resolve(__dirname, "dist") : "", // <-- 얘 수정해주세요.
  plugins: [vue()],
});

 여기서는 development 환경에서는 아이들이 asset들이 build 된 파일을 바라보지 않아야하니까!

 

 자, 이제 스크립트를 바꿉니다.

/package.json

// ...생략

"scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview",
    "start": "vite && electron ." // <-- 이부분 vite && 추가
},
  
// ... 생략

 

 그리고 실행해보시면.

vite v2.6.7 dev server running at:

> Local: http://localhost:3000/
> Network: use `--host` to expose

ready in 467ms.

 이렇게 뜨고 일렉트론은 실행조차 되지 않습니다. 그렇다고 start 스크립트에서 "vite"를 빼면 아래 에러가 뿜뿜하죠.

 

스크립트 에러

 에러의 이유는 일렉트론이 실행되면서 localhost:3000를 읽어오지 못하기 때문입니다. localhost:3000이 만들어지기 전에 electron이 먼저 실행되면서 읽어올 수 없다고 찡찡대는 거죠.

 

자, 그럼 방법이 보입니다.

1) vite를 실행시킨다.(개발환경에서만 쓸 거니까 NODE_ENV도 development로 설정해준다.)

2) localhost:3000을 기다린 이후에 일렉트론을 실행한다.

 

 이 두 개의 명령이 따로 실행되면 안 되니 같이 실행될 수 있게 해주는 뭔가가 또 필요하겠죠.

 

 그럼 이제 세 개의 라이브러리가 필요해집니다

cross-env: 윈도우, 맥, 리눅스 환경에 구애받지 않고 환경변수를 설정할 수 있게 해주는 애

wait-on: port가 열릴 때까지 기다릴 수 있게 만들어주는 애

concurrently: 1)과 2)가 동시에 실행될 수 있게 만들어주는 애

 

그럼 설치!

npm install --save-dev concurrently wait-on cross-env
//or
yarn add -D concurrently wait-on cross-env

 설치가 완료되면 스크립트 파일을 아래처럼 만들어주세요./package.json

// ... 위에 생략

"scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview",
    "start": "concurrently -k \"cross-env NODE_ENV=development && vite\" \"wait-on tcp:3000 && electron .\"" // <-- 여기요 여기
},

// ... 아래 생략

 

그리고 npm run start(또는 yarn start)를 실행해봅니다.

제발 실행되었기를 빕니다.

 

 잘 실행이 되었다면 소스코드를 변경해봅니다.

/src/App.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3 + Vite!!" /> // <-- 이부분에 느낌표 두개 추가해볼게요.
</template>

편안


 마음이 편안해지는군요. 이제 백엔드와 프론트 둘 다 소스코드가 변경되면 알아서 앱이 껐다 켜지거나, 화면이 리로드 됩니다. 한번 체험해보세요 속도를. 감동입니다.

 

 이제 여러분도 그 감동과 함께 하시기를! 그리고 다음 포스팅은 2021 버전 데스크탑 앱 만들기 마지막입니다. preload.js를 활용해서 ipc 통신하는 방법을 올려보겠습니다. 굿바이!

 


2021.11.12 오류 발생!

NODE_ENV=development 환경에서 localhost:3000이 실행된 이후에 electron이 안뜬다면 start 스크립에서 wait-on tcp:3000을 빼보세요! 그러니 되더군요!

 

 

한 글자 바꿀 때마다 새로고침 하고 싶어.. 너무 좋아..
돌아온 앱 만들기 시리즈

 

바이트가 아니라 빗! 이라고 강조하더군요


링크

① 데스크탑 앱 만들기 #1 - Vite2 + Vue3 + Electron

② 데스크탑 앱 만들기 #2 - Hot reload

③ 데스크탑 앱 만들기 #3 - ipcMain, ipcRenderer(예정)

 

 데스크탑 앱 만들기 시리즈를 작년 9월에 시작하고 벌써 1년이 넘게 지났네요. 그동안 많은 기술이 나왔고 일렉트론도 엄청난 버전업을 했습니다. 2021년 10월 13일 오전 1시 30분 현재 15.1.2 버전이군요. 작년 이맘때가 10.1.0 버전이었는데.(얘네는 왜 이렇게 빨리 버전을 올리는지 모르겠습니다)

 

 그리고 바로 몇 시간 전 11시에 Nuxt3가 또 발표됐습니다. 두근대는 마음으로 만지작 거리다가 오랜만에 블로그를 업데이트해야겠다는 생각이 들어서 바로 시작합니다! 조만간  Nuxt에 대한 내용도 포스팅하고 싶군요 두근두근.

 

 아무튼 그 동안 Vue3도 나오고 Vite도 2 버전으로 업그레이드되었습니다. Vite를 처음 접했을 때의 그 놀라움을 아직도 잊지 못하고 있습니다. 항상 VueCLI로만 작업을 하던 저에게 새로고침 속도의 미학을 알려주었죠. (감동)

에반유. 당신은 정말..

그래서 여러분께도 그 감동을 전해드리고 싶었어요. 자 그럼 각설하고 바로 앱 만들기 시리즈 첫번째. 환경설정에 들어가 보도록 하겠습니다.


1. Vite 설치

npm init vite@latest
// or
yarn create vite

 뒤에 프로젝트 이름을 넣을 수 있는 데 그냥 바로 실행하면 아래 처럼 이름과 옵션을 고를 수 있어요.

~$ yarn create vite

yarn create v1.22.15
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Installed "create-vite@2.6.6" with binaries:
      - create-vite
      - cva
✔ Project name: … vite-electron-test
? Select a framework: › - Use arrow-keys. Return to submit.
    vanilla
❯   vue
    react
    preact
    lit
    svelte

타입스크립트는 vue-ts를 골라주면 되는데 일단 저는 vue 선택해서 Javascript로 진행합니다.

✔ Project name: … vite-electron-test
✔ Select a framework: › vue
? Select a variant: › - Use arrow-keys. Return to submit.
❯   vue
    vue-ts

그러면 완료. 들어가서 종속성을 설치하고 실행합니다.

Done. Now run:

  cd vite-electron-test
  yarn
  yarn dev

✨  Done in 262.96s.

그리고 yarn dev 또는 npm run dev 하면

짜장

라라벨 Watch나 VueCLI serve를 쓰다 보니 속도 하나에도 감동을 느낍니다. 물론 쟤네가 느린 건 아니지만..

localhost:3000만큼 사랑해

완성된 첫페이지입니다.

 

그리고 폴더구조는 아래와 같아요.

아무것도 없지요

아무것도 없어요. 이제부터 하나하나 설치해봅니다.

 

2. Electron 설치

 바로  Dev 디펜던시에 추가해줍니다.

npm install --save-dev electron
//or
yarn add -D electron

설치한 결과  package.json

{
  "name": "vite-electron-test",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "vue": "^3.2.16"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^1.9.3",
    "electron": "^15.1.2",
    "vite": "^2.6.4"
  }
}

자 이제 설치했으니 다음 단계로!

 

3. Vite 빌드

 Vite를 빌드하면 dist 폴더에 빌드 파일이 생성됩니다. 그걸 Electron이 읽을 수 있도록 만들어볼 거예요.

npm run build
//or
yarn build

빠른빌드

빌드를 하면 dist폴더에 static파일들이 생성된 것을 확인할 수 있습니다. 이제 Electron이 얘를 읽을 수 있게 경로 설정할 거예요.

 

다음은 Electron 설정을 시작해보죠!

 

4. Electron 파일 설정

Electron 빠른 시작 페이지 맨 밑에 보면 코드가 싹 다 나와있습니다.

링크: https://www.electronjs.org/docs/latest/tutorial/quick-start 

 

네가지 파일 정도를 신경써줘야합니다. 실제로는 3개파일이예요.

- 1. main.js

- 2. preload.js

- 3. index.html(있는거 그대로)

- 4. package.json

 

저 중에 2.preload.js는 세 번째 시리즈(③ 데스크탑 앱 만들기 #3 - ipcMain, ipcRenderer)에서 통신을 위해 필요하니까 파일만 만들면 두시면 됩니다. 그리고 index.html은 그냥 가만히 냅두면 되고 package.json파일은 만들 필요 없으니 main.js파일 경로랑 "start"스크립트만 추가하면 됩니다.

 

package.json

{
  "name": "vite-electron-test",
  "version": "0.0.0",
  "main": "main.js", // <-- 요기 추가
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview",
    "start": "electron ." // <-- 요기 추가
  },
  "dependencies": {
    "vue": "^3.2.16"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^1.9.3",
    "electron": "^15.1.2",
    "vite": "^2.6.4"
  }
}

main.js 파일명이나 script에 "start" 명령은 좋아하는 걸로 바꿔주세요. 편하신 걸로!

 

main.js 생성

const { app, BrowserWindow } = require('electron')
const path = require('path')

function createWindow () {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  // and load the index.html of the app.
  mainWindow.loadFile('./dist/index.html') // <-- 요기에 './dist/'를 추가!

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()
}

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

  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})

 

preload.js 파일 생성

// 냉무

 

자 끝났습니다. 이제 시작해볼까요?

 

5. 실행 그리고 오류 고치기

 설정은 대략 끝났으니 실행해봅니다.

npm run start
//or 
yarn start

짜잔! 빈 화면이 보입니다. 그리고 콘솔 창에 이런 오류가 있을 거예요.

뭐라는 거야 대체.

dist안에 있는 index.html 파일을 열어봅니다.

 

파일들의 경로가

/assets/index.860ec699.js

이런 식으로 지정되어 있을 거예요. Electron은 root폴더에서 실행이 되는데 asset폴더는 root폴더에 있는 게 아니란 말이죠. 그래서 저 경로들을 모조리 dist폴더를 향하게 만들 겁니다.

 

vite.config.js로 가볼게요.

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
const path = require("path"); // <-- 얘 추가하고

// https://vitejs.dev/config/
export default defineConfig({
  base: path.resolve(__dirname, "dist"), // <-- 얘 추가하고
  plugins: [vue()],
});

저 두 줄을 추가하고 다시 빌드합니다.

 

그리고 다시 dist폴더 안에 index.html 파일에 소스 경로를 확인해보면

/Users/my-name/electron/vite-electron-test/dist/assets/index.860ec699.js

 

요로케 뭔가 길어진 것을 확인할 수 있습니다. 그러니 이제 root에 있는 main.js가 읽어 들일 수 있게 변했군요.

 

그럼 다시 "start"해봅시다.

깔끔!

 

6. 마무리

 끝났습니다. 이제 Vite랑 Vue3랑 Electron을 실행할 준비가 됐어요. 근데 개발을 하려면 소스코드가 변경되었을 때 알아서 바뀌게 하고 싶잖아요? 매번 코드 바뀔 때마다 빌드하고 "start"해주는 건 너무 번거롭잖아요? 그래서 다음 포스팅은  Hot reload기능을 구현해보도록 하겠습니다!

 

그럼 다음 시리즈에서!

 


너무 깔끔해.. 젠장, 기분 좋아.

+ Recent posts