天气真不错 發表於 2017-8-22 09:59:00

electron + vue 实践项目

<h1 id="github地址">github地址</h1>
<h4 id="本地安装环境准备">本地安装环境准备</h4>
<ul>
<li>安装node: * https://nodejs.org/en/download/</li>
<li>配置webpack: npm install -g webpack(sudo权限)</li>
<li>windows配置cnpm:</li>
</ul>
<pre><code class="language-bash">    npm install -g cnpm --registry=https://registry.npm.taobao.org
    因为npm的默认仓库在国外,下载很慢,国内淘宝搞了个CNPM,每10分钟同步一次,完全够用了
</code></pre>
<ul>
<li>当然也可以使用yarn下载</li>
</ul>
<pre><code class="language-bash">    npm install -g yarn
    yarn install
</code></pre>
<h4 id="依赖包安装">依赖包安装</h4>
<ul>
<li>进入项目目录</li>
<li>执行cnpm install</li>
</ul>
<h4 id="安装问题">安装问题</h4>
<blockquote>
<ul>
<li>cnpm install之后,可能会由于网络不好而导致一些包安装不完整,这里推荐使用yarn进行安装</li>
<li>需要额外安装vue-style-loader、vue-template-compiler,不然vue-loader会报错</li>
<li>electron配置项(config.js)为true时,运行npm run dev,浏览器访问会报错, <code>Uncaught ReferenceError: require is not defined</code>,原因可以去这里看,由于配置config.electron是开启状态,于是require被browserified化了,不是原先node原生require函数,所以在browser会出现此问题</li>
<li>应用打包的时候,需要注意package.json的main配置项main,必须指向electron的主线程文件,此处为app/index.js</li>
</ul>
</blockquote>
<h4 id="字体引入问题">字体引入问题</h4>
<p>对于webpack对于引入字体文件一直都会有问题,有时候你使用了file-laoder,url-loader,但是在使用还是会存在一些问题,比如渲染进程入口文件components/App.vue希望引入<code>common.scss</code>,<code>common.scss</code>会去<code>@import iconfont.css</code>(字体样式),这时候<code>iconfont.css</code>的字体路径就会出现问题,webpack一直提示找不到依赖路径。在开发环境下,我是将iconfont.cn获取的字体文件远程地址写进build/index.html,这样解决了问题。正式环境下,可以将字体文件代码引入到App.vue文件中去</p>
<h3 id="功能列表">功能列表</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input class="task-list-item-checkbox" disabled="" type="checkbox"><label>mac安装包生成</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" disabled="" type="checkbox"><label>新增各个模块功能</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> windows安装包生成 -- 完成</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 应用自动更新 -- 完成</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 中英文切换 -- 完成</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 全局快捷键绑定 -- 完成</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 即时通讯功能 -- 完成</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> excel表格导入导出 -- 完成</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> 登录功能 -- 完成</label></li>
<li class="task-list-item"><input class="task-list-item-checkbox" checked="" disabled="" type="checkbox"><label> mock.easy提供数据 -- 完成</label></li>
</ul>
<p>development:</p>
<pre><code class="language-bash">
$ npm run dev
# express开启服务,可以通过`http://localhost:port`访问(热重载)
# 原理:通过electron创建主体窗口,`mainWindow.loadURL(http://localhost:port)`,加载应用的 index.html

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

</code></pre>
<p>socket.io:</p>
<pre><code class="language-bash">
$ npm run socket

使用express + mongoDB + socket.io引入基于node的即时通讯模块

</code></pre>
<p>本地调试时,只需运行<code>npm run dev</code> <strong>=&gt;</strong> <code>npm run app</code>,需要开启即时通讯的功能的需要<code>npm run sock</code>,这里需要注意即时通讯模块目前没有迁移至服务器,要在本地运行,需要使用express起一个服务(<code>./socket/</code>),这里的数据库集成使用的是mongoDB,所以必须要安装mongoDB,然后配置环境变量(比如说我安装的目录是<code>d:</code>,我的环境变量这样配置,<code>D:\Program Files\MongoDB\Server\3.4\bin</code>),这样之后,便可以使用<code>mongod</code>、<code>mongo</code>命令了,执行<code>mongod</code>命令,一般会报错,默认存储文档的目录没有,那可以这样,新建一个文件夹,用来存储mongo产生的文档对象,执行<code>mongod --dbpath D:\mongodb\db</code>,至于mongo(models/sechemas)、socket.io、express如何搭配去实现即时通讯的的功能,具体可以看代码如何实现,对于这些新的东西,也只是了解个大概,后面准备花些时间去深入学习。</p>
<p>production:</p>
<pre><code class="language-bash">
$ npm run build
#生成正式文件到app/dist目录(eletron应用目录)

</code></pre>
<p>package:</p>
<pre><code class="language-bash">
$ npm run package:mac
$ npm run package:win
$ npm run package:linux
$ npm run package

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

</code></pre>
<p><img src="https://raw.githubusercontent.com/xiaobinwu/electron-vue-project/master/git_img/1.png"></p>
<p>setup:</p>
<pre><code class="language-bash">
$ npm run setup

这里生成安装包(仅适合于window),将上一步生成的package,通过grunt和grunt-electron-installer完成打包,打包至`./package_dir`

</code></pre>
<p><img src="https://raw.githubusercontent.com/xiaobinwu/electron-vue-project/master/git_img/2.png"></p>
<p>生成安装包的过程:</p>
<blockquote>
<ul>
<li>npm run build</li>
<li>npm run package:win(目前只支持window)</li>
<li>npm run setup</li>
</ul>
</blockquote>
<p>对于打包工具,这里使用的是<code>electron-packager</code>,安装命令:</p>
<pre><code>rimraf package &amp;&amp; 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)\"

