【原創】從零開始搭建Electron+Vue+Webpack項目框架(四)完善Electron配置

導航:html

(一)Electron跑起來
(二)從零搭建Vue全家桶+webpack項目框架
(三)Electron+Vue+Webpack,聯合調試整個項目
(四)Electron配置潤色
(五)預加載及自動更新
(六)構建、發佈整個項目(包括client和web)(未完待續)vue

摘要:前面幾篇介紹瞭如何啓動electron和vue項目,並進行聯合調試,這篇就來給咱們的Electron配置潤色一下,至少看起來不那麼像一個‘demo’。項目完整代碼:https://github.com/luohao8023/electron-vue-templatenode

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

以前咱們是把建立窗口以及窗口配置都放在了main.js中,這樣會讓咱們的主進程看起來很亂,摻雜了各類配置、各方面的代碼,並且一旦咱們的項目稍微複雜一些,好比同時維護多個窗口,或者有不少針對某個窗口的事件監聽等。這裏所說的一個個窗口其實就是electron的渲染進程,不一樣的渲染進程由主進程來統一維護和調度。把渲染進程提取爲單獨的配置文件,對外只暴露方法,這樣就能簡化主進程代碼,也讓咱們的項目結構更清晰、更合理,總之是好處多多。git

新建文件:main>index.jsgithub

/**
* 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:web

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);
});

2、單實例檢查,只容許啓動一個客戶端。npm

新建文件: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")(); //禁止打開多份

3、註冊快捷鍵打開控制檯:

細心的話能夠發現,咱們已經把控制檯關掉了。以往的作法是在代碼裏打開控制檯,打包發佈時再把代碼註釋掉,某個環境的包出問題了,又要放開限制再打對應環境的包,至關的麻煩。這裏的解決方案是:

經過註冊快捷鍵的方式來操做控制檯,而不是頻繁的註釋、取消註釋代碼。

新建文件: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();
});

4、配置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中使用到端口信息的地方。

以上就是此次的內容,感受囉嗦了一堆沒什麼重點。有什麼想了解可是文中未說起的地方,歡迎留言。

相關文章
相關標籤/搜索