用JavaScript开发桌面应用:Electron + Rea
随着JavaScript开源社区的发展,JavaScript的应用场景越来越广泛,到目前为止,JavaScript在Web开发、桌面开发、APP开发、服务端开发方面都可以胜任。
在桌面开发方面,Electron是我个人最喜欢的解决方案,它基于HTML、CSS、JavaScript,跨平台。目前有很多优秀的桌面软件都是使用Electron开发的:清单
Electron案例 Electron案例(没错,微软的VSCode也是Electron开发的,微软居然没用自己的开发套件,可见Electron的桌面解决方案应该是很优秀的。)
创建一个简单的桌面应用
前提条件是在开发环境必须安装了NodeJS
- 安装Electron
npm install electron -g
- 创建一个目录和必备文件
mkdir hello-world && cd hello-world
touch main.js && touch package.json && touch index.html
- 在package.json文件中写入
{
"name" : "your-app",
"version" : "0.1.0",
"main" : "main.js"
}
- 在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.
- 在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>
-
在终端运行
electron .
-
你可以看到一个桌面应用程序
第一个应用
Electron详细文档可以参看官方文档
创建一个React项目
用Electron创建一个桌面应用很简单,但是用HTML+Javascript肯定会需要用到一些前端库来辅助开发。
目前比较主流的前端库Vue.JS、AngularJS以及ReactJS。三个库/框架都很优秀,不过我选择了React。
React创建一个项目其实很繁琐,因为它用了JSX,所以需要配置Babel、webpack 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并且保留热调试和本地包引用需要以下几个简单的操作
- 需要在React项目的根目录(不是src目录)创建Electron的启动文件main.js(前文中有详细内容)
- 在React项目中的package.json文件中增加main字段,值为 "./main.js"
- 修改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信息。
解决这些问题还需要几个小步骤
-
修改package.json添加字段
"homepage":"."
默认情况下,homepage是 http://localhost:3000 ,build后,所有资源文件路径都是/static
,而Electron调用的入口是以file:协议,/staitc就会定位到系统的根目录去,所以找不到静态文件。在package.json文件中添加homepage字段并设置为"."后,静态文件的路径就变成了相对路径,就能正确的找到了。 -
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官方提供的工具生成工程项目,只需要修改几个配置和入口文件即可。
总结一下
- 用Create-React-App创建React项目
- 根目录下创建Electron入口文件 main.js,修改main.js的启动页
- 在package.json中添加main字段为"main.js",添加 homepage字段为".",添加DEV字段为true/false(DEV字段选择性添加,如果你更喜欢修改mian.JS的话)
- 应用本地库使用window.require替代require
欢迎大家简书或我的个人博客与我交流