electron寫一個簡單host切換工具

nanjixiong發表於2018-09-06

作為一個開發人員,工作中需要經常進行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 檔案進行讀寫,基本操作如下:

electron寫一個簡單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 專案, 用於解決實際需求,還是挺有意思的,後續專案還要做一些測試,持續整合,自動更新的處理,目前經驗還不足,各位社群的基友,請多指教指教,一起學習!

相關文章