electron에서 express를 쓰는 것! 결론은 불가능 합니다.

어찌어찌 띄워도 사용자 pc마다 방화벽 설정이 있고, 로컬에서 포트를 오픈한다는 것 자체가 꽤나 위험을 동반 합니다. 내 PC 에서는 어떻게 되었다고 해도 배포한 PC에서는 된다는 보장이 없는거죠

그런데 왜 자꾸 express를 쓰려고 하는가? 왜냐하면 restful api를 구축을 해야 하기 때문 입니다. 이 방법이 익숙하기도 하고 앱을 만드는데 좋은 방법이기도 합니다. 그렇기 때문에 electron에 express를 어떻게 띄워볼려고 맨 땅에 헤딩을 하지만.. 결국은 안된다네요.

그래도 대안은 있습니다. electron-router 를 쓰는거죠.

electron-router 는 서버에서 지원하는 api.get(), api.post() 이런걸 다 지원 합니다.

다만 외부에서 접근은 안되고, 내부 랜더러(브라우저) 에서만 접근 가능 합니다.

 

 

 

1. electron-router 

찬찬히 살펴보실 분은 아래를 참고 해 보세요.

www.npmjs.com/package/electron-router

 

 

 

 

2. 기본앱 만들기

간단히 보여드리기 위해 먼저 기본적인 앱을 만들어 봅시다.

package.json

{
  "name": "electron-simple",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

main.js

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

function createWindow () {  // 브라우저 창을 생성
  let win = new BrowserWindow({
    width: 600,
    height: 400,
    webPreferences: {
      nodeIntegration: true  //랜더러(브라우저)에서 시스템에 직접 접근함, 보안상 좋지않음
    }
  })
  win.webContents.openDevTools()  //랜더러에서 console창 보여주기
  win.loadFile('./index.html')  //랜더러의 파일
}
app.on('ready', createWindow) //준비되면 랜더러의 브라우저를 보여주기


const { ipcMain } = require('electron')  //이벤트 송/수신 관련 라이브러리
ipcMain.on('hi', (event, arg) => {  //dbconn요청이 들어오면,
  console.log(arg) // html로 받은 파라미터 
  event.reply('reply', 'good job')  //결과 완료 후 보낸다.
});

index.html

<!DOCTYPE html>
<html lang="ko">
<head><meta charset="UTF-8"></head>
<body>
  
  <button id="btn">hello world</button>

<script>
const { ipcRenderer } = require('electron');
document.getElementById("btn").addEventListener("click", function(){
  ipcRenderer.send('hi', 'hello world')
  ipcRenderer.on('reply', (event, arg) => {
    console.log(arg) 
  })
})
</script>
</body>
</html>

터미널에서

electron .

결과화면

설명

앱을 실행하고, [hello world] 를 클릭하면 랜더러의  ipcRenderer.send('hi',..)  에서 hi 를 메인으로 보낸다
메인에서는  ipcMain.on('hi',..)  에서 이벤트를 받아 처리하고  event.reply('reply',..) 에서 되돌려 준다.
최종적으로 랜더러의  ipcRenderer.on('reply',..)  에서 받아 로그창에 출력한다.

 

소스코드

electron-simple.zip
0.00MB

 

 

 

 

 

3. electron-router 사용법

이제는 기본앱에 electron-router 를 적용 해 봅시다

 

설치

npm install electron-router

package.json

{
  "name": "electron-router",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "electron-router": "^0.5.1"
  }
}

main.js

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

function createWindow () {  // 브라우저 창을 생성
  let win = new BrowserWindow({
    width: 600,
    height: 400,
    webPreferences: {
      nodeIntegration: true,  //랜더러(브라우저)에서 시스템에 직접 접근함, 보안상 좋지않음
      enableRemoteModule: true
    }
  })
  win.webContents.openDevTools()  //랜더러에서 console창 보여주기
  win.loadFile('./index.html')  //랜더러의 파일
}
app.on('ready', createWindow) //준비되면 랜더러의 브라우저를 보여주기


const Router = require('electron-router')
let router = Router('MAIN')

router.on('print', (msg) => {
  console.log('print : ' + msg);
})
router.get('/process', ( req, res ) => {
  console.log('get.process :' + JSON.stringify(req));
  // res.json('error','')  //에러일경우
  res.json('ok')  //성공일경우
});

