【原创】从零开始搭建Electron+Vue+Webpack项目框架,一套代码,同时构建客户端、web端四

导航:

(一)Electron跑起来
(二)从零搭建Vue全家桶+webpack项目框架
(三)Electron+Vue+Webpack,联合调试整个项目
(四)Electron配置润色
(五)预加载及自动更新(未完待续)
(六)构建、发布整个项目(包括client和web)(未完待续)

摘要:前面几篇介绍了如何启动electron和vue项目,并进行联合调试,这篇就来给我们的Electron配置润色一下,至少看起来不那么像一个‘demo’。项目完整代码:https://github.com/luohao8023/electron-vue-template

一、’清理‘主进程文件main.js,提取窗口配置文件。

之前我们是把创建窗口以及窗口配置都放在了main.js中,这样会让我们的主进程看起来很乱,掺杂了各种配置、各方面的代码,而且一旦我们的项目稍微复杂一些,比如同时维护多个窗口,或者有很多针对某个窗口的事件监听等。这里所说的一个个窗口其实就是electron的渲染进程,不同的渲染进程由主进程来统一维护和调度。把渲染进程提取为单独的配置文件,对外只暴露方法,这样就能简化主进程代码,也让我们的项目结构更清晰、更合理,总之是好处多多。

新建文件:main>index.js

/**
* Tip:    主进程
* Author: haoluo
* Data:   2020-02-25
**/
const {
    BrowserWindow,
    dialog
} = require("electron");
const electron = require("electron");
const process = require("process");
const url = require("url");
const path = require("path");
const cookie = require('cookie');

const devMode = process.env.NODE_ENV === "development";
let mainWindow = null;

const filter = {
    urls: ['http://*.kakayang.cn/*']
};
//创建窗口
function createWindow() {
    // 首页路径,file协议,pathToFileURL得到编码过的URL
    let filePath = url.pathToFileURL(path.join(__dirname, 'index.html')).href;
    let indexUrl = 'http://localhost:8099/';
    let winW = electron.screen.getPrimaryDisplay().workAreaSize.width,
        winH = electron.screen.getPrimaryDisplay().workAreaSize.height;
    let config = {
        title: "electron-vue-template",
        width: winW <= 1240 ? winW : 1240,
        height: winH <= 730 ? winH : 730,
        minWidth: winW <= 1240 ? winW : 1240,
        minHeight: winH <= 730 ? winH : 730,
        offscreen: true,
        show: true,
        center: true,
        frame: false,  //去掉窗口边框
        autoHideMenuBar: true, //隐藏菜单栏
        titleBarStyle: 'customButtonsOnHover',
        simpleFullscreen: true,
        resizable: process.platform === 'darwin', //可否调整大小
        movable: true, //可否移动
        minimizable: true, //可否最小化
        maximizable: true, //可否最大化
        fullscreen: false, //MAC下是否可以全屏
        skipTaskbar: false, //在任务栏中显示窗口
        acceptFirstMouse: true, //是否允许单击页面来激活窗口
        transparent: process.platform === 'darwin', //允许透明
        opacity: 1,//设置窗口初始的不透明度
        closable: true,
        backgroundColor: '#fff',
        allowRunningInsecureContent: true,//允许一个 https 页面运行 http url 里的资源
        webPreferences: {
            devTools: true, //是否打开调试模式
            webSecurity: false,//禁用安全策略
            allowDisplayingInsecureContent: true,//允许一个使用 https的界面来展示由 http URLs 传过来的资源
            allowRunningInsecureContent: true, //允许一个 https 页面运行 http url 里的资源
            nodeIntegration: true//5.x以上版本,默认无法在渲染进程引入node模块,需要这里设置为true
        }
    };
    // 增加session隔离配置
    config.webPreferences.partition = `persist:${Date.now()}${Math.random()}`;
    mainWindow = new BrowserWindow(config);
    global.windowIds.main = mainWindow.webContents.id;
    // 开发环境使用http协议,生产环境使用file协议
    mainWindow.loadURL(devMode ? encodeURI(indexUrl) : filePath);

    //监听关闭
    mainWindow.on('closed', function () {
        mainWindow = null;
    }).on('close', function (event) {
        mainWindow.send("close-window-render");
        event.preventDefault();
    }).on('ready-to-show', function () {
        mainWindow.show();
    });

    try {
        if (mainWindow.webContents.debugger.isAttached()) mainWindow.webContents.debugger.detach("1.1");
        mainWindow.webContents.debugger.attach("1.1");
        mainWindow.webContents.debugger.sendCommand("Network.enable");
    } catch (err) {
        console.log("无法启动调试", err);
        dialog.showErrorBox("get", "无法启动调试");
    }
    // 拦截请求并处理cookie
    mainWindow.webContents.session.webRequest.onBeforeSendHeaders(filter, onBeforeSendHeaders);
    mainWindow.webContents.session.webRequest.onHeadersReceived(filter, onHeadersReceived);
    return mainWindow;
}
function onBeforeSendHeaders(details, callback) {
    if (details.requestHeaders) {
        details.requestHeaders['Cookie'] = global.cookie;
        details.requestHeaders['Origin'] = details.url;
        details.requestHeaders['Referer'] = details.url;
    }
    callback({ requestHeaders: details.requestHeaders });
}
function onHeadersReceived(details, callback) {
    let cookieArr = [];
    for (let name in details.responseHeaders) {
        if (name.toLocaleLowerCase() === 'Set-Cookie'.toLocaleLowerCase()) {
            cookieArr = details.responseHeaders[name];
        }
    }
    let webCookie = "";
    cookieArr instanceof Array && cookieArr.forEach(cookieItem => {
        webCookie += cookieItem;
    });
    let webCookieObj = cookie.parse(webCookie);
    let localCookieObj = cookie.parse(global.cookie || '');
    let newCookie = Object.assign({}, localCookieObj, webCookieObj);
    let cookieStr = "";
    for (let name in newCookie) {
        cookieStr += cookie.serialize(name, newCookie[name]) + ";";
    }
    global.cookie = cookieStr;
    callback({ response: details.responseHeaders, statusLine: details.statusLine });
}
module.exports = {
    create(_callback) {
        if (mainWindow && !mainWindow.isDestroyed()) {
            mainWindow.destroy();
        }
        mainWindow = createWindow();
        if (_callback instanceof Function) _callback(mainWindow);
        return mainWindow;
    }
}

