作为一个开发人员,工作中需要经常进行host
切换,快速在不同环境中进行开发测试,阿里内部有个iHost,用起来简单顺手,可惜并没有开放,离开后没有找到一款更好的用的host
切换工具,索性自己写一个。项目已经开源
, 欢迎吐槽。
所用到的技术
因为是桌面应用,作为一个前端开发,目前的首选自然是eletron, 前端框架选择react技术栈。
项目基于 生成,用到技术包括:
- react 16.x
- redux 4.x
- redux-thunk 2.x
- react-router 4.x
- ant-design 3.x
- reselect 3.x
- redux-actions 3.x
- webpack 4.x
- node-sass 4.x
主要逻辑和演示
整个应用的难度其实不大,主要就是生成一些条目,基于条目的激活状态对 host
文件进行读写,基本操作如下:
功能设计
-
三个tab页
- host设置页:进行host条目的增删改查
- 当前生效的host: 查看系统当前生效的host
- 原始host: 启动应用后会备份一份原始host稿件,用于还原
-
host 设置
- 能够创建一个host条目,编写对应的host
- 可以对host进行增删改查
- 同时可以创建一个host分组进行统一管理
- 点击左侧的 checkbox,编辑激活状态的host设置都会实时改变系统host,不过在编辑时设置了一个 2秒的延迟,避免在不断的输入过程中频繁读写文件
整个应用功能就是这么简单,一个关键点就是权限问题,要操作host文件需要改变/private/etc/host
文件的和/private/etc
目录的权限。所以在应用启动时会弹出输入电脑用户密码的弹窗进行授权。
记录几个主要技术使用
redux-actions和bindActionCreators
基于redux的项目有一个经常被诟病的地方在于action, reducer的繁琐,模板代码太多。 是一个不错的工具用来解决此问题,具体用法请自行学习。不过值得注意的一点是,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是可以嵌套,所以原始的bindActionCreators
和 redux-actions
配合起来很不舒服。项目中稍微改写了一下 使其支持嵌套。
对于一些基于计算性的数据,同时把原始数据和计算数据存储在store上不是一个好的方案,每次更新要进行双重更新,很容易产遗漏, redux
不同于 mobx
, mobx
存在computed
装饰器用于解决计算属性问题。 这个时候 就派上了用场,不仅解决了计算性数据问题,它更大的价值在于能够减少重复计算,每次rerender对于大量数据的计算可以在入参不变的情况下不重复计算。不过问题就是会多出一层selectors
层,可能也会让某些人抓狂吧,嘎嘎~~
state 持久化存储
为了每次打开App的时候保持之前的状态,整个store层需要存储下来,因此借助 写了一个简单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
。
带来的坑点
flow 和 eslint
和一些规则会在前期带来很多困扰和额外的工作,所以可以自行斟酌修改一些规则,不过对于Flow
和eslint
个人还是建议多多使用的,会减少很多后期的小问题。
但是项目中的eslint-import
插件在结合 webpack
设置alias
的时候会出现问题, 同样对于测试用例,webpack
的alias
配置也不会生效。
几个处理关键点:
- .eslintrc 需要改成.eslintrc.js
- .eslintrc.js中引用
path
需要require
, 不可以import
- 改成.eslintrc.js 在vscode中会出现
Eslint server
挂掉的问题,主要是因为项目中webpack.config.render.dev.js
中自己进行了环境变量的检测CheckNodeEnv('development')
, 注释掉此行代码。
在不断地更新,最新版的eslint配置可能已经和我当时不一致了,一些处理经验也有可能过时了,列出一些参考issue: , ,
图片的引用
引用图片的路径在打包后总是有问题,官方建议在render进程中通过 require
引入图片,走一遍 loader
生成 base64
的图片, 直接通过 path.join
和 __dirname
生成路径在开发环境没问题,但是打包后会报错。
然而,在主进程中要使用图片同样存在问题,上诉方案并不生效,目前尚未没有找到解决方案,已经提了相关
貌似electron
的静态资源路径在开发和生成环境是会有些问题,这里还需要进一步研究下,有了解的同学可以指教下。
shell的exec
本想使用 做一些命令处理,但是发现其有electron
兼容性问题
因为需求不复杂,直接用 child_process.exec
进行处理。
一个诡异的打包问题
由于图片引入问题,我会经常打包验证,回来发现一个问题,如果上一次的打包出现问题,修改后再次进行打包,发现程序仍然启动不了,这个时候需要断网启动才会成功。尚不了解什么原因。
阶段小结
第一次写一个完整的 electron 项目, 用于解决实际需求,还是挺有意思的,后续项目还要做一些测试,持续集成,自动更新的处理,目前经验还不足,各位社区的基友,请多指教指教,一起学习!