iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 26
0
Modern Web

Next.js + 各種套件組合系列 第 27

Next.js & Electron

介紹
Electron 是可以做一個跨平台的桌面應用軟體。 Electron 是個用 JavaScrtip、HTML 及 CSS 等網頁技術開發原生應用程式的框架。因為 Electron的後端是使用node.js 前端是使用 javascript Html,用React 有模組化開發更方便。

實際上 Electron 他的後端有自己的node.js環境 ,我們只需要 靜態頁面的部分所以會使用next export來產生文件給 Electron 使用

安裝

 省略...
  "devDependencies"
    "electron"
    "electron-builder"
 省略...
  "dependencies"
    "electron-is-dev": "0.3.0",
    "electron-next": "3.0.8"
 省略...

在 Electron 的entry有一個 node 跑 electron 透過 ipcMain與前端溝通,Electron的架構很簡單跟網頁一樣,並使用chromium 的方式執行

這邊的 prepareNext 使用 'electron-next'套件來把 Next export的靜態網頁 跑一個網頁或是靜態檔案給Electron可以正常使用

格式 可以指定 port
  await  prepareRenderer(< path >,< port >)
  
  await prepareNext('./renderer')

發佈產品的話會使用 file ://協議 (next export 的靜態檔案)
開發模式,會起一個server來跑網頁模式這樣比較方便開發,

  const url = isDev
    ? 'http://localhost:8000/start'
    : format({
      pathname: join(__dirname, '../renderer/start/index.html'),
      protocol: 'file:',
      slashes: true
    })

// Native
const { join } = require('path')
const { format } = require('url')

// Packages
const { BrowserWindow, app, ipcMain } = require('electron')
const isDev = require('electron-is-dev')
const prepareNext = require('electron-next')

// Prepare the renderer once the app is ready
app.on('ready', async () => {
  await prepareNext('./renderer')

  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600
  })
   const url = isDev
    ? 'http://localhost:8000/start'
    : format({
      pathname: join(__dirname, '../renderer/start/index.html'),
      protocol: 'file:',
      slashes: true
    })

  mainWindow.loadURL(url)
})

// 關閉事件
app.on('window-all-closed', app.quit)

// 透過ipcMain與前端溝通 
ipcMain.on('message', (event, message) => {
  event.sender.send('message', message)
})


前端部分 主要是載入 import { ipcRenderer } from 'electron' 要來跟 node ipcMan溝通
生命週期 起始的時候 componentDidMount 與結束的時候 做監聽與移除監聽

ipcRenderer.on('message', this.handleMessage)
ipcRenderer.removeListener('message', this.handleMessage)
之後透過 ipcRenderer.send('message', this.state.input) 的部分就可以跟node定義好的部分做溝通了

import { Component } from 'react'
import { ipcRenderer } from 'electron'

export default class extends Component {
  state = {
    input: '',
    message: null
  }

  componentDidMount () {
    // start listening the channel message
    ipcRenderer.on('message', this.handleMessage)
  }

  componentWillUnmount () {
    // stop listening the channel message
    ipcRenderer.removeListener('message', this.handleMessage)
  }

  handleMessage = (event, message) => {
    // receive a message from the main process and save it in the local state
    this.setState({ message })
  }

  handleChange = event => {
    this.setState({ input: event.target.value })
  }

  handleSubmit = event => {
    event.preventDefault()
    ipcRenderer.send('message', this.state.input)
    this.setState({ message: null })
  }

  render () {
    return (
      <div>
        <h1>Hello Electron!</h1>

        {this.state.message &&
          <p>{this.state.message}</p>
        }

        <form onSubmit={this.handleSubmit}>
          <input type='text' onChange={this.handleChange} />
        </form>

        <style jsx>{`
          h1 {
            color: red;
            font-size: 50px;
          }
        `}</style>
      </div>
    )
  }
}


總結

Electron 中 只會使用到 Next.js 靜態網頁, 而Next.js的強項是 SSR Code splitting 還有一些代理webpack與File-system route,比較不太能感受 Next 的好處, 這樣的開發環境的優點是可以滿乾淨方便的 Route 使用filesystem 就搞定


上一篇
Next.js & Firebase Database (二)
下一篇
Next.js & 組合介紹 (一)
系列文
Next.js + 各種套件組合30

尚未有邦友留言

立即登入留言