阅读 1335

electron写一个简单host切换工具

作为一个开发人员,工作中需要经常进行host切换,快速在不同环境中进行开发测试,阿里内部有个iHost,用起来简单顺手,可惜并没有开放,离开后没有找到一款更好的用的host切换工具,索性自己写一个。项目已经开源

代码地址 , 欢迎吐槽。

所用到的技术

因为是桌面应用,作为一个前端开发,目前的首选自然是eletron, 前端框架选择react技术栈。

项目基于 electron-react0-boilerplate 生成,用到技术包括:

  1. react 16.x
  2. redux 4.x
  3. redux-thunk 2.x
  4. react-router 4.x
  5. ant-design 3.x
  6. reselect 3.x
  7. redux-actions 3.x
  8. webpack 4.x
  9. node-sass 4.x

主要逻辑和演示

整个应用的难度其实不大,主要就是生成一些条目,基于条目的激活状态对 host 文件进行读写,基本操作如下:

功能设计

  1. 三个tab页
    • host设置页:进行host条目的增删改查
    • 当前生效的host: 查看系统当前生效的host
    • 原始host: 启动应用后会备份一份原始host稿件,用于还原
  2. host 设置
    • 能够创建一个host条目,编写对应的host
    • 可以对host进行增删改查
    • 同时可以创建一个host分组进行统一管理
    • 点击左侧的 checkbox,编辑激活状态的host设置都会实时改变系统host,不过在编辑时设置了一个 2秒的延迟,避免在不断的输入过程中频繁读写文件

整个应用功能就是这么简单,一个关键点就是权限问题,要操作host文件需要改变/private/etc/host文件的和/private/etc目录的权限。所以在应用启动时会弹出输入电脑用户密码的弹窗进行授权。

记录几个主要技术使用

redux-actions和bindActionCreators

基于redux的项目有一个经常被诟病的地方在于action, reducer的繁琐,模板代码太多。redux-actions 是一个不错的工具用来解决此问题,具体用法请自行学习。不过值得注意的一点是,redux的bindActionCreators 不支持对象嵌套的actionCreator, 例如

const actionsCreators = {
	add: function() {
		xx
	},
	change: {
		changeTitle: function() {
			xx
		},
		changeDate: function() {
			xx
		}
	}
}

const { add, change } = bindActionCreators(actionsCreator, dispatch)


复制代码

这里 change 中的actionCreators是不会绑定成功的,由于redux-actions生成的actionCreators是可以嵌套,所以原始的bindActionCreatorsredux-actions 配合起来很不舒服。项目中稍微改写了一下 bindActionCreators 使其支持嵌套。

reselect

对于一些基于计算性的数据,同时把原始数据和计算数据存储在store上不是一个好的方案,每次更新要进行双重更新,很容易产遗漏, redux 不同于 mobx, mobx 存在computed 装饰器用于解决计算属性问题。 这个时候reselect 就派上了用场,不仅解决了计算性数据问题,它更大的价值在于能够减少重复计算,每次rerender对于大量数据的计算可以在入参不变的情况下不重复计算。不过问题就是会多出一层selectors 层,可能也会让某些人抓狂吧,嘎嘎~~

state 持久化存储

为了每次打开App的时候保持之前的状态,整个store层需要存储下来,因此借助 electron-json-storage 写了一个简单redux 中间件:


import storage from 'electron-json-storage';

// 同步 store 到某个文件的持久化存储中间件, 基于electron-json-storage做存储

const storageState = store => dispatch => action => {

  dispatch(action);
  
  const nextState = store.getState();
  
  const { menuTree, checkedKeys } = nextState.host.menus;
  
  const { systemHost } = nextState.host.systemHost;
  
  const defaultDataPath = 	storage.getDefaultDataPath();
  
  const dataPath = storage.getDataPath();
  
  console.log('paths:', defaultDataPath, dataPath);
  
  storage.set('HostState-xu', nextState); // 会创建一个HostState-xu.json的文件,尽可能保证唯一性,不与其他应用冲突
};
export default storageState;

复制代码

每一次action改变都同步保持state

electron-react-boilerplate 带来的坑点

flow 和 eslint

Flow和一些eslint规则会在前期带来很多困扰和额外的工作,所以可以自行斟酌修改一些规则,不过对于Floweslint个人还是建议多多使用的,会减少很多后期的小问题。

但是项目中的eslint-import插件在结合 webpack 设置alias的时候会出现问题, 同样对于测试用例,webpackalias配置也不会生效。

几个处理关键点:

  1. .eslintrc 需要改成.eslintrc.js
  2. .eslintrc.js中引用path 需要require, 不可以 import
  3. 改成.eslintrc.js 在vscode中会出现Eslint server挂掉的问题,主要是因为项目中webpack.config.render.dev.js中自己进行了环境变量的检测CheckNodeEnv('development'), 注释掉此行代码。

electron-react-boilerplate 在不断地更新,最新版的eslint配置可能已经和我当时不一致了,一些处理经验也有可能过时了,列出一些参考issue: #620 ,#1321 , #1509

图片的引用

引用图片的路径在打包后总是有问题,官方建议在render进程中通过 require 引入图片,走一遍 loader 生成 base64 的图片, 直接通过 path.join__dirname 生成路径在开发环境没问题,但是打包后会报错。

然而,在主进程中要使用图片同样存在问题,上诉方案并不生效,目前尚未没有找到解决方案,已经提了相关issue

貌似electron的静态资源路径在开发和生成环境是会有些问题,这里还需要进一步研究下,有了解的同学可以指教下。

shell的exec

本想使用 shelljs 做一些命令处理,但是发现其有electron 兼容性问题 electron-compatibility

因为需求不复杂,直接用 child_process.exec 进行处理。

一个诡异的打包问题

由于图片引入问题,我会经常打包验证,回来发现一个问题,如果上一次的打包出现问题,修改后再次进行打包,发现程序仍然启动不了,这个时候需要断网启动才会成功。尚不了解什么原因。

阶段小结

第一次写一个完整的 electron 项目, 用于解决实际需求,还是挺有意思的,后续项目还要做一些测试,持续集成,自动更新的处理,目前经验还不足,各位社区的基友,请多指教指教,一起学习!

关注下面的标签,发现更多相似文章
评论