Study & Project ✏️/electron 🐣

[라즈베리파이 크로스컴파일] electron process model 공부!

JM 2021. 12. 28. 20:54
반응형

출처. https://www.electronjs.org/docs/latest/tutorial/process-model

 

Process Model | Electron

Electron inherits its multi-process architecture from Chromium, which makes the framework architecturally very similar to a modern web browser. In this guide, we'll expound on the conceptual knowledge of Electron that we applied in the minimal quick start

www.electronjs.org

강의도 없고 혼자 하려니 완전 기초부터 천천히 공식문서 보고 해야겠다.

process model을 보니 간단하지만 어렵게 설명을 잘해놨다.

이렇게 이해하는게 맞을까?

대략 얘기하자면 (저 비 전공자예요)

크로미늄에서 멀티 프로세스 모델을 채택한 이유는

웹 페이지는 여러 가지 관리할게 많아서란다.

별도의 창, 탭 등 그 순간에 처리할 process가 많은데

이걸 다 메인에서 처리할 순 없으니 멀티 프로세스로 미리 준비해 놓는 듯하다.

 

그래서 오늘은 메인 프로세스에서 관리하는 BrowserWindow라는 API를 사용해보자.

Main Process <- BrowserWindow

메인 프로세스의 주 역할은 BrowserWindow를 이용해서 어플리케이션 윈도우를 만들고 관리하는 것이란다.

각각의 BrowserWindow의 인스턴스는 각각의 렌더러 프로세스가 웹 페이지에서 이뤄진 윈도우를 불러온다.

이런 웹 브라우저와 상호작용 하는 것은 윈도우의 webContents를 이용하면 된다.

 

Main Process에서 다루는 만큼 Main.js에서 사용된다.

공홈의 코드를 따라 해 봤는데

const { BrowserWindow } = require('electron')

const win = new BrowserWindow({ width: 800, height: 600 })
win.loadFile('index.html');

이대로 했더니 app이 ready상태가 아니면 실행할 수 없다고 한다.

electron에서 app.ready라는 api를 통해서만 창을 띄울 수 있게 해 놨나 보다.

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

// 윈도우를 만들어줄 함수
function createWindow() {
    const win = new BrowserWindow({
        width: 800,
        height: 600
    })
     win.loadFile('index.html')
    // 특정 URL을 윈도우로 사용
    // win.loadURL('http://github.com')
}

// 앱의 상태를 확인하고 윈도우를 만드는 함수를 호출할 app API
app.whenReady().then(() => {
    createWindow()
    app.on('activate', ()=> {
        if(BrowserWindow.getAllWindows().length === 0) createWindow()
    })
})

// 앱의 상태를 확인하고 윈도우를 끄는 함수를 호출할 app API
app.on('window-all-closed', () => {
    if(process.platform !== 'darwin') app.quit()
})

그래서 이렇게 app.whenReady().then()을 추가해줬다.

화면이 잘 나오는 걸 볼 수 있다.

깨알같이 win.loadURL()도 추가했으니 한 번 써볼 만하다.

 

BrowserWindow()의 param을 통해서 여러 커스터마이징이 가능하다.

나중에 한 번 보는 걸로 하고,

 


앱이 준비될 동안 버벅거림을 보여주지 않고 윈도우를 띄우는 방식이 두 가지가 있다고 한다.

1. ready-to-show 이벤트

2. backgroundColor property

1. ready-to-show 이벤트

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

// 윈도우를 만들어줄 함수
function createWindow() {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        show: false,
    })
    //  win.loadFile('index.html')
    // 특정 URL을 윈도우로 사용
    win.loadURL('http://github.com')
    // Default값을 show: false로 하고, once가 호출되면 show: true로 바꿈
    // did-finish-load 이후에 ready-to-show 이벤트가 방출되므로 가능.
    win.once('ready-to-show', () => {
        win.show()
    })
}

// 앱의 상태를 확인하고 윈도우를 만드는 함수를 호출할 app API
app.whenReady().then(() => {
    createWindow()
    app.on('activate', ()=> {
        if(BrowserWindow.getAllWindows().length === 0) createWindow()
    })
})

// 앱의 상태를 확인하고 윈도우를 끄는 함수를 호출할 app API
app.on('window-all-closed', () => {
    if(process.platform !== 'darwin') app.quit()
})

did-finish-load이벤트(rendering) 이후에 한 번만 ready-to-show가 나오게 된다.

그때 BrowserWindow의 show값이 true로 바뀌게 하면 렌더링이 끝난 화면이 나오게 되는 것이다.

 

조심할 것.

페이지가 너무 많은 리소스를 차지하면 did-finish-load이전에 ready-to-show가 나올 수도 있다고 한다...?

paintWhenInitiallyHidden: false라는 parameter를 사용하면 ready-to-show 이벤트가 나오지 않을 수도 있단다.

(뭔지는 모르겠음..)

 

2. backgroundColor property

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

// 윈도우를 만들어줄 함수
function createWindow() {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        backgroundColor: '#2e2c29'
        // show: false,
    })
    //  win.loadFile('index.html')
    // 특정 URL을 윈도우로 사용
    win.loadURL('http://github.com')
    // // Default값을 show: false로 하고, once가 호출되면 show: true로 바꿈
    // // did-finish-load 이후에 ready-to-show 이벤트가 방출되므로 가능.
    // win.once('ready-to-show', () => {
    //     win.show()
    // })
}

// 앱의 상태를 확인하고 윈도우를 만드는 함수를 호출할 app API
app.whenReady().then(() => {
    createWindow()
    app.on('activate', ()=> {
        if(BrowserWindow.getAllWindows().length === 0) createWindow()
    })
})

// 앱의 상태를 확인하고 윈도우를 끄는 함수를 호출할 app API
app.on('window-all-closed', () => {
    if(process.platform !== 'darwin') app.quit()
})

backgroundColor가 먼저 보이고 rendering이 되면 화면이 표시되니 훨씬 더 추천하는 방식이라고 한다.

깔끔하기도 하고, 로딩 중 같은 화면을 보여줘도 괜찮을 것 같다.

 


다음으로는 창을 여러 개 띄울 수 있는 Parent and child windows.

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

// 윈도우를 만들어줄 함수
function createWindow() {
    const top = new BrowserWindow({
        width: 800,
        height: 600
    })

    const child = new BrowserWindow({
        width: 400,
        height: 200,
        parent: top
    })
    //  win.loadFile('index.html')
    // 특정 URL을 윈도우로 사용
    top.loadURL('http://github.com')
    child.loadFile('index.html')
}

// 앱의 상태를 확인하고 윈도우를 만드는 함수를 호출할 app API
app.whenReady().then(() => {
    createWindow()
    app.on('activate', ()=> {
        if(BrowserWindow.getAllWindows().length === 0) createWindow()
    })
})

// 앱의 상태를 확인하고 윈도우를 끄는 함수를 호출할 app API
app.on('window-all-closed', () => {
    if(process.platform !== 'darwin') app.quit()
})

이런 식으로 나오게 된다.

특징

자식 폼은 항상 부모 폼 위에 있는 것,

창이 2개 뜬 걸로 나오지 않고 하나의 묶음으로 보는 듯?

그리고 자식 폼은 꺼도 문제가 없지만 부모 폼을 끄면 다 꺼진다.


위의 Parent, child폼에서 파생된 Modal windows란?

흔히 대화 상자라고 불린다.

.once와 show: false를 재탕했다.

예제에서는 ready-to-show로 사용했지만, 특정 이벤트가 나오면 그때 나오는 식으로 사용할 수 있을 것 같다.

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

// 윈도우를 만들어줄 함수
function createWindow() {
    const top = new BrowserWindow({
        width: 800,
        height: 600
    })

    const child = new BrowserWindow({
        width: 400,
        height: 200,
        parent: top,
        // 대화상자
        modal: true,
        show: false
    })
    //  win.loadFile('index.html')
    // 특정 URL을 윈도우로 사용
    top.loadURL('http://github.com')
    child.loadFile('index.html')
    child.once('ready-to-show', () => {
        child.show()
    })
}

// 앱의 상태를 확인하고 윈도우를 만드는 함수를 호출할 app API
app.whenReady().then(() => {
    createWindow()
    app.on('activate', ()=> {
        if(BrowserWindow.getAllWindows().length === 0) createWindow()
    })
})

// 앱의 상태를 확인하고 윈도우를 끄는 함수를 호출할 app API
app.on('window-all-closed', () => {
    if(process.platform !== 'darwin') app.quit()
})

Page visibility는 win.hide()나 minimized와 같이 쓰이기도 하면서

결론적으로 안 보이게 하는 것이기 때문에 맥락상 같은 것 같다.

win.hidden(), show: false, backgroundThrottling: disabled를 사용하는 것 같다...(잘 모르겠음)

공식 문서에서는 많은 리소스를 쓸 때 잠시 안 보이게 하면 리소스 절약을 할 수 있다고 하는데

나중에 3D visualization 할 때 사용할 만한 것 같다.

 


드디어 마지막 다이얼로그다. JS의 alert 같은 것인 듯

맥은 사용을 안 하니.... 리눅스 계열에서는 modal windows가 dialog로 바뀔 수 있단다.

modal을 변형해서 toggle 됐을 때 나오고 사라지게 하면 될 듯하다.

추가로, 아래에 safeDialogs, safeDialogsMessage가 있는데

이건 창이 연속적으로 계속 올라올 때 경고창이 올라오는 것 같다.


Main Process <- BrowserWindow <- Renderer Process

추가로 렌더러 프로세서는 BrowserView API처럼 웹 안에 내장되어 있는 것이란다.

그러므로 webContents라는 Object 또한 웹 콘텐츠 안에 접근이 가능하다.

 

Main Process <- BrowserWindow <- Renderer Process이므로

브라우저 윈도우가 꺼지면 렌더러 프로세스도 같이 끝난다.

 

 

추가로 알아야 할 Main Process에서 다룰 것들

어플리케이션의 생명 주기는 Electron의 app 모듈로 관리되는데,

이 모듈은 거대하고 앱의 행동에 대해 커스텀이 가능한 모듈이다.

 

그리고 Electron만의 Native API들도 있단다.

사용자가 메인 프로세스에서 사용할 다양한 기능(함수), 메뉴, 다이얼로그들 그리고 tray 아이콘들이 있다.

차후에 API document를 보면서 공부해보면 좋을 것 같다.

 

 

 

엄청 길더라도 한 번에 쭉 끝내는 게 공부에 더 도움이 되는 듯하다.

출처 페이지 하단에 BrowserWindow에 관련된 API와 parameter들이 많으니 한 번씩은 봐 두는 게 좋을 것 같다.

땡!