</code></pre>
<p>参数:</p>
<blockquote>
<ul>
<li><code>.</code> =&gt; 应用目录</li>
<li><code>TEST</code> =&gt; 应用名称</li>
<li><code>--platform=win32</code> =&gt; 要打包的平台</li>
<li><code>--overwrite</code> =&gt; 覆盖模式安装</li>
<li><code>--icon=hosts.ico</code> =&gt; 应用图标(window时可以是<code>.ico</code>、<code>.png</code>,mac时可以为<code>.icns</code>)</li>
<li><code>--out=./package</code> =&gt; 输出目录</li>
<li><code>--electron-version</code> =&gt; electron版本</li>
<li><code>--version-string.CompanyName=TEST --version-string.ProductName=TEST</code> =&gt; 为了生成安装包的时候,应用名字为<code>TEST</code>,而不是默认的<code>electron</code></li>
<li><code>--ignore=XXX</code> =&gt; 忽略打包的目录</li>
</ul>
</blockquote>
<p>详细可看这里</p>
<p>打包成安装程序,需要使用到<code>grunt</code>、<code>grunt-electron-installer</code>,请保证事先安装好<br>
在<code>package.json</code>设置:</p>
<pre><code>{
    "version": "1.0.0", // 这个是必须的,为了后面使用electron updater实现自动更新
    "productName": "my-electron",
    "description": "My Superb Vue Project For Electron",
    ......
}
</code></pre>
<p>Gruntfile.js文件如下详细:</p>
<pre><code>var grunt = require('grunt')

// 配置
grunt.config.init({
    pkg: grunt.file.readJSON('package.json'), // 这里会去获取版本号
    'create-windows-installer': {
      x64: {
            authors: 'xiaobinwu &lt;xiaobin_wu@yahoo.com&gt;', // 作者
            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'])

</code></pre>
<p>于是就会生成如上图所示的<code>my-electronSetup.exe</code>,点击运行,进入一个安装的过程,会有安装的小动画,如下图:<br>
<img src="https://raw.githubusercontent.com/xiaobinwu/electron-vue-project/master/git_img/setup.gif"><br>
而我们需要的是安装完后自动生成快捷方式,这里使用的<code>electron-squirrel-startup</code>npm包,然后在主线程文件中app/index.js中写入<code>startupEventHandle</code>方法,安装时触发squirrel.window的一些命令,将其放在创建主体窗口的回调函数中,代码如下:</p>
<pre><code>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
      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
    }
}

</code></pre>
<p>这样便可以在安装时生成快捷方式,卸载时删除快捷方式了,在这个过程中,有可能回报<code>electron-squirrel-startup module not found</code>类似的错误,那是<code>electron-packager</code>打包时,过滤掉了<code>node_moudles</code>目录,所以需要手动添加到生成的package里面。至于网上的一些教程说,是需要安装vs2015环境,并且将msbuild程序声明成环境变量,但是我觉得应该是缺少npm包的原因,大家也可以试试,我本地是本来就安装过vs2015的。</p>
<p>lint:</p>
<pre><code class="language-bash">
$ npm run lint
# lint项目(配置规则:.eslintrc)

</code></pre>
<blockquote>
<p>上面的npm run script命令可能有些多,涉及的内容也比较多,文章后面会一一讲解!下面上一波效果图:</p>
</blockquote>
<p><img src="https://raw.githubusercontent.com/xiaobinwu/electron-vue-project/master/git_img/1.gif"><br>
<img src="https://raw.githubusercontent.com/xiaobinwu/electron-vue-project/master/git_img/2.gif"><br>
<img src="https://raw.githubusercontent.com/xiaobinwu/electron-vue-project/master/git_img/3.gif"><br>
<img src="https://raw.githubusercontent.com/xiaobinwu/electron-vue-project/master/git_img/4.gif"><br>
<img src="https://raw.githubusercontent.com/xiaobinwu/electron-vue-project/master/git_img/5.gif"></p>
<h4 id="electron自动更新">electron自动更新</h4>
<p>前面我们也有提到过自动更新,这里使用的官方提供的<code>electron.autoUpdater</code>模块去更新,坑爹的是官方对这一功能的描述真是少之又少,autoUpdater的一些方法和事件这里可以去了解清楚,<code>autoUpdater.setFeedURL(url)</code>这一方法是重中之重,<code>url</code>放着高版本的文件(.exe,.nupkg,RELEASES),这里我是存储在阿里oss,然后<code>autoUpdater.checkForUpdates()</code>会去检查是否需要更新,它会触发<code>error、checking-for-update、update-available、update-downloaded</code>中的一些事件,而我们需要利用主进程跟渲染进程之间的通讯(ipc/remote/webContent),来触发更新,具体代码如下:</p>
<pre><code>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()
    })
}
</code></pre>
<p>如果内容对你有帮助的话,可以去github给个star!!!!</p>
<p>参考资料:<br>
https://segmentfault.com/a/1190000008287730<br>
https://segmentfault.com/a/1190000007616641<br>
https://juejin.im/entry/5805e39ad20309006854e58f<br>
https://github.com/hua1995116/webchat</p>
<hr>
<p>Generated by VuePack.<br>
vuePack Issue</p><br><br>
来源:https://www.cnblogs.com/wuxiaobin/p/7410114.html
頁: [1]
查看完整版本: electron + vue 实践项目