修改main.js:

const { app, BrowserWindow } = require("electron");
let mainWindow = require("./index.js");

//注册全局变量
// 页面跟路径配置,优先使用此配置,考虑到小版本更新时,版本之间的切换
global.wwwroot = {
    path: __dirname
};
global.cookie = "";
//主窗口id,在创建主窗口的js中获取并修改此处
global.windowIds = {
    main: 0
};

app.on('ready', () => {
    mainWindow.create();
});
app.on('window-all-closed', function() {
    setTimeout(() => {
        let allwindow = BrowserWindow.getAllWindows();
        if (allwindow.length === 0 ) app.exit(1);
    }, 500);
});

二、单实例检查,只允许启动一个客户端。

新建文件:main->libs->runCheck.js:

const {
    app,
    BrowserWindow
} = require("electron");
module.exports=()=>{
    // 单实例检查
    const gotTheLock = app.requestSingleInstanceLock();
    if (!gotTheLock) return app.quit();
    app.on('second-instance', () => {
        let myWindows = BrowserWindow.getAllWindows();
        myWindows.forEach(win => {
            if (win && !win.isDestroyed()) {
                if (win.isMinimized()) win.restore();
                win.focus();
            }
        });
    });
}

在main.js中引入并执行check函数:

require("./libs/runCheck.js")(); //禁止打开多份

三、注册快捷键打开控制台:

细心的话可以发现,我们已经把控制台关掉了。以往的做法是在代码里打开控制台,打包发布时再把代码注释掉,某个环境的包出问题了,又要放开限制再打对应环境的包,相当的麻烦。这里的解决方案是:

通过注册快捷键的方式来操作控制台,而不是频繁的注释、取消注释代码。

新建文件:main->libs->shortcut.js:

const {
    app,
    BrowserWindow
} = require("electron");
const globalShortcut = require("electron").globalShortcut;
class Shortcut{
    register(keys='Command+Control+Alt+F4'){
        globalShortcut.register(keys, function () {
            let allWindow = BrowserWindow.getAllWindows();
            for(let index =0;index < allWindow.length ;index++){
                let win=allWindow[index]
                if(win.webContents && !win.webContents.isDevToolsOpened()){
                    win.webContents.openDevTools({mode: 'detach'});
                }
            }
        })
    }
    
}
app.on('will-quit', function () {
    globalShortcut.unregisterAll()
});
module.exports=new Shortcut();

然后在主进程中引用并执行:

const shortcut = require("./libs/shortcut.js"); //注册快捷键

app.on('ready', () => {
    //注册快捷键打开控制台事件
    shortcut.register('Command+Control+Alt+F5');
    mainWindow.create();
});

四、配置devServer:

写死端口可不是个好主意,得能配置才行,不然万一哪个端口被占用,要修改所有引用的地方,很是麻烦。

新建文件:config->devServerConfig.js:

/**
* Tip:    devServer的配置
* Author: haoluo
* Data:   2020-02-25
* Tips:   使用以下命令启动各环境配置,npm run dev [dev|test|release]
**/

let envList = ['dev', 'test', 'release'];
let currentEnv = 'release';
let envArg = process.argv[2];

if (envArg && envList.includes(envArg)) {
    currentEnv = envArg;
}
//导出服务配置
module.exports = {
    url: '127.0.0.1',
    port: 8098,
    // 运行环境
    currentEnv: currentEnv,
    // 调试完打开浏览器
    devComplateOpened: true
};

可以看到我们增加了启动参数,用来调试不同环境,这个参数可以用来标记不同环境的后端服务,对于后端接口地址我们也可以提取配置文件,跟这个环境参数相对应,这里就不多说了。

修改index.js:

const devServerConfig = require('@config/devServerConfig.js');

let indexUrl = `http://${devServerConfig.url}:${devServerConfig.port}/`;

修改dev.js中使用到端口信息的地方。

以上就是这次的内容,感觉啰嗦了一堆没什么重点。有什么想了解但是文中未提及的地方,欢迎留言。

 

原文地址:https://www.cnblogs.com/kakayang/p/12165742.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要讲解了“electron打包中的坑如何解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“electron...
这篇文章主要介绍“electron打包的坑如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“electron打包的坑如何...
这篇文章主要为大家分析了VSCode中如何调试Electron应用的主进程代码的相关知识点,内容详细易懂,操作细节合理,具有一定参考价值。如果感兴趣的话,不妨跟着跟...
这篇“如何在VSCode上调试Electron应用的主进程代码”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价
vue-cli+electron一种新的脚手架(vue-electron)vue-electron主要业务逻辑都放在src下的renderer文件夹内,和之前的vue-cli搭建项目流程没有任何区别 GIT地址:https://github.com/SimulatedGREG/electron-vue 搭建项目:1.全局安装脚手架:npminstall--globalvue-cli
1、首先成功安装Node.js。2、配置好环境变量path,参加上一篇博客《NodeJs安装》3、全局安装electron,并测试。如下图
相关代码:https://github.com/WozHuang/Barrage-helper/blob/master/src/main/index.dev.js在SPA逐渐成为构建优秀交互体验应用的主流方式后,使用Electron开发跨平台的软件是一个优秀的解决方案。下面简单介绍一下Electron-vue安装vue-devtool的方式。安装步骤下载vue-de
前言本人是做java开发的(菜鸟),做web项目的朋友们基本上都会遇到同样一个,永远不知道客户会怎么样使用,或者说永远不知道客户会用什么浏览器打开我们做出来的应用,就算你跟他说明了一定得用某某某浏览器打开,还是有人会用别的浏览器打开,这种情况通常我们会去做适配(前端),最近公司有需求
electron-builder是将electron做的桌面应用打包成安装包的插件。一、安装使用yarn安装,使用npm安装的有问题(没有尝试),先安装yarn工具。npminstall-gyarn安装electron-builderyarnaddelectron-builder--save-dev二、配置在package.json 中配置"build":{
来源:https:/ewsn.net/say/electron-asar.html 在electron中,asar是个特殊的代码格式。asar包里面包含了程序猿编写的代码逻辑。默认情况下,这些代码逻辑,是放置在resource/app目录下面的,明文可见,这样的话,也就有了代码加密(asar打包)的需求 asar如何解密加密?electron的asar的
 字体图标丢失问题解决方案 重新打包文件npmrunbuild再次运行electron 
<img:src="item.headUrl"alt=""class="contact-head":onerror="morenImage">data(){return{morenImage:'this.src="static/image/head.png"',//默认头像}}
在electron-vue中使用了字体图标,但是打包成.exe文件后图标不显示,路劲问题把字体图标放到static目录下就可以了,静态图片也一样我原来放在其它地方不行改到static目录就可以了
//设置登录cookiesetCookie(name,value){varDays=30;varexp=newDate();vardate=Math.round(exp.getTime()/1000)+Days*24*60*60;constcookie={url:this.webApi,name:name,value:value,e
vue部分cnpminstall-gvue-clivueinitsimulatedgreg/electron-vuemy-projectelectron下载失败解决办法:单独设置electron为淘宝镜像,npmconfigsetelectron_mirrorhttps:/pm.taobao.org/mirrors/electron/yarnconfigsetelectron_mirrorhttps:/pm.taobao.org
原始的方式打包下载对应的版本号的ReleaseElectron然后把对应的项目方便整理成这样的目录结构(Windows下)node_modules重新安装,不然可能启动失败把整文件夹给别人就可以了如果想改名子可以用改名工具rcedit应用程序打包成一个文件为了缓解windows路径名过长的问题(就
窗口间通信的问题electron窗口通信比nwjs要麻烦的多electron分主进程和渲染进程,渲染进程又分主窗口的渲染进程和子窗口的渲染进程主窗口的渲染进程给子窗口的渲染进程发消息1234567891011subWin.webContents.on('dom-ready', () => {    subWin.webCo
按照上一个问题here,我有一个使用Electron平台和Javascript的桌面应用程序,我使用以下方法将HTML5画布转换为JPEG:<aid="download"download="Path.jpg">DownloadJPG</a>然后,functiondownload(){vardt=canvas.toDataURL('image/jpeg');this.href
一.什么是Electron?它和NW.js的区别是什么?Electron是GitHub开发的桌面应用开发框架,它支持使用HTML、CSS、JavaScript来构建跨平台的桌面应用。Electron和NW.js(NW.js是什么可以百度下)的区别是:1.整合Chromium和Node.js的方式不同。在NW.js中,Chromium是直接被打补丁打进去
1.打开父子模态创建,<button@click="showModalHandler">父子模态窗口</button>/enderer渲染器中主注册事件showModalHandler(){ipcRenderer.send("child-down-modal");}//主进程中触发事件/***父子模态窗口*/letchildDownModal;ipcMain.on(&#