Electron+vue-cli3开发跨平台桌面应用

目录

一步一步搭建Electron+vue-cli3开发平台(亲测有效)

Electron是一个基于Chromium和 Node.js,可以使用 HTML、CSS和JavaScript构建跨平台应用的技术框架,兼容 Mac、Windows 和 Linux。虽然B/S是目前开发的主流,但是C/S仍然有很大的市场需求。受限于浏览器的沙盒限制
[^沙盒(英语:sandbox,又译为沙箱),计算机专业术语,在计算机安全领域中是一种安全机制,为运行中的程序提供的隔离环境。通常是作为一些来源不可信、具破坏力或无法判定程序意图的程序提供实验之用。]
网页应用无法满足某些场景下的使用需求,而桌面应用可以读写本地文件、调用更多系统资源,再加上Web开发的低成本、高效率的优势,这种方式越来越受到开发者的喜爱。

这篇博客一步一步教你如何使用Electron和vue-cli3,在完全保留vue开发web应用的习惯下,搭建桌面应用。

这篇博客不涉及Electron和vue的开发教程,仅以实现两者结合为目的,若要深入学习Electron和vue,请访问官方:

ElectronVueVue-cliStylus

学习该框架之前,希望读者需要提前掌握以下技能:

HTML、CSS、JavaScriptVue2.xStylus

1.创建项目

1.1 安装Nodejs

Node.js 中文网下载安装

1.2 使用cnpm加速下载

npm有时***很慢,可以安装cnpm,从国内淘宝镜像下载,执行以下命令:

1

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

之后所有的npm命令都可以直接替换成cnpm使用了。

1.3 为什么不使用electron-vue搭建呢

Electron-vue官方中文文档

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

1.4 安装/升级vue-cli3

  • 先执行以下命令,确认下本地安装的vue-cli版本(如果自己的电脑没有安装过vue,跳过前两步到第三步吧!):

$ vue -V$ vue --version

在写本篇博客时,我的vue是2.9.6版本。

  • 如果本地使用的是vue-cli2.x或者更早版本,可先执行下面命令全局卸载:

$ cnpm uninstall vue-cli -g

(1)vue-cli3使用了新的npm包名,与旧版本不一样。

(2)在vue2.9.6下执行上面命令,控制台输入vue -V仍然有输出,解决方法:

​ a. 当然, 卸载命令还是要执行的: 全局卸载:npm uninstall vue-cli -g;

​ b. npmrc文件删除掉

​ c. 检索删除vue-cli文件夹

​ 再试试: vue -V,就不显示版本号了。

(3)可以忽略上述问题,直接安装最新版本的vue-cli3即可(亲测有效)。

  • 执行以下命令全局安装vue-cli3:

$ cnpm install @vue/cli -g

  • 执行以下命令升级vue-cli3:

$ cnpm update @vue/cli -g

1.5 创建vue项目

  • 在指定目录下,打开终端,执行以下命令,创建vue项目:

$ vue create electron-vue-demo

这里的项目名称为electron-vue-demo(不能出现大写字母),可根据自己的具体项目改变。

  • 创建命令执行后,在完成创建之前,会出现以下选项(如果熟悉此步骤可跳过本节内容):

1

2

3

4

Vue CLI v4.4.6

? Please pick a preset: (Use arrow keys)

  default (babel, eslint)

> Manually select features

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


1

2

3

4

5

6

7

8

9

10

11

? Check the features needed for your project: (Press <space> to select, <a> to toggle all,

<i> to invert selection)

>(*) Babel

 ( ) TypeScript

 ( ) Progressive Web App (PWA) Support

 (*) Router

 (*) Vuex

 (*) CSS Pre-processors

 (*) Linter / Formatter

 ( ) Unit Testing

 ( ) E2E Testing

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


1

2

? 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/page,比较好看。但是还需要后台配置支持。

这里我们选择n


1

2

3

4

5

6

? 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


1

2

3

4

5

? 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,标准配置。


1

2

3

? 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


1

2

3

? 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


1

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

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

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

1.6 自动安装Electron

  • 执行以下命令,进入项目目录:

