用JavaScript开发桌面应用:Electron + React DeskTop开发环境搭建

1,402 阅读5分钟
原文链接: www.jianshu.com

随着JavaScript开源社区的发展,JavaScript的应用场景越来越广泛,到目前为止,JavaScript在Web开发、桌面开发、APP开发、服务端开发方面都可以胜任。

在桌面开发方面,Electron是我个人最喜欢的解决方案,它基于HTML、CSS、JavaScript,跨平台。目前有很多优秀的桌面软件都是使用Electron开发的:清单

Electron案例 Electron案例

(没错,微软的VSCode也是Electron开发的,微软居然没用自己的开发套件,可见Electron的桌面解决方案应该是很优秀的。)

创建一个简单的桌面应用

前提条件是在开发环境必须安装了NodeJS

  1. 安装Electron
    npm install electron -g
  2. 创建一个目录和必备文件
    mkdir hello-world && cd hello-world
    touch main.js && touch package.json && touch index.html
  3. 在package.json文件中写入
{
  "name"    : "your-app",
  "version" : "0.1.0",
  "main"    : "main.js"
}
  1. 在main.js文件中写入
const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

function createWindow () {
  // Create the browser window.
  win = new BrowserWindow({width: 800, height: 600})

  // and load the index.html of the app.
  win.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // Open the DevTools.
  win.webContents.openDevTools()

  // Emitted when the window is closed.
  win.on('closed', () => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (win === null) {
    createWindow()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
  1. 在index.html中写入
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using node <script>document.write(process.versions.node)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>
  1. 在终端运行
    electron .

  2. 你可以看到一个桌面应用程序


    第一个应用

Electron详细文档可以参看官方文档

创建一个React项目

用Electron创建一个桌面应用很简单,但是用HTML+Javascript肯定会需要用到一些前端库来辅助开发。

目前比较主流的前端库Vue.JS、AngularJS以及ReactJS。三个库/框架都很优秀,不过我选择了React。

React创建一个项目其实很繁琐,因为它用了JSX,所以需要配置Babelwebpack or Browserify

不过好在官方提供了一个工具 Create React App,可以非常简单快速的创建React 项目,并且提供了热调试环境。详细参考官方文档

简单的来说,Create React App 创建了一个React的项目模版、配置,并且提供了一些很方便的脚本命令用于调试和部署React前端程序。

使用Create React App创建的项目可以通过 npm start 启动http://localhost:3000/ 服务热调试;通过npm run build 编译所有文件放在根目录下build目录里。

整合Electron和React

Create React App创建的项目是一个纯前端项目,整合React项目和Electron并且保留热调试和本地包引用需要以下几个简单的操作

  1. 需要在React项目的根目录(不是src目录)创建Electron的启动文件main.js(前文中有详细内容)
  2. 在React项目中的package.json文件中增加main字段,值为 "./main.js"
  3. 修改main.js 中的win.loadURL,改为
 win.loadURL(url.format({
    pathname: path.join(__dirname, './build/index.html'),
    protocol: 'file:',
    slashes: true
  }))

到目前为止,在根目录下运行 electron .就可以启动React创建的桌面应用了。

但是还有几个问题

  • 资源文件显示不出来,在调试面板出现找不到文件的错误提示
  • 每次都要 npm run build 后才能看到修改项
  • 无法获得系统包,例如用 os.cpus()无法得到系统cpus信息。

解决这些问题还需要几个小步骤

  1. 修改package.json添加字段 "homepage":"."
    默认情况下,homepage是 http://localhost:3000 ,build后,所有资源文件路径都是/static,而Electron调用的入口是以file:协议,/staitc就会定位到系统的根目录去,所以找不到静态文件。在package.json文件中添加homepage字段并设置为"."后,静态文件的路径就变成了相对路径,就能正确的找到了。

  2. main.js启动页修改为 http://localhost:3000/

 win.loadURL('http://localhost:3000/')

开发时,启动nom start 后,在另一个终端启动 electron . 这样在electron中就可以热调试了

不过编译后需要改回从build/index.html启动,这样很麻烦,可以在package.json中定义个 DEV字段,设置为 true/false,然后修改main.js 代码如下:

  const pkg = require('./package.json') // 引用package.json

//判断是否是开发模式
  if(pkg.DEV){
      win.loadURL("http://localhost:3000/")
  }else{
    win.loadURL(url.format({
    pathname: path.join(__dirname, './build/index.html'),
    protocol: 'file:',
    slashes: true
  }))
}

以后运行electron .之前,根据需要修改DEV为true/false就行了

最后,无论是运行build中的index.html还是http://localhost:3000 都无法通过require调用本地包的,需要使用window.require。

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

var os = window.require('os') // not be : var os = require('os')
console.log("got:",os.cpus())

class App extends Component {
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
        </div>
         CPU count: {os.cpus().length}
      </div>
    );
  }
}
export default App;

使用require

Paste_Image.png

使用window.require

Paste_Image.png

无论启动页是 http://localhost:3000/ 还是 build/index.html都有效。

至此,整合Electron和React就完成了,整个过程大部分工作都使用React官方和Electron官方提供的工具生成工程项目,只需要修改几个配置和入口文件即可。

总结一下

  1. 用Create-React-App创建React项目
  2. 根目录下创建Electron入口文件 main.js,修改main.js的启动页
  3. 在package.json中添加main字段为"main.js",添加 homepage字段为".",添加DEV字段为true/false(DEV字段选择性添加,如果你更喜欢修改mian.JS的话)
  4. 应用本地库使用window.require替代require

欢迎大家简书或我的个人博客与我交流