Electron+vue-cli4开发跨平台桌面应用详细流程

Electron是一个基于Chromium和 Node.js,可以使用 HTML、CSS和JavaScript构建跨平台应用的技术框架,兼容 Mac、Windows 和 Linux。虽然B/S是目前开发的主流,但是C/S仍然有很大的市场需求。受限于浏览器的沙盒限制,网页应用无法满足某些场景下的使用需求,而桌面应用可以读写本地文件、调用更多系统资源,再加上Web开发的低成本、高效率的优势,这种方式越来越受到开发者的喜爱。

本文一步一步教你如何使用Electron5和vue-cli3,在完全保留vue开发web应用的习惯下,搭建桌面应用。

本文不涉及Electron和vue的开发教程,仅以实现两者结合为目的,如深入学习Electron和vue,请访问官方:

Electron: https://electronjs.org/
vue: https://cn.vuejs.org/
vue-cli: https://cli.vuejs.org/zh/
stylus: http://stylus-lang.com/

※注:本文代码区域每行开头的“+”表示新增,“-”表示删除,“M”表示修改;代码中的“…”表示省略。

目录
1 创建项目

1.1 使用cnpm加速下载

1.2 为什么不使用SimulatedGREG/electron-vue

1.3 安装/升级vue-cli3

1.4 创建vue项目

1.5 自动安装electron

1.6 编译并启动APP

2 配置项目

2.1 配置ESLint代码格式检查工具

2.2 配置vue

3 项目基本设定

3.1 主进程和渲染进程简介

3.2 APP窗口大小

3.3 取消跨域限制

3.4 取消菜单栏

3.5 设置APP窗口图标

3.6 设置APP窗口标题栏名称

4 build最终产品

4.1 设置APP及安装包图标

4.2 设置APP名称

4.3 注册快捷键打开devTools

4.4 打包APP

5 可能出现的错误

1 创建项目

1.1 使用cnpm加速下载
npm有时下载速度很慢,可以安装cnpm,从国内淘宝镜像下载,执行以下命令:

npm install -g cnpm --registry=https://registry.npm.taobao.org

以后npm直接替换成cnpm使用。

1.2 为什么不使用SimulatedGREG/electron-vue

SimulatedGREG/electron-vue已经很久没有更新了,而且其生成的工程结构并不是vue-cli3。所以放弃使用。

1.3 安装/升级vue-cli3
先执行以下命令,确认下本地安装的vue-cli版本:

vue -V

在写本文时,我使用的是4.1.x版本。

如果本地使用的是vue-cli2.x或者更早版本,可先卸载:

cnpm uninstall vue-cli -g

※注:vue-cli3使用了新的npm包名,与旧版本不一样。
如果还没有安装vue-cli3,先执行以下命令安装:

cnpm install @vue/cli -g

如果你已安装vue-cli3,但不是最新版本,可执行以下命令升级:

(我这里使用cnpm并没有完成升级,所以使用了npm)

npm update @vue/cli -g
1.4 创建vue项目
找个喜欢的目录,执行以下命令,创建vue项目:

(这里把项目名称定为electron-vue-demo)

vue create electron-vue-demo

会出现以下选项(如果熟悉此步骤可跳过本节内容):

Vue CLI v4.1.4
? Please pick a preset: (Use arrow keys)
  default (babel, eslint) 
> Manually select features

选择“Manually select features” (自定义安装)。

? Check the features needed for your project: (Press <space> to select, <a> to t
oggle all, <i> to invert selection)
❯◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◉ Router
 ◉ Vuex
 ◉ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

这里选择了常用的模块,请根据实际需求进行选择。

? Use history mode for router? (Requires proper server setup for index fallback 
in production) (Y/n)  n

如果选择了router,这里会询问是否使用history模式。

vue-router 默认使用hash模式(即通过url#hash来跳转页面),使用URL的hash来模拟一个完整的 URL,当URL改变时,页面不会重新加载。 如果使用history,URL就像正常的url,例如 http://yoursite.com/user/id ,比较好看。但是还需要后台配置支持。
这里我们选择“n”。

? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported 
by default): (Use arrow keys)
  Sass/SCSS (with dart-sass) 
  Sass/SCSS (with node-sass) 
  Less 
❯ Stylus

选择CSS预处理模块,这里我们使用“Stylus”。

? Pick a linter / formatter config: (Use arrow keys)
  ESLint with error prevention only 
  ESLint + Airbnb config 
❯ ESLint + Standard config 
  ESLint + Prettier

选择ESLint代码格式检查工具的配置,选择“ESLint + Standard config”,标准配置。

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i
> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit
Line on save表示在保存代码的时候,进行格式检查。

Lint and fix on commit表示在git commit的时候自动纠正格式。

这里只选择“Lint on save”。

? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? 
  In dedicated config files 
❯ In package.json

这里问把 babel, postcss, eslint 这些配置文件放哪?

In dedicated config files 表示独立文件

In package.json 表示放在package.json里

这里选择“In package.json”。

? Save this as a preset for future projects? (y/N) N

是否为以后的项目保留这些设置?选择“N”。

然后耐心等待项目安装完成。

1.5 自动安装electron
※注:此过程可能需要科学上网,由于直接从国外镜像下载较慢,可能需要等待很漫长的时间。如果你对自己的网速没有超强自信,请跳过本节,前往1.6小节手动安装。
进入到项目根目录,执行:

vue add electron-builder

在安装过程中,很可能会卡在这一步不动了:

node ./download-chromedriver.js
没关系,我们先强制结束掉。再执行一次vue add electron-builder,然后就可以顺利通过了。

接下来出现配置选项:

? Choose Electron Version (Use arrow keys)
  ^7.0.0 
  ^8.0.0 
❯ ^9.0.0

选择Electron版本。选择 “^8.0.0”。

然后耐心等待安装完成。如果中间出现错误中断了,请重复此步骤。

安装完成后会自动在src目录下生成background.js并修改了package.json。

※注:由于网络原因,如果中间出现过中断失败,再次重新安装可能会很快完成,但实际上electron可能并未安装完全。建议完成以上步骤后,直接删除项目根目录的node_modules/,并且执行cnpm install,从国内镜像重新安装所有依赖包。
1.6 编译并启动APP
执行以下命令,开始编译APP,并启动开发环境APP:

npm run electron:serve

首次启动可能会等待很久,出现以下信息:

INFO  Launching Electron...
Failed to fetch extension, trying 4 more times
Failed to fetch extension, trying 3 more times
Failed to fetch extension, trying 2 more times
...

这是因为在请求安装vuejs devtools插件。需要科学上网才能安装成功。如果不能科学上网也没关系,耐心等待5次请求失败后会自动跳过。

编译成功后,就会出现开发环境的APP了。

2 配置项目

2.1 配置ESLint代码格式检查工具
ESlint可以高效的检查代码格式,让参与项目的所有工程师都能保持统一的代码风格。其检测精度甚至可以精确到是否多一个空格或者少一个空格。代码格式的统一对提高团队的协同开发效率有很大的帮助,特别是对有代码洁癖的工程师。

在项目根目录下创建.eslintrc.js (注意文件名前面有个“.”)

请粘贴以下代码:

module.exports = {
    
    
  root: true,
  env: {
    
    
    node: true
  },
  'extends': [
    'plugin:vue/essential',
    '@vue/standard'
  ],
  rules: {
    
    
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    // 不检测语句末尾的分号
    'semi': ['off', 'always'],
    // 强制缩进为2个空格
    'indent': ['error', 2],
    // 关闭函数名称跟括号之间的空格检测
    'space-before-function-paren': 0,
    // 忽略大括号内的空格
    'object-curly-spacing': 0
  },
  parserOptions: {
    
    
    parser: 'babel-eslint'
  }
}

这里说明下关于indent缩进的配置,要配合项目根目录下的.editorconfig

[*.{
    
    js,jsx,ts,tsx,vue}]
indent_style = space   <--这里定义缩进类型是空格还是tab
indent_size = 2        <--这里需要与.eslintrc.js的indent对应
trim_trailing_whitespace = true
insert_final_newline = true

.editorconfig 用于IDE自动格式化代码
.eslintrc.js 用于ESlint检测
2.2 配置vue
在项目根目录下创建vue.config.js,粘贴以下代码:

const path = require('path');

function resolve (dir) {
    
    
  return path.join(__dirname, dir);
}

module.exports = {
    
    
  publicPath: './',
  devServer: {
    
    
    // can be overwritten by process.env.HOST
    host: '0.0.0.0',  
    port: 8080
  },
  chainWebpack: config => {
    
    
    config.resolve.alias
      .set('@', resolve('src'))
      .set('src', resolve('src'))
      .set('common', resolve('src/common'))
      .set('components', resolve('src/components'));
  }
};

devServer 用于设置开发环境的服务,这里表示在本地8080端口启动web服务。

chainWebpack 我们给项目目录起了“别名(alias)”,在代码中,我们可以直接用“别名”访问资源,省去了每次输入完整相对路径的麻烦。

※注:
◉ 在js代码中可直接使用别名,例如:

@/common/js/xxx.js 等价于 src/common/js/xxx.js
common/js/xxx.js 等价于 src/common/js/xxx.js

◉ 在css或者html中使用别名,需要在别名前加“~”,例如:

@import "~common/stylus/font.styl";

3 项目基本设定

3.1 主进程和渲染进程简介
在开始下面的步骤之前,很有必要简单了解下Electron的应用架构。

主进程
Electron 运行 package.json 的 main 脚本(background.js)的进程被称为主进程。 在主进程中运行的脚本通过创建web页面来展示用户界面。 一个 Electron 应用总是有且只有一个主进程。

渲染进程
由于 Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。 每个 Electron 中的 web 页面运行在它自己的渲染进程中。

在普通的浏览器中,web页面通常在一个沙盒环境中运行,不被允许去接触原生的资源。 然而 Electron 的用户在 Node.js 的 API 支持下可以在页面中和操作系统进行一些底层交互。

主进程与渲染进程的关系
主进程使用 BrowserWindow 实例创建页面。 每个 BrowserWindow 实例都在自己的渲染进程里运行页面。 当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。

主进程管理所有的web页面和它们对应的渲染进程。 每个渲染进程都是独立的,它只关心它所运行的 web 页面。

3.2 APP窗口大小
修改background.js:

function createWindow () {
    
    
      // Create the browser window.
      win = new BrowserWindow({
    
    
M      width: 1200,
M      height: 620,
        webPreferences: {
    
    
          nodeIntegration: true
        }
      })

3.3 取消跨域限制
修改background.js:

function createWindow () {
    
    
      // Create the browser window.
      win = new BrowserWindow({
    
    
        width: 1200,
        height: 620,
        webPreferences: {
    
    
+         webSecurity: false,
          nodeIntegration: true
        }
      })

3.4 取消菜单栏
在我们生成的桌面APP中,我们可以看到默认的菜单栏。

在windows中,菜单栏在APP窗口内的顶部;在macOS中,菜单栏位于电脑屏幕顶部。

为了方便项目将来也能直接生成纯web应用,尽量把APP的全部功能都做到渲染进程里,这里我们取消菜单栏。

由于macOS的特殊性,顶部菜单栏无法删除,所以我们针对macOS特殊处理,把菜单栏只保留“关于”和“退出”。

修改background.js:

M   import {
    
     app, protocol, BrowserWindow, Menu } from 'electron'
    ...
    function createWindow () {
    
    
        ...
        win.on('closed', () => {
    
    
            win = null
        })

+       createMenu()
    }

+   // 设置菜单栏
+   function createMenu() {
    
    
+       // darwin表示macOS,针对macOS的设置
+       if (process.platform === 'darwin') {
    
    
+           const template = [
+           {
    
    
+               label: 'App Demo',
+               submenu: [
+                   {
    
    
+                       role: 'about'
+                   },
+                   {
    
    
+                       role: 'quit'
+                   }]
+           }]
+           let menu = Menu.buildFromTemplate(template)
+           Menu.setApplicationMenu(menu)
+       } else {
    
    
+           // windows及linux系统
+           Menu.setApplicationMenu(null)
+       }
+   }

3.5 设置APP窗口图标

准备windows和macOS两版图标。

windows: app.ico 最小尺寸:256x256 macOS: app.png或app.icns 最小尺寸:512x512
(后续4.1章节用到)

把图标文件放到public/目录下,项目结构如下:
|- /dist_electron
(略)
|- /public
|- app.icns <-- 本教程暂时未使用icns
|- app.ico
|- app.png
|- favicon.ico
|- index.html
|- /src
(略)
|- .editorconfig
|- .eslintrc.js
|- .gitignore
|- babel.config.js
|- package.json
|- package-lock.json
|- README.md

可以顺便把favicon.ico也修改一下,但是在桌面版APP上是用不到的。如果以后生成纯web项目才会用到。

修改background.js,让APP窗口应用图标:

function createWindow () {
    
    
      // Create the browser window.
      win = new BrowserWindow({
    
    
        width: 1200,
        height: 620,
        webPreferences: {
    
    
          nodeIntegration: true
        },
+       // eslint-disable-next-line no-undef
+       icon: `${
      
      __static}/app.ico`
      })

这里的${__static}对应的是public目录

现在,Windows系统上可以看到开发环境的APP窗口图标已经生效了。
macOS图标请参照4.1章节,并且需要在build后才能生效。
3.6 设置APP窗口标题栏名称
修改public/index.html:

我们把electron-vue-demo改为App Demo。

<head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
M       <title>App Demo</title>
  </head>

4 build最终产品

这里我们已经集成了electron-builder工具,官方文档可以参阅:https://www.electron.build/

4.1 设置APP及安装包图标
在3.5章节,我们的图标生效于运行APP的窗口。本小节将生效于最终生成的可执行文件和安装包图标。需要准备的图标文件请回看3.5章节。

修改vue.config.js

chainWebpack: config => {
    
    ...},
+   pluginOptions: {
    
    
+       electronBuilder: {
    
    
+           builderOptions: {
    
    
+               win: {
    
    
+                   icon: './public/app.ico'
+               },
+               mac: {
    
    
+                   icon: './public/app.png'
+               }
+           }
+       }
+   }
    ...

4.2 设置APP名称
APP名称包括安装包中APP的名称、可执行文件的文件名。

修改vue.config.js:

pluginOptions: {
    
    
        electronBuilder: {
    
    
            builderOptions: {
    
    
                win: {
    
    
                    icon: './public/app.ico'
                },
                mac: {
    
    
                    icon: './public/app.png'
                },
+               productName: 'AppDemo'
            }
        }
    }

4.3 注册快捷键打开devTools
在Electron中打开devTools是通过主线程中调用win.webContents.openDevTools()实现的。以上教程仅在开发环境初始启动的时候打开devTools,但是一旦关闭就不能再打开了。下面讲一下怎么通过快捷键打开devTools。

修改background.js:

...
M   import {
    
     app, protocol, BrowserWindow, Menu, globalShortcut } from 'electron'
    ...
    app.on('ready', async () => {
    
    
        if (isDevelopment && !process.env.IS_TEST) {
    
    
        // Install Vue Devtools
            try {
    
    
                await installVueDevtools()
            } catch (e) {
    
    
                console.error('Vue Devtools failed to install:', e.toString())
            }
        }
        // 在开发环境和生产环境均可通过快捷键打开devTools
+       globalShortcut.register('CommandOrControl+Shift+i', function () {
    
    
+           win.webContents.openDevTools()
+       })
        createWindow()
})

在windows下,按Ctrl+Shift+i即可打开devTools

在macOS下,按Commond+Shift+i即可打开devTools

为什么没用F12?因为windows系统中,F12是系统保留快捷键,无法使用。官方原话是这么解释的:

The F12 key is reserved for use by the debugger at all times, so it
should not be registered as a hot key. Even when you are not debugging
an application, F12 is reserved in case a kernel-mode debugger or a
just-in-time debugger is resident.

但是可以使用Ctrl+F12,只要不单独使用F12就可以。

以上代码在开发环境和生产环境中均有效,为保证生产环境的安全,建议不要在生产环境中使用。放到上面的if语句中即可。

4.4打包APP
执行以下命令,可以build工程:

npm run electron:build

最终在dist_electron目录下生成build后的产品。

windows版本
目录如下:

dist_electron
|- /bundled
  (略)
|- /win-unpacked  <-- 绿色版
  (略)
|- AppDemo Setup 0.1.0.exe  <-- 安装文件
|- AppDemo Setup 0.1.0.exe.blockmap
|- builder-effective-config.yaml
|- index.js

这里其实就win-unpacked和AppDemo Setup 0.1.0.exe有用。

※注:在32位环境下打包生成的是32位APP,在64位环境下打包生成的是64位APP。
mac版本

/dist_electron
|- /bundled
  (略)
|- /mac
   |- AppDemo   <-- 绿色版
|- AppDemo-0.1.0-mac.zip  <-- 绿色版压缩包
|- AppDemo-0.1.0-mac.dmg  <-- 安装包
|- AppDemo-0.1.0.dmg.blockmap
|- builder-effective-config.yaml
|- index.js

5 可能出现的错误

build失败

我曾经在Win10 64bit 1809版本上build失败,保存信息中提示:

Error output: Can’t open output file Error - aborting creation process

与此同时,在win7和win10 1803版本build正常。经研究,无果。后来把windows升级到1903版本,问题解决了。应该是vue-cli-plugin-electron-builder插件与系统之间的问题导致

初次使用Electron下载慢,Electron-builder打包慢
一共分为下面几步:

1、设置 npm 源为 npm config set registry https://registry.npm.taobao.org/
2、用浏览器,前往 https://npm.taobao.org/mirrors/electron/ 下载你所需要的版本(通常需要下载 mac 和 win 两个,看自己项目需求)

我下载的版本和所需的文件如下(我的项目需要在 Windows 和 Mac 上使用)

注意下载的 SHASUMS文件,记得在最后加上你所使用的版本号,否则会去重新下载

在这里插入图片描述
3、将下载的文件拷贝到下列对应的文件夹中:

3.1、 Linux:$XDG_CACHE_HOME 或 ~/.cache/electron/

3.2、 macOS:~/Library/Caches/electron/

3.3、Windows:~/AppData/local/electron/Cache

4、在你的项目中运行 npm install

执行完上述步骤,就能分分钟装好依赖了。

Electron-builder 第一次打包时下载慢的问题
如果你是第一次在你电脑时使用 electron-builder 来打包,你很大可能会卡在下面的几个地方(如有不同,请视情况酌情处理,但是处理的方式都是一样的

如果你的打包卡在了图中这样,一直在 downloading,那么你可以点击图中的链接,去浏览器下载对应的几个包。

包的版本请根据你的项目需要下载,不知道你的项目需要那个版本的时候,可以在执行打包时,卡住了就去下载。下载后进行如下操作:(以 Mac 为例,其他平台类似)

我打包 Windows 和 macOS 两个平台运行包,一共下载了如下几个文件,
在这里插入图片描述
然后,在 ~/Library/Caches/electron-builder 文件夹下面,先新建三个文件夹 nsiswinewinCodeSign

注意文件名大小写。

然后将前面下载的文件分别解压到对应的文件夹中

注意文件夹名称!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这样就能顺利的进行打包了,不会因为网络问题,一直卡在下载那一步。

猜你喜欢

转载自blog.csdn.net/weixin_44714325/article/details/113104748