electron + vue 實踐項目


github地址

本地安裝環境准備

    npm install -g cnpm --registry=https://registry.npm.taobao.org
    因為npm的默認倉庫在國外,下載很慢,國內淘寶搞了個CNPM,每10分鍾同步一次,完全夠用了
  • 當然也可以使用yarn下載
    npm install -g yarn
    yarn install

依賴包安裝

  • 進入項目目錄
  • 執行cnpm install

安裝問題

  • cnpm install之后,可能會由於網絡不好而導致一些包安裝不完整,這里推薦使用yarn進行安裝
  • 需要額外安裝vue-style-loader、vue-template-compiler,不然vue-loader會報錯
  • electron配置項(config.js)為true時,運行npm run dev,瀏覽器訪問會報錯, Uncaught ReferenceError: require is not defined,原因可以去這里看,由於配置config.electron是開啟狀態,於是require被browserified化了,不是原先node原生require函數,所以在browser會出現此問題
  • 應用打包的時候,需要注意package.json的main配置項main,必須指向electron的主線程文件,此處為app/index.js

字體引入問題

對於webpack對於引入字體文件一直都會有問題,有時候你使用了file-laoder,url-loader,但是在使用還是會存在一些問題,比如渲染進程入口文件components/App.vue希望引入common.scsscommon.scss會去@import iconfont.css(字體樣式),這時候iconfont.css的字體路徑就會出現問題,webpack一直提示找不到依賴路徑。在開發環境下,我是將iconfont.cn獲取的字體文件遠程地址寫進build/index.html,這樣解決了問題。正式環境下,可以將字體文件代碼引入到App.vue文件中去

功能列表

  • [ ] mac安裝包生成
  • [ ] 新增各個模塊功能
  • [x] windows安裝包生成 -- 完成
  • [x] 應用自動更新 -- 完成
  • [x] 中英文切換 -- 完成
  • [x] 全局快捷鍵綁定 -- 完成
  • [x] 即時通訊功能 -- 完成
  • [x] excel表格導入導出 -- 完成
  • [x] 登錄功能 -- 完成
  • [x] mock.easy提供數據 -- 完成

development:


$ npm run dev
# express開啟服務,可以通過`http://localhost:port`訪問(熱重載)
# 原理:通過electron創建主體窗口,`mainWindow.loadURL(http://localhost:port)`,加載應用的 index.html

$ npm run app
# 運行`electron ./`,生成桌面應用

socket.io:


$ npm run socket

使用express + mongoDB + socket.io引入基於node的即時通訊模塊

本地調試時,只需運行npm run dev => npm run app,需要開啟即時通訊的功能的需要npm run sock,這里需要注意即時通訊模塊目前沒有遷移至服務器,要在本地運行,需要使用express起一個服務(./socket/),這里的數據庫集成使用的是mongoDB,所以必須要安裝mongoDB,然后配置環境變量(比如說我安裝的目錄是d:,我的環境變量這樣配置,D:\Program Files\MongoDB\Server\3.4\bin),這樣之后,便可以使用mongodmongo命令了,執行mongod命令,一般會報錯,默認存儲文檔的目錄沒有,那可以這樣,新建一個文件夾,用來存儲mongo產生的文檔對象,執行mongod --dbpath D:\mongodb\db,至於mongo(models/sechemas)、socket.io、express如何搭配去實現即時通訊的的功能,具體可以看代碼如何實現,對於這些新的東西,也只是了解個大概,后面准備花些時間去深入學習。

production:


$ npm run build
#生成正式文件到app/dist目錄(eletron應用目錄)

package:


$ npm run package:mac
$ npm run package:win
$ npm run package:linux
$ npm run package

將上一步`npm run build`后生成的正式文件,進行打包,生成程序,打包至`./package`目錄中

img

setup:


$ npm run setup

這里生成安裝包(僅適合於window),將上一步生成的package,通過grunt和grunt-electron-installer完成打包,打包至`./package_dir`

img

生成安裝包的過程:

  • npm run build
  • npm run package:win(目前只支持window)
  • npm run setup

