electron打包vue-cli4项目的解决方案1(项目实测)

背景:

项目已通过vue-cli4框架开发并运行在nginx服务器上(使用了nginx的反向代理),现需要将该项目转成桌面端应用程序,选择electron来实现。

设想2种解决方案:

1、使用electron-quick-start的loadURL方法读取服务的线上url,需要做一个用户URL输入界面便于部署。vue服务的版本迭代部署都和该electron无关;

2、vue-cli项目引入electron并取代nginx服务器的功用

 

electron简介:

Electron 使用 web 页面作为它的 GUI,所以你能把它看作成一个被 JavaScript 控制的,精简版的 Chromium 浏览器。

Electron大家应该不陌生了,它提供了一种解决方案,让我们能够利用Node.js 和 前端三宝 HTML + JS + CSS 来实现客户端软件。咋一听感觉像NW.js。其实NW.js(node+websocket)可以算是Electron的前身了,都是出自同个作者之手。关于Electron和NW.js的区别官网上是这么说的。简单讲就是Electron优化了NW.js中的一些不足。 秉着与时俱进的态度,我们当然要使用Electron。有了Electron作为容器,我们小前端就可以用HTML+JS+CSS来开发客户端了。就像开发前端页面一样柔顺。Electron的使用比较简单,提供的API也比较清晰。核心概念就是Main Process 和 Render Process顾名思义Main Process是主进程,用于运行Electron的基本操作,如创建窗口,创建菜单等。Render Process是渲染进程,我们需要在渲染进程中创建软件界面,每个渲染进程对应的是一个窗口,主进程开启了多个窗口就会有多个渲染进程。

通俗解释:electron使用nodejs将web应用套了一层壳使之变成了桌面应用electron官网

 

electron-quick-start快速启动项目

下载 electron-quick-start demo 或使用git clone后启动

git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
cnpm install //这里我用的是cnpm,npm太慢了 
npm start

启动成功效果

  

 

启动流程:关注main.jspackage.jsonindex.html这几个文件。从 package.json 文件看起,我们运行 npm start 命令 其实是 运行了 electron . 命令,该命令会从当前目录文件中寻找 package.json 文件,找到 package.json 文件 然后读取 package.json 文件 中的 main 值main值 指向 main.js文件,然后运行 man.js 文件找到index.html文件在主进程创建应用窗口,创建桌面应用实例。

注意:

1、npm start命令中的 “chcp 65001”表示使用utf-8的编码格式,解决console打印乱码的问题

2、main进程中“nodeIntegration”配置表示是否集成nodejs模块

 

 

如何打包成exe桌面应用程序

需求分析:loadURL方法读取服务的线上url,但需要做一个URL输入界面便于用户输入vue服务的地址,因为loadURL方法不管vue服务是否成功都会跳转,url无法访问会导致electron打包后的桌面一片空白,所以尽量在loadURL跳转页面前加以判定

 

解决方案一

流程:

1、打包前需要确认已安装electron和electron-packager、jquery依赖

cnpm install electron --save-dev 
cnpm install electron-packager --save-dev //这个是打成exe文件的插件,之后要用,提前下载好
cnpm install jquery  --save-dev 

2、在package.json配置文件中修改启动和打包命令

{"name": "electron-quick-start","version": "1.0.0","description": "A minimal Electron application","main": "main.js","scripts": {"start": "chcp 65001 &&  electron .", //utf8编码格式,启动"electron_exe":"electron-packager . --platform=win32 --arch=x64 --overwrite" , //覆盖打包"electron_all":"electron-packager ./ notes --all --overwrite"   //全平台打包},"repository": {"type": "git","url": "git+https://github.com/electron/electron-quick-start.git"},"keywords": ["Electron","quick","start","tutorial","demo"],"author": "GitHub","license": "CC0-1.0","devDependencies": {"electron": "^11.2.0","electron-packager": "^15.2.0","jquery": "^3.5.1"},"bugs": {"url": "https://github.com/electron/electron-quick-start/issues"},"homepage": "https://github.com/electron/electron-quick-start#readme","dependencies": {"jquery": "^3.5.1" }
}

 

3、在mian.js主进程中创建窗口配置nodeIntegration允许使用nodejs功能。这里使用了ipcMain和ipcRender(主进程和渲染进程)通信,见后文或官网

// Modules to control application life and create native browser window
var electron = require('electron');
var { app, BrowserWindow, Menu, ipcMain, globalShortcut } = require('electron')
var path = require('path')
var { dialog } = require('electron')var electronScreen = electron.screen; //window.screen 是一个预设值的 DOM 属性, 所以这样写 var screen = require('electron').screen 将不会工作function createWindow() {var mainWindow = new BrowserWindow({ //创建窗口// frame:false, //无边框width: 1400,height: 800,// fullscreen: true, //默认全屏展示webPreferences: {nodeIntegration: true, //false则禁用Node.js的require模块化引入preload: path.join(__dirname, 'preload.js'),enableRemoteModule: true, //远程模块}})mainWindow.loadFile('index.html') //窗口读取本地文件// 在开发环境和生产环境均可通过快捷键打开devToolsglobalShortcut.register('ctrl+F12', function () {if(mainWindow.webContents.isDevToolsOpened()){mainWindow.webContents.closeDevTools()}else {mainWindow.webContents.openDevTools() // 打开F12调试页面}})//主进程监听渲染进程发过来的数据ipcMain.on('asynchronous-message', (event, arg) => {try {// console.log("主进程收到有效数据-----", arg) // prints "ping"mainWindow.loadURL(arg)} catch (err) {console.error(err)mainWindow.loadFile('index.html')}})Menu.setApplicationMenu(null)  // 关闭菜单栏.//快捷键全屏globalShortcut.register('ctrl+f11', () => {if(mainWindow.isFullScreen()){mainWindow.setFullScreen(false);}else {mainWindow.setFullScreen(true);}})}// 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.whenReady().then(() => {createWindow()app.on('activate', function () {// 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 (BrowserWindow.getAllWindows().length === 0) {mouseTimer = null;createWindow()}})})// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {if (process.platform !== 'darwin') app.quit()mouseTimer = null;
})

 

4、index.html中可能出现CSP的安全策略,Content-Security-Policy这里可以注释掉了。

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><!-- 关闭内容安全策略 --><!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --><!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'"> --><title>Hello Boy!</title><style>body {text-align: center;}.url-setting {height: 20%;min-height: 150px;font-size: 30px;}</style></head><body><h1>Hello World!</h1><hr><div class="url-setting"><input type="url" id="vueUrl" placeholder="格式如http://127.0.0.1:8080"><button id="linkBtn">进入系统</button></div><script>//解决在electron-packager打包为exe时nodejs无法require加载jquery的问题window.$ = window.jQuery = require("./node_modules/jquery/dist/jquery.min.js");</script><script src="./renderer.js"></script>
</body></html>

 

5、在renderer.js渲染进程中使用nodejs的require引入jquery会在exe包运行时报错“$ not defined ”,所以在index.html中重新定义$,要注意jquery依赖的文件路径是否能在打包好的electron项目下找到

// This file is required by the index.html file and will be executed in the renderer process for that window.
// No Node.js APIs are available in this process because `nodeIntegration` is turned off. 
// Use `preload.js` to selectively enable features needed in the rendering  process.// ipcRenderer 用于和主进程通信
const ipcRenderer = require('electron').ipcRenderer;
//const $ = require('jquery'); //尽管nodeIntegration设置允许继承nodejs后可以正常启动electron,但打包成exe时会报错//使用 remote 模块,可以调用主进程对象的方法
const remote = require('electron').remote;
const dialog = remote.dialog;
const app = remote.app;//使用nodejs读取本地文件数据,安装electron-store也可以存储数据,但响应性能受较大影响//electron-store存储数据
// const Store = require('electron-store');
// const store = new Store();
// const currentUrl = store.get('serveUrl');const fs = require('fs')//jquery检查连接的url服务是否有效,适用所有浏览器
$(document).ready(function () {// 执行代码var filePath = "./serveUrl.txt"if(app.isPackaged){ //app.isPackaged在生产模式则为truefilePath = "./resources/app/serveUrl.txt"}fs.readFile(filePath, function (error, data) { //if (error) {console.log('读取文件失败了',error)} else {$("#vueUrl").val(data.toString());}})function NetPing(pingUrl) {$.ajax({type: "GET",cache: false,url: pingUrl,data: "",success: function () {fs.writeFile(filePath, pingUrl,function (error) { //存储用户输入的路径if (error) {console.log('存储URL失败',error)}}) ipcRenderer.send('asynchronous-message', pingUrl); //异步将渲染进程的数据传给主进程},error: function () {dialog.showErrorBox("错误提示", "无效网址,请重新输入!")$("#vueUrl").val("");}});}//点击连接vue前端服务$("#linkBtn").click(function () {let urlVal = $("#vueUrl").val();if(urlVal){NetPing(urlVal);}else {dialog.showErrorBox("错误提示", "网址不能为空,请重新输入!")}})
});//接收主进程的信息
ipcRenderer.on('asynchronous-reply', function (event, arg) {// console.log(arg); // prints "pong"
});

注意:没有使用electron-store存储持久化数据,而是使用nodejs读存到本地文件serveUrl.txt上。引用本地文件时可以用app.isPackaged判断是否是生产环境

 

6、启动.\electron-quick-start\electron-quick-start-win32-x64成功

   

 

 

electron方案优缺点:

对比于Cocoa,Qt等传统桌面客户端技术,基于前端技术的实现成本较低(C++牛请忽略)跨平台支持更好(框架都帮你做好了),且天然支持热更新。

由于Electron本身包含了chromium和Node.js的代码, 所以不考虑项目本身体积,打包后的软件最小仍然有100M+, 这也是Electron最为显著的缺点之一。所以基本体积是无法避免的,我们只能尽量减小其他开发文件的大小,避免将一些无关包文件也打包进去。为什么要强调这点呢?因为基于Node.js开发的项目往往会有一个庞大的node_modules文件夹,里面包含了一些开发和生产所用的包,也即对应package.json中的dependencies和devDependencies。而devDependencies中的包是不需要打包到软件的。这里推荐使用 electron-packager, 能自动排除dev依赖包,并支持自定义排除包文件夹。也可以打包出支持不同系统格式的软件。

对于NW.js 有的大多数缺点Electron也有,其中一个通病就是性能问题,主要是渲染性能方面。基于webkit引擎来渲染UI界面,跟原生的系统UI还是有一定的差距。毕竟是基于DOM节点的渲染,每次节点的重排都是一次大的开销。这点只能通过在前端框架中来优化,比如利用Virtual DOM等相关技术。而视觉上的缺点则可以通过CSS做到竟可能接近原生控件。

 

electron主进程和渲染进程间通信:

Electron提供了IPC用于进程间通信。分别是ipcMain和ipcRender。该通信机制允许ipcRender向ipcMain发送信号请求,并通过ipcMain返回数据。反回来ipcMain无法向特定的ipcRender发起请求。而且通信间传递的消息会被格式化为JSON字符串,所以并不支持在两个进程间传递句柄方法等,也就是不支持上下文传递。假如要实现在渲染进程中点击一个按钮,则关闭客户端窗口,可以通过ipcRender发送一个信号给ipcMain, ipcMain接收到该信号后调用Electron的API关闭窗口。对于类似这种比较简单的指令操作,运用IPC实现就可以了,但是如果操作比较复杂,并且需要传递复杂数据类型,则用IPC就行不通了。Electron提供了另一个API remote,用于在Render Process中直接操作主进程的方法。这样就不需要移交Main Process处理,直接在前端页面中调用Electron的API。

// In main process.
const ipcMain = require('electron').ipcMain;
ipcMain.on('asynchronous-message', function(event, arg) {console.log(arg);  // prints "ping"event.sender.send('asynchronous-reply', 'pong');
});ipcMain.on('synchronous-message', function(event, arg) {console.log(arg);  // prints "ping"event.returnValue = 'pong';
});
// In renderer process (web page).
const ipcRenderer = require('electron').ipcRenderer;
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong"ipcRenderer.on('asynchronous-reply', function(event, arg) {console.log(arg); // prints "pong"
});
ipcRenderer.send('asynchronous-message', 'ping');

 

 

解决方案二见下文

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/553886.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IP 基础知识“全家桶”,45 张图一套带走!

转载自&#xff1a; https://mp.weixin.qq.com/s/kPjFeefB1Xsbc2bHz_Or1Q 前言 前段时间&#xff0c;有读者希望我写一篇关于 IP 分类地址、子网划分等的文章&#xff0c;他反馈常常混淆&#xff0c;摸不着头脑。 那么&#xff0c;说来就来&#xff01;而且要盘就盘全一点&am…

浅谈XSS攻击的那些事(附常用绕过姿势)

本文《浅谈XSS攻击的那些事&#xff08;附常用绕过姿势&#xff09;》 由一叶知安团队原创投稿安全脉搏首发&#xff0c;作者geek痕,安全脉搏独家首发表本文&#xff0c;如需要转载&#xff0c;请先联系安全脉搏授权&#xff1b;未经授权请勿转载。随着互联网的不断发展&#x…

了解与防御XSS攻击

一. XSS是什么 XSS攻击全称跨站脚本攻击&#xff08;Cross Site Scripting&#xff09;&#xff0c;是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆&#xff0c;故将跨站脚本攻击缩写为XSS&#xff0c;XSS是一种在web应用中的计算机安全漏洞&#xff0c;它允许恶意…

BS架构和CS架构的优缺点

1、CS、BS架构定义 CS&#xff08;Client/Server&#xff09;&#xff1a;客户端----服务器结构。C/S结构在技术上很成熟&#xff0c;它的主要特点是交互性强、具有安全的存取模式、网络通信量低、响应速度快、利于处理大量数据。因为客户端要负责绝大多数的业务逻辑和UI展示&a…

webService、webSocket、socket、http之间的区别

HTTP HTTP 是基于请求响应式的&#xff0c;即通信只能由客户端发起&#xff0c;服务端做出响应&#xff0c;无状态&#xff0c;无连接。 无状态&#xff1a;每次连接只处理一个请求&#xff0c;请求结束后断开连接。 无连接&#xff1a;对于事务处理没有记忆能力&#xff0c;服…

OSI七层模型传输过程的通俗理解

转自&#xff1a;http://bbs.clnchina.com.cn/thread-1250443-1-1.html 1.OSI七层模型划分。 从上到下依次是&#xff1a;应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。 分层功能应用层网络服务与最终用户的一个接口&#xff08;可理解为人机交互界面&#xf…

软件开发之常见前端安全漏洞

原标题&#xff1a;软件开发之常见前端安全漏洞 软件开发完成后&#xff0c;在Web服务器在投入使用之前&#xff0c;应该确保服务器是相对安全地。保证服务器相对安全地前提是&#xff0c;要充分了解影响Web系统安全。 1、跨站脚本&#xff08;XSS&#xff09;漏洞跨站脚本攻击…

修改el-popover和el-select样式

如图el-popover弹框和el-select下拉项的的容器是div#app之外的&#xff0c;所以在scoped作用域内使用>>>或/deep/修改样式无效。虽然可以使用全局样式修改&#xff0c;但是会造成所有页面组件样式改变。 1、修改el-select选项样式的解决办法&#xff1a; Popper-appen…

vue项目使用electron打包成桌面应用

打包流程详情步骤&#xff1a; 1、准备工作&#xff1a; a、win7系统则确保node版本在v12以上&#xff0c;electron-builder对系统或版本有要求&#xff1b; b、项目路径不使用中文&#xff1b; c、使用淘宝镜像命令代替npm管理工具 npm install -g cnpm --registryhttps://…

Haar特征与积分图—概念解析

1. Adaboost方法的引入 1.1 Boosting方法的提出和发展 在了解Adaboost方法之前&#xff0c;先了解一下Boosting方法。 回答一个是与否的问题&#xff0c;随机猜测可以获得50%的正确率。如果一种方法能获得比随机猜测稍微高一点的正确率&#xff0c;则就可以称该得到这个方法的过…

在jsp中对mysql数据库分页的方法

针对分页&#xff0c;首先开发一个 PageBean 用来控制页面参数&#xff1a; Java代码 package com.longweir; //分页后的javaBean import java.sql.*; import com.longweir.util.*; public class PageBean { private int pageSize5; // 每页显示的记录…

MyEclipse 2015优化技巧

MyEclipse 2015优化速度方案仍然主要有这么几个方面&#xff1a;去除无需加载的模块、取消冗余的配置、去除不必要的检查、关闭更新。第一步: 去除不需要加载的模块 一个系统20%的功能往往能够满足80%的需求&#xff0c;MyEclipse也不例外&#xff0c;我们在大多数时候只需要20…

Highcharts+Spring饼图使用实例

项目上要用到Hightcharts展示平台机器占用情况,使用这类第三方插件很方便就能实现 JSP: <script type"text/javascript" src"<%basePath%>/resources/thirdparty/highcharts/highcharts.js"></script><div id"machineRate"…

Highcharts双饼图使用实例

这次实践了Highcharts的双饼图,确实比普通饼图复杂多了,关键相关数据 多不能继续用简单基本数据类型Map,list了,单独建了个VO存放要用到的数据,不多说,贴代码! JS: /**查看机器占比(按产品线) 2015/8*/ function loadMachineRate(){var chart;$(document).ready(function(){ch…

使用jackson对Java对象与JSON字符串相互转换的一些总结

总结一下自己使用 jackson 处理对象与 JSON 之间相互转换的心得。jackson 是一个用 Java 编写的&#xff0c;用来处理 JSON 格式数据的类库&#xff0c;它速度非常快&#xff0c;目前来看使用很广泛&#xff0c;逐渐替代了 Gson 和 json-lib 。 如果直接引入 jar 包&#xff0…

使用Java的BlockingQueue实现生产者-消费者

BlockingQueue也是java.util.concurrent下的主要用来控制线程同步的工具。 BlockingQueue有四个具体的实现类,根据不同需求,选择不同的实现类 1、ArrayBlockingQueue&#xff1a;一个由数组支持的有界阻塞队列&#xff0c;规定大小的BlockingQueue,其构造函数必须带一个int参数…

循环删除List集合的错误

症状:不是郝柱也能看到灾备分析:调试发现动作中有两个灾备,不过只过滤了其中一个 错误所在:代码如下,这里for循环删除List逻辑出问题了,犯了一个比较基础的错误 : 两个灾备动作索引是相邻的,当我remove掉第一个时紧跟着的动作就会取代它原来的位置,最终导致问题发生 修改方案:解…

ajax中return取不到值的问题

症状:机器迁移时判断JS返回取不到值分析 :调试发现data是有值的&#xff0c;而且下断点调试发现这段ajax还没走完&#xff0c;后面的逻辑已经开始走了错误所在:ajax之所以叫ajax它首先是异步的&#xff0c;顺序执行的程序不需要等待ajax跑完才继续执行 修改方案:将默认为true的…

Websocket判断逻辑Bug

症状:灾备后台失败但前台提示成功分析 :下断点发现此时前端的data.obj为undifined&#xff0c;后台pyhon脚本执行报错了 错误所在:前台判断不应该加上undifined 修改方案:第一次修改如上&#xff0c;判断严谨多了&#xff0c;但是运行是前台报不能对undefined使用length分析 :…

SpringMVC深度探险 —— SpringMVC核心配置文件详解

在上一篇文章中&#xff0c;我们从DispatcherServlet谈起&#xff0c;最终为读者详细分析了SpringMVC的初始化主线的全部过程。整个初始化主线的研究&#xff0c;其实始终围绕着DispatcherServlet、WebApplicationContext和组件这三大元素之间的关系展开。 在文章写完之后&…