$ cd electron-vue-demo

  • 然后执行以下命令:

$ vue add electron-builder

electron-builder是一个简单又强大的库。解决了打包这个棘手的问题,而且可以应对大部分的打包需求。

  • 接下来出现配置选项:

1

2

3

4

? Choose Electron Version (Use arrow keys)

  ^7.0.0

  ^8.0.0

> ^9.0.0

选择Electron版本,我写这篇博客的时候,选项是上面3个版本,选择最新的即可。

然后耐心等待安装完成。

1.7 手动安装Electron

  • 修改package.json,添加以下7行:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

...

"scripts": {

  "serve""vue-cli-service serve",

  "build""vue-cli-service build",

  "lint""vue-cli-service lint",

  "electron:build""vue-cli-service electron:build"// add

  "electron:serve""vue-cli-service electron:serve"// add

  "postinstall""electron-builder install-app-deps"// add

  "postuninstall""electron-builder install-app-deps"    // add

},

"main""background.js",      // add

"dependencies": {

  "core-js""^3.6.5",

  "vue""^2.6.11",

  "vue-router""^3.2.0",

  "vuex""^3.4.0"

},

"devDependencies": {

  "@vue/cli-plugin-babel""~4.4.0",

  "@vue/cli-plugin-eslint""~4.4.0",

  "@vue/cli-plugin-router""~4.4.0",

  "@vue/cli-plugin-vuex""~4.4.0",

  "@vue/cli-service""~4.4.0",

  "@vue/eslint-config-standard""^5.1.2",

  "babel-eslint""^10.1.0",

  "electron""^9.0.5",       // add

  "eslint""^6.7.2",

  "eslint-plugin-import""^2.20.2",

  "eslint-plugin-node""^11.1.0",

  "eslint-plugin-promise""^4.2.1",

  "eslint-plugin-standard""^4.0.0",

  "eslint-plugin-vue""^6.2.2",

  "stylus""^0.54.7",

  "stylus-loader""^3.0.2",

  "vue-cli-plugin-electron-builder""~2.0.0-rc.3",       // add

  "vue-template-compiler""^2.6.11"

},

...

  • 新建src/background.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

'use strict'

 

import { app, protocol, BrowserWindow } from 'electron'

import {

  createProtocol,

  installVueDevtools

} from 'vue-cli-plugin-electron-builder/lib'

const isDevelopment = process.env.NODE_ENV !== 'production'

 

// Keep a global reference of the window object, if you don't, the window will

// be closed automatically when the JavaScript object is garbage collected.

let win

 

// Scheme must be registered before the app is ready

protocol.registerSchemesAsPrivileged([

  { scheme: 'app', privileges: { secure: true, standard: true } }

])

 

function createWindow() {

  // Create the browser window.

  win = new BrowserWindow({

    width: 1000,

    height: 600,

    webPreferences: {

      // Use pluginOptions.nodeIntegration, leave this alone

      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration

      // for more info

      // nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION

      webSecurity: false,

      nodeIntegration: true

    }

  })

 

  if (process.env.WEBPACK_DEV_SERVER_URL) {

    // Load the url of the dev server if in development mode

    win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)

    if (!process.env.IS_TEST) win.webContents.openDevTools()

  else {

    createProtocol('app')

    // Load the index.html when not in development

    win.loadURL('app://./index.html')

  }

 

  win.on('closed', () => {

    win = null

  })

}

 

// Quit when all windows are closed.

app.on('window-all-closed', () => {

  // On macOS it is common for applications and their menu bar

  // to stay active until the user quits explicitly with Cmd + Q

  if (process.platform !== 'darwin') {

    app.quit()

  }

})

 

app.on('activate', () => {

  // On macOS it's common to re-create a window in the app when the

  // dock icon is clicked and there are no other windows open.

  if (win === null) {

    createWindow()

  }

})

 

// This method will be called when Electron has finished

// initialization and is ready to create browser windows.

// Some APIs can only be used after this event occurs.

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

    }

  }

  createWindow()

})

 

// Exit cleanly on request from parent process in development mode.