對於打包工具,這里使用的是electron-packager,安裝命令:

rimraf package && electron-packager . TEST --platform=win32 --arch=x64 --overwrite --icon=hosts.ico --out=./package --electron-version=1.6.11 --version-string.CompanyName=TEST --version-string.ProductName=TEST --ignore=\"(build|client$|static|theme|.gitignore|LICENSE|README.md|.editorconfig|.eslintrc|node_modules|gruntPackage.json|Gruntfile.js|yarn.lock|socket|package_dir|git_img)\"

參數:

  • . => 應用目錄
  • TEST => 應用名稱
  • --platform=win32 => 要打包的平台
  • --overwrite => 覆蓋模式安裝
  • --icon=hosts.ico => 應用圖標(window時可以是.ico.png,mac時可以為.icns
  • --out=./package => 輸出目錄
  • --electron-version => electron版本
  • --version-string.CompanyName=TEST --version-string.ProductName=TEST => 為了生成安裝包的時候,應用名字為TEST,而不是默認的electron
  • --ignore=XXX => 忽略打包的目錄

詳細可看這里

打包成安裝程序,需要使用到gruntgrunt-electron-installer,請保證事先安裝好
package.json設置:

{
    "version": "1.0.0", // 這個是必須的,為了后面使用electron updater實現自動更新
    "productName": "my-electron",
    "description": "My Superb Vue Project For Electron",
    ......
}

Gruntfile.js文件如下詳細

var grunt = require('grunt')

// 配置
grunt.config.init({
    pkg: grunt.file.readJSON('package.json'), // 這里會去獲取版本號
    'create-windows-installer': {
        x64: {
            authors: 'xiaobinwu <xiaobin_wu@yahoo.com>', // 作者
            projectUrl: '',
            appDirectory: './package/TEST-win32-x64', // 要打包的輸入目錄
            outputDirectory: './package_dir', // grunt打包后的輸出目錄
            exe: 'TEST.exe', // 生成的exe文件
            description: 'My Superb Vue Project For Electron',
            setupIcon: './app/hots.ico', // 圖標
            noMsi: true // 是否生成.msi
        }
    }
})

// 加載任務
grunt.loadNpmTasks('grunt-electron-installer')

// 設置為默認
grunt.registerTask('default', ['create-windows-installer'])

於是就會生成如上圖所示的my-electronSetup.exe,點擊運行,進入一個安裝的過程,會有安裝的小動畫,如下圖:
gif
而我們需要的是安裝完后自動生成快捷方式,這里使用的electron-squirrel-startupnpm包,然后在主線程文件中app/index.js中寫入startupEventHandle方法,安裝時觸發squirrel.window的一些命令,將其放在創建主體窗口的回調函數中,代碼如下:

app.on('ready', function(){
    ......
    startupEventHandle()
    ......
})
......

function startupEventHandle () {
    if (require('electron-squirrel-startup')) { return }
    // 安裝和更新時添加快捷方式,刪除和卸載時刪除快捷方式
    var handleStartupEvent = function () {
        if (process.platform !== 'win32') {
            return false
        }
        var squirrelCommand = process.argv[1]
        switch (squirrelCommand) {
            case '--squirrel-install':
            case '--squirrel-updated':
                install()
                return true
            case '--squirrel-uninstall':
                uninstall()
                app.quit()
                return true
            case '--squirrel-obsolete':
                app.quit()
                return true
        }
        // 安裝
        function install () {
            var cp = require('child_process')
            var updateDotExe = path.resolve(path.dirname(process.execPath), '..', 'update.exe')
            var target = path.basename(process.execPath)
            var child = cp.spawn(updateDotExe, ['--createShortcut', target], { detached: true })
            child.on('close', function (code) {
                app.quit()
            })
        }
        // 卸載
        function uninstall () {
            var cp = require('child_process')
            var updateDotExe = path.resolve(path.dirname(process.execPath), '..', 'update.exe')
            var target = path.basename(process.execPath)
            var child = cp.spawn(updateDotExe, ['--removeShortcut', target], { detached: true })
            child.on('close', function (code) {
                app.quit()
            })
        }
    }
    if (handleStartupEvent()) {
        return
    }
}

這樣便可以在安裝時生成快捷方式,卸載時刪除快捷方式了,在這個過程中,有可能回報electron-squirrel-startup module not found類似的錯誤,那是electron-packager打包時,過濾掉了node_moudles目錄,所以需要手動添加到生成的package里面。至於網上的一些教程說,是需要安裝vs2015環境,並且將msbuild程序聲明成環境變量,但是我覺得應該是缺少npm包的原因,大家也可以試試,我本地是本來就安裝過vs2015的。

lint:


$ npm run lint
# lint項目(配置規則:.eslintrc)

上面的npm run script命令可能有些多,涉及的內容也比較多,文章后面會一一講解!下面上一波效果圖:

gif
gif
gif
gif
gif

electron自動更新

前面我們也有提到過自動更新,這里使用的官方提供的electron.autoUpdater模塊去更新,坑爹的是官方對這一功能的描述真是少之又少,autoUpdater的一些方法和事件這里可以去了解清楚,autoUpdater.setFeedURL(url)這一方法是重中之重,url放着高版本的文件(.exe,.nupkg,RELEASES),這里我是存儲在阿里oss,然后autoUpdater.checkForUpdates()會去檢查是否需要更新,它會觸發error、checking-for-update、update-available、update-downloaded中的一些事件,而我們需要利用主進程跟渲染進程之間的通訊(ipc/remote/webContent),來觸發更新,具體代碼如下:

function updateHandle () {
    ipcMain.on('check-for-update', function (event, arg) {
        if (process.platform !== 'win32') {
            return false
        }
        let appName = '門店系統'
        let appIcon = __dirname + '/hots.ico'
        let message = {
            error: '檢查更新出錯',
            checking: '正在檢查更新……',
            updateAva: '下載更新成功',
            updateNotAva: '現在使用的就是最新版本,不用更新',
            downloaded: '最新版本已下載,將在重啟程序后更新'
        }
        const os = require('os')
        const { dialog } = require('electron')
        // 放最新版本文件的文件夾的服務器地址
        // 阿里oss
        autoUpdater.setFeedURL('http://electron20170815.oss-cn-beijing.aliyuncs.com/electron/')
        autoUpdater.on('error', function (error) {
            return dialog.showMessageBox(mainWindow, {
                type: 'info',
                icon: appIcon,
                buttons: ['OK'],
                title: appName,
                message: message.error,
                detail: '\r' + error
            })
        })
        .on('checking-for-update', function (e) {
            return dialog.showMessageBox(mainWindow, {
                type: 'info',
                icon: appIcon,
                buttons: ['OK'],
                title: appName,
                message: message.checking
            })
        })
        .on('update-available', function (e) {
            var downloadConfirmation = dialog.showMessageBox(mainWindow, {
                type: 'info',
                icon: appIcon,
                buttons: ['OK'],
                title: appName,
                message: message.updateAva
            })
            if (downloadConfirmation === 0) {
                return
            }
        })
        .on('update-not-available', function (e) {
            return dialog.showMessageBox(mainWindow, {
                type: 'info',
                icon: appIcon,
                buttons: ['OK'],
                title: appName,
                message: message.updateNotAva
            })
        })
        .on('update-downloaded',  function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
            var index = dialog.showMessageBox(mainWindow, {
                type: 'info',
                icon: appIcon,
                buttons: ['現在重啟', '稍后重啟'],
                title: appName,
                message: message.downloaded,
                detail: releaseName + '\n\n' + releaseNotes
            })
            if (index === 1) { return }
            autoUpdater.quitAndInstall()
        })
        autoUpdater.checkForUpdates()
    })
}

如果內容對你有幫助的話,可以去github給個star!!!!

參考資料:
https://segmentfault.com/a/1190000008287730
https://segmentfault.com/a/1190000007616641
https://juejin.im/entry/5805e39ad20309006854e58f
https://github.com/hua1995116/webchat


Generated by VuePack.
vuePack Issue


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM