Skip to content
electron项目实践
Vue JavaScript CSS HTML
Branch: master
Clone or download
Latest commit 3e0ba09 Aug 23, 2017
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
app 修改版本号显示 Aug 16, 2017
build code spliting Aug 23, 2017
client code spliting Aug 23, 2017
git_img 修改README.md Aug 21, 2017
socket code spliting Aug 23, 2017
static first commit Jun 18, 2017
theme 设置窗口可拖动,以及引入element-ui Jun 24, 2017
.editorconfig first commit Jun 18, 2017
.eslintrc 修改app/index.js Jun 22, 2017
.gitignore '自动更新,electron-squirrel-startup报错,默认node-moudles没有打包,需要将其另外提取出来(暂时怎么处理)' Aug 15, 2017
Gruntfile.js 精简版本信息的修改 Aug 15, 2017
README.md
package.json 修改README.md Aug 21, 2017
yarn.lock code spliting Aug 23, 2017

README.md

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安装包生成
  • 新增各个模块功能
  • windows安装包生成 -- 完成
  • 应用自动更新 -- 完成
  • 中英文切换 -- 完成
  • 全局快捷键绑定 -- 完成
  • 即时通讯功能 -- 完成
  • excel表格导入导出 -- 完成
  • 登录功能 -- 完成
  • 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的,而且安装包没办法自定义安装目录,默认都是安装在C:\Users\Wushaobin\AppData\Local\XXX下面的。

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()
    })
}

参考资料:
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

You can’t perform that action at this time.