if (isDevelopment) {

  if (process.platform === 'win32') {

    process.on('message', (data) => {

      if (data === 'graceful-exit') {

        app.quit()

      }

    })

  else {

    process.on('SIGTERM', () => {

      app.quit()

    })

  }

}

以上代码是1.6小节使用自动化方式安装后生成的。

  • 安装依赖包

在项目目录下执行以下命令,安装全部依赖包:

$ cnpm install

1.8 编译并启动APP

  • 执行以下命令,开始编译APP,并启动开发环境APP:

$ npm run electron:serve$ yarn electron:serve

首次启动可能会等待很久,加载完后会自动打开APP,等待即可。

  • 编译成功后,就会出现开发环境的APP了,如下图(Win10启动界面):

  • 当回到控制台,发现控制台的信息:

1

2

3

4

5

6

7

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

Failed to fetch extension, trying 1 more times

Failed to fetch extension, trying 0 more times

Vue Devtools failed to install: Error: net::ERR_CONNECTION_TIMED_OUT

这是因为在请求安装vuejs devtools插件。需要***才能安装成功。可以忽略上面的问题,耐心等待5次请求失败后会自动跳过,上面的成功界面即证实跳过依然编译成功。

依然有解决方案:

注释掉src/background.js中的以下代码就行了:

1

/* if (isDevelopment && !process.env.IS_TEST) { // Install Vue Devtools try { await installVueDevtools(); } catch (e) { console.error("Vue Devtools failed to install:", e.toString()); } } */

2.配置项目

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

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

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

请粘贴以下代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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

1

2

3

4

5

[*.{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检测

更多配置可参阅 ESLint教程

2.2 配置vue

在项目目录下创建vue.config.js,粘贴以下代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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:

1

2

3

4

5

6

7

8

9

10

win = new BrowserWindow({

    width: 1000,

    height: 600,

    webPreferences: {

      // Use pluginOptions.nodeIntegration, leave this alone

      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration

      // for more info

      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION

    }

 })

3.3 取消跨域限制

修改background.js:

1

2

3

4

5

6

7

8

9

10

11

12

win = new BrowserWindow({

    width: 1000,

    height: 600,

    webPreferences: {

      // Use pluginOptions.nodeIntegration, leave this alone

      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration

      // for more info

      // nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION

      webSecurity: false,

      nodeIntegration: true

    }

 })

3.4 取消菜单栏

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

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

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

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

修改background.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

'use strict'

// 添加Menu组件

import { app, protocol, BrowserWindow, Menu } from 'electron'

...

function createWindow() {

  // Create the browser window.

  ...

 

  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'

        }]

    }]

    const menu = Menu.buildFromTemplate(template)

    Menu.setApplicationMenu(menu)

  else {

    // windows及linux系统

    Menu.setApplicationMenu(null)

  }

}

改变后的APP界面样式:

更多关于菜单栏设置,请参阅:Electron官方API

3.5 设置APP窗口图标

准备windows和macOS两版图标:

PlatformFile TypeSpecification
Windowsapp.ico最小尺寸:256x256
MacOSapp.png或app.icns最小尺寸:512x512

把图标文件放到public/目录下,项目结构如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

|- /dist_electron

   |...

|- /public

   |- app.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窗口应用图标:

1

2

3

4

5

6

7

8

9

10

11

function createWindow() {

  // Create the browser window.

  win = new BrowserWindow({

    ...

     

    // eslint-disable-next-line no-undef

    icon: `${__static}/app.ico`

  })

 

  ...

}

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

现在,Windows系统上可以看到开发环境的APP窗口图标已经生效了。

MacOS图标请参照4.1章节,并且需要在build后才能生效。

3.6 设置APP窗口标题栏名称

修改public/index.html

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<!DOCTYPE html>

<html lang="en">

  <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">

    <!-- 把'<%= htmlWebpackPlugin.options.title %>'改为App Demo -->

    <title>My App</title>

  </head>

  <body>

    ...

  </body>

</html>

4.打包

这里我们已经集成了electron-builder工具,可以参阅官方文档

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值