index.html

<!DOCTYPE html>
<html lang="ko">
<head><meta charset="UTF-8"></head>
<body>
  
  <button id="btnSend">call send</button>
  <button id="btnGet">call get</button>

<script>


// In the renderer process
const $ = require('jquery')
const Router = require('electron-router')
let router = Router('ROUTER_RENDERER')

document.getElementById("btnSend").addEventListener("click", function(){
  router.send('print', 'send message, No response required')
})

document.getElementById("btnGet").addEventListener("click", function(){
  router.route('get', '/process', 'Request results after processing', ( err, result ) => {
    if(err !=null){
      console.error(err)
    }else{
      console.log(result)
    }
  })
})

</script>
</body>
</html>

터미널에서

electron .

결과화면

설명

앱을 실행하고, [call send] 를 클릭하면 랜더러의  router.send('print',..)  에서 메시지를 메인으로 보낸다
메인에서는 
router.on('print',..)  에서 이벤트를 받아 테미널에 로그를 출력하고 회신은 보내지 않는다.

[call get] 을 클릭하면 랜더러의 
router.route('get', '/process',..)  에서 메시지를 메인으로 보낸다
메인에서는 
router.get('/process', ..) 에서 이벤트를 받아 로그를 출력하고  res.json('ok')  으로 응답한다.
랜더러의 
( err, result ) => {}  에서 받아 브라우져콘솔 로그창에 ok 를 출력한다.

추가내용

사이트에 가 보면 아래와 같은 추가 설명이 들어 있으니 참고 하세요.

### Wildcards
Every sent/listened message can use wildcards
```javascript
router.on('loading::start', () => { console.log('start loading...') }
router.on('loading::continue', () => { console.log('continue loading...') }
router.on('loading::end', () => { console.log('end loading...') }

...

router.send('loading::start', ...) // logs "start loading"
router.send('loading::*', ...) // logs "start loading", "continue loading", "end loading"

```

#### Simple, plain communication
You can send messages unidirectionally from the main process to the renderer process and viceversa (analogous to electron's ipc) (Previous example)

#### Duplex communication with channels

```javascript
router.get('config::*')
router.post('config', ( req, res ) => {
	// req.params contain sent parameters
	// res.json sends data back
})
...

router.route('get', 'config::start', ( err, result ) => {
	console.log('got config', result)
})
```

## API

The router is just a static object, there will be one router in the main process and another one on the renderer. Just 'require' it and start listening/sending events/data. What this object does is route callbacks from one side to another passing parameters, triggered by different events.
It can listen to ipc events and send window events too.
HTTP Verbs are used just as different channels and for completness (equality to express)
For every route/event it is possible register wildcard ('*')

#### Instance
```javascript
// Constructs the object setting its name
let Router = require('electron-router')

// Returns the static instance
let router = Router( name )
```

#### Simple communication
```javascript
// Triggers/Sends a message on the given event name passing provided messages.
router.send( event, msg1, msg2... )

// Register a listener on the given event, triggering the callback when the event is sent.
// Callback receives the messages sent on the other side
router.on( event, ( msg1, msg2... ) => {})
```

#### Duplex communication
```javascript
// Triggers/Sends a message to the given route on the given method (channel, HTTP Verbs)
// passing the given messages to that channel/route handler. 
// Callback is called with err/result when the handler calls res.json()
// if the handler does not call the return function, callback is invoked with Err: Timeout

router.route( method, route, msg1, msg2..., ( err, result ) => {})

// Similar to router.routes.method( route, msg1, msg2..., ( err, result ) => {})

// All handlers on all channels are called with
// 	req { parameters: [], method: channel }
// 	res { json: [Function] } - function to call with (err, result), triggers the route back

// Registers handler on GET channel at the given route.
router.get( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on POST channel at the given route.
router.post( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on UPDATE channel at the given route.
router.update( route, ( req, res ) => {}) // must call res.json( err, result )

// Registers handler on DELETE channel at the given route.
router.delete( route, ( req, res ) => {}) // must call res.json( err, result )

소스코드

electron-router.zip
0.00MB

 

 

 

 

 

 

 

 

+ Recent posts