這篇隨筆記錄一下electron + vue與nodejs 的一些開發的過程和問題..隨緣更新css
最近基於Electron作一個針對UE4應用的進程守護和更新啓動器...html
花費大量了時間的處理來UI線程堵塞的問題上了(吐槽感受Nodejs IO和線程不是hin好用..)vue
涉及的技術點估計之後不會怎麼經常使用,因此寫篇隨筆整理一下node
electron啓動更新器:linux
github: https://github.com/linqingwudiv1/electron-startupgit
----------------------------------------割-------------------------------------------------------------github
Electron+ Vue環境:web
Vue環境目前有倆個比較好用的開發環境:vue-cli
1.electron-vue: https://github.com/SimulatedGREG/electron-vuetypescript
2.Vue + Vue CLI Plugin Electron Builder
區別
electron-vue 是基於vue-cli 2.0的快速開發框架
Plugin Electron Builder是vue-cli 3.X的electron 腳手架插件.
我用的是 Electron Builder...
Vue cli 3.x版本的Vue + Vue CLI Plugin Electron Builder整合的Electron應用
插件使用文檔 : https://github.com/nklayman/vue-cli-plugin-electron-builder
VS Code 斷點調試配置指南: https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/recipes.html#table-of-contents
Electron Vue DevTools配置指南:https://github.com/vuejs/vue-devtools/blob/dev/packages/shell-electron/README.md
參考:
1.electron的渲染進程xmlhttprequest的cors問題/開啓nodejs和Worker線程等:
win = new BrowserWindow( { width: 800, height: 600, backgroundColor: '#ffffff', webPreferences: { nodeIntegration: true, webSecurity: false, //cors nodeIntegrationInWorker: true // } });
2.Nodejs/electron下 解壓zip
使用 adm-zip-ex解壓實例:
const AdmZip = require('adm-zip-ex'); let zip = new AdmZip("d://Test.zip"); zip.extractAllTo('d:/temp');
adm-zip-ex單個entry的異步解壓示例:
let zip = new AdmZip('c:temp.zip'); let zipEntries = zip.getEntries(); zipEntries.forEach( ( zipEntry:any, index:number ) => { if ( zipEntry == null ) { return; } const entryPath = join( 'c:/', zipEntry.entryName); if ( zipEntry.isDirectory ) { return; } let path = dirname( entryPath ); // unzip entry...... zip.extractEntryToAsync(zipEntry, path , true, (err:any) => { if ( err != undefined ) { console.log(err); return; } //do something..... }); });
3.nodejs怎麼進行流文件下載:
用nodejs的http模塊或electron的net模塊均可以,可是太底層了,建議用 request或request-promise庫,是對於nodejs的網絡模塊封裝的,ts版本:@types/request 文檔:https://github.com/request/request
http下載文件:
request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))
若是有大文件下載需求,請添加 request-progress-ex模塊,跟request組合使用..
https://www.npmjs.com/package/request-progress-ex
附 request-promise幫助類:
import request, { RequestPromiseOptions } from 'request-promise'; let options:RequestPromiseOptions = { baseUrl: process.env.APP_BIZ_BASE_API, qs: { //access_token: 'xxxxx xxxxx' // -> uri + '?access_token=xxxxx%20xxxxx' }, headers: { 'User-Agent': 'Request-Promise' }, json: true // Automatically parses the JSON string in the response }; let services =request.defaults(options); export default services;
4.worker_threading(線程):
https://github.com/wilk/microjob/blob/master/GUIDE.md
5.進程通信的基本例子:
note:也可使用remote調用main process進程功能或模塊.可是不推薦這麼作,由於破壞了electron的封裝性
https://electronjs.org/docs/api/ipc-main
remote例子:
import {remote} from 'electron'; const { app } = remote;
6.electron 怎麼系統托盤app?
例子(typescript):
Browser事件處理:(close事件能夠根據自身狀況處理)
GWin.MainWindow.on('minimize',(ev:any)=> { if (GWin.MainWindow !=null) { console.log('on minimize...'); GWin.MainWindow.setSkipTaskbar(true); GWin.MainWindow.hide(); } ev.preventDefault(); });
建立系統托盤 tray類:
electron:隱藏任務欄條 setSkipTaskbar(true)
electron:顯示任務欄條setSkipTaskbar(false)
note:注意new Tray('ico.jpg')時,ico.jpg必須存在,不然托盤圖標將不顯示..沒法點擊
GWin.TrayIcon = new Tray('ico.jpg'); const contextMenu = Menu.buildFromTemplate([ { label: '顯示', //type: 'radio', click:()=> { if(GWin.MainWindow != null) { GWin.MainWindow.show(); GWin.MainWindow.setSkipTaskbar(false); } } }, { label: '退出', //type: 'radio' click:()=> { app.quit(); } } ]) GWin.TrayIcon.setToolTip('更新啓動器'); GWin.TrayIcon.setContextMenu(contextMenu);
7.NodeJS從文件中讀取json:
ts
let jsonStr:string = readFileSync('UE/version.json', { encoding: 'utf-8' });
js
let jsonStr = fs.readFileSync('UE/version.json', { encoding: 'utf-8' });
8.Electron持久化配置到磁盤文件:
其實能夠用nodejs模塊本身IO到json文件,可是比較麻煩,須要本身封裝接口
並且已經有相關的electron-store類庫了..
https://github.com/sindresorhus/electron-store
typescript 版本:
npm install @types/electron-store
electron-store 每次set 或get都是從disk文件讀寫配置信息
簡單的使用示例:(建議寫成這樣的單例)
/** * Electron-Store的配置內容 */ interface SystemStore { CacheDir: string; } /** * 整個App的全局變量,或函數 */ export default class GApp { /** 系統持久化配置實例 */ private static sysStore?:Store<SystemStore> = undefined; /** Get 系統持久化配置單例 */ public static get SystemStore():Store<SystemStore> { if (GApp.sysStore == undefined) { GApp.sysStore = new Store<SystemStore>({ defaults: { CacheDir: GApp.RootDir + '/cache/' } }); } return GApp.sysStore; } }
9.Nodejs獲取指定文件的所在目錄:
import {dirname} from 'path'; let dir = dirname(`d:/test/ttt/helloworld.png`);
10.Nodejs遞歸建立目錄:
nodejs 的mkdir()目前還不能 建立多級路徑...
如C:/a/b/c 若是C:/a/b 路徑還不存在則報錯..
(v13.x)
實現:
雖然也能夠本身寫遞歸調用mkdir(),
但仍是推薦使用 shelljs 類庫 用mkdir腳本建立路徑...(linux環境須要加 -p)
Q.Electron無邊框模式並自定義標題欄:
官方參考:
https://electronjs.org/docs/api/frameless-window
Electron自定義標題欄很是簡單..
Step1:開啓無邊框模式:
如
let win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: false })
Step2:render進程編寫標題欄Div和處理事件
並添加關鍵css
-webkit-user-select : none; -webkit-app-region : drag;
這兩個css屬性會自動識別爲可拖拽區,使之能像標題欄同樣隨意移動窗口..
如:
<div class="titlebar-btn-group"> <el-button id="btn-close" size="medium" type="text" icon="el-icon-close"></el-button> </div>
width:150px; background: green; position : fixed; top:10px; right :10px; -webkit-user-select : none; -webkit-app-region : drag;
width:150px; background: green; position : fixed; top:10px; right :10px; -webkit-user-select : none; -webkit-app-region : drag;
Note:
若是隻是但願把菜單欄移到標題欄上,推薦使用:
Electron自定義標題欄 (Custom Title Bar)插件:https://github.com/AlexTorresSk/custom-electron-titlebar
若是隻是須要自定義拖拽移動區: