vue中electron框架自定義外部配置文件的配置與讀取辦法
簡介
在vue2.6版本后,會生成vue.config.js文件,本文章主要講解如何在vue中,如何生成electron的外部配置文件,與如何讀取外部配置文件。
一、配置與生成config.json文件
首先,要在項目下新建一個config.json文件,然后再config文件中,寫入一些信息。
然后在vue.config.js中寫入配置,通知electron在打包時,不要將指定文件打包進app.asar中。
pluginOptions: { electronBuilder: { builderOptions: { // build配置在此處 // options placed here will be merged with default configuration and passed to electron-builder appId: "com.emr.app", extraResources: [ { "from": "./config.json", "to": "../" } ], "mac": { "icon": "./public/favicon.icns" }, "win": { "icon": "./public/favicon.ico" } // 配置打包后,在win下的應用圖標。ico圖片至少要是256*256尺寸的,尺寸太小,會打包失敗。 } }, },
這里附上我的vue.config.js文件的配置,方便大家理解
const webpack = require('webpack') module.exports = { lintOnSave: false, publicPath: "./", // PC端適配代碼 // css: { // loaderOptions: { // css: {}, // postcss: { // plugins: [ // require("postcss-px2rem")({ // remUnit: 192, // 以1920屏幕為標準來縮放網(wǎng)頁 // propList: ['*', '!border', '!font-size'], // border屬性不進行適配 // }) // ] // } // } // }, chainWebpack: config => { config.plugin('provide').use(webpack.ProvidePlugin, [{ $: 'jquery', jquery: 'jquery', jQuery: 'jquery', 'window.jQuery': 'jquery' }]) }, configureWebpack: { resolve: { alias: {} } }, pluginOptions: { electronBuilder: { builderOptions: { // build配置在此處 // options placed here will be merged with default configuration and passed to electron-builder appId: "com.emr.app", extraResources: [ { "from": "./config.json", "to": "../" }, { "from": "./MatchDownloader.exe", "to": "../" }, { "from": "./download.bat", "to": "../" }, ], "mac": { "icon": "./public/favicon.icns" }, "win": { "icon": "./public/favicon.ico" } } }, }, // 代理 /* devServer: { port: 8080, // host: 'localhost', https: false, // https:{type:Boolean} open: true, // 配置自動啟動瀏覽器 disableHostCheck: true, "proxy": { "/*": { "target": "http://xxx", "changeOrigin": true } } }, */ }
然后,在執(zhí)行npm run electron:build命令后,就可以在打包后的文件里看到config.json文件被獨立出來了。
至此,就完成了第一步,配置與生成config.json這個外部配置文件了。
二、讀取外部配置文件 ---- config.json
至此,我們已經(jīng)有了config.json這個外部配置文件,要讀取這個文件的配置信息,就要用到electron的remote模塊,這個模塊不同electron版本的獲取方式不同,這個用了是electron13.0.0的獲取方法。
首先,要在electorn的入口文件(我項目里的是background.js)里,做一些配置,讓html頁面能訪問node里面的fs模塊,方便調(diào)用fs來讀取文件。
// main.js 'use strict' // Modules to control application life and create native browser window // const { app, BrowserWindow } = require('electron') import moment from "moment" import { app, protocol, BrowserWindow, globalShortcut } from 'electron' import { createProtocol, installVueDevtools } from 'vue-cli-plugin-electron-builder/lib' // 設置運行內(nèi)存350MB process.env.NODE_OPTIONS = '--no-warnings --max-old-space-size=350' // app.commandLine.appendSwitch('disable-site-isolation-trials'); // //這行一定是要加的,要不然無法使用iframe.contentDocument方法 const { ipcMain, Menu, MenuItem, shell } = require('electron') const path = require('path') const fs = require('fs') const exePath = path.dirname(app.getPath('exe')) const localFileUrlList = { // 要生成的文件的本地文件路勁 'app.asar': { win: '\\resources\\app.asar', mac: '/resources/app.asar' }, 'update.asar': { win: '\\resources\\update.asar', mac: '/resources/update.asar' }, 'download.bat': { win: '\\download.bat', mac: '/download.bat' } } // console.log("exePath", exePath) const menuContextTemplate = [ { label: '復制', role: 'copy' }, // 使用了role,click事件不起作用 { label: '粘貼', role: 'paste' } ] const menuBuilder = Menu.buildFromTemplate(menuContextTemplate) // Scheme must be registered before the app is ready protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }]) function showGoBackMenu (mainWindow) { const template = [{ label: '返回', submenu: [{ label: '返回上一頁', click: () => { mainWindow.webContents.goBack() } }] }, { label: '刷新', // 重新加載代碼 accelerator: 'CmdOrCtrl+R', click: function (item, focusedWindow) { if (focusedWindow) { focusedWindow.reload() } } } ] // 構(gòu)建菜單模版 const m = Menu.buildFromTemplate(template) // 設置菜單模版 Menu.setApplicationMenu(m) } function deleteOldLogFiles() { let rententionPeriodInMs = 7 * 24 * 60 * 60 * 1000 let now = new Date().getTime() // 時間閾值,創(chuàng)建時間早于此閾值,則刪除對應文件 let thresholdTime = now - rententionPeriodInMs let LogsFolderPath = path.join(exePath, "logs") console.log("LogsFolderPath", LogsFolderPath) let files = fs.readdirSync(LogsFolderPath) files.forEach(file => { let filePath = path.join(LogsFolderPath, file) let fileStat = fs.statSync(filePath) // 返回文件的文件信息 let createTimeOfFile = fileStat.ctimeMs // 獲取文件的創(chuàng)建時間 if (createTimeOfFile < thresholdTime) { fs.unlinkSync(filePath) } }) } const createWindow = () => { // Create the browser window. const mainWindow = new BrowserWindow({ width: 800, height: 600, title: '', webPreferences: { // preload: path.join(__dirname, 'preload.js'), nodeIntegration: true, // 允許html頁面上的javascipt代碼訪問nodejs 環(huán)境api代碼的能力 enableRemoteModule: true, // 是否允許使用remote contextIsolation: false, // 加載本地圖片 webSecurity: false, // 允許跨域 webviewTag: true // 允許webview }, icon: path.join(__static, './favicon.ico'), show: false, autoHideMenuBar: true, // 隱藏頂部工具欄,生產(chǎn)環(huán)境時設置為true frame: false // 無邊框 }) let timeStr = moment(new Date()).format("YYYY-MM-DD HH:mm:ss") let dateStr = moment(new Date()).format("YYYY-MM-DD") let LogsFolderPath = path.join(exePath, "logs") let logFilePath = path.join(LogsFolderPath, `log-${dateStr}.log`) // 如果文件夾不存在,則新建 if (!fs.existsSync(LogsFolderPath)) { fs.mkdirSync(LogsFolderPath) } // 刪除7天前的日志文件,節(jié)約硬盤空間 deleteOldLogFiles() // 監(jiān)聽控制臺錯誤輸出的事件 mainWindow.webContents.on('console-message', (event, level, message, line, sourceId) => { if (level === 3) { // 3 代表錯誤級別 const logMessage = `[${timeStr}] ${message}\n`; fs.appendFileSync(logFilePath, logMessage); console.error(logMessage); } }); // 生產(chǎn)環(huán)境下隱藏此函數(shù) // showGoBackMenu(mainWindow) globalShortcut.register('CommandOrControl+Shift+i', function () { mainWindow.webContents.openDevTools() }) mainWindow.maximize() mainWindow.show() createProtocol('app') mainWindow.loadURL('http://localhost:8080') // 跑本地開啟這行,打包的時候注掉這行 // mainWindow.loadURL(`app://./index.html`); //打包的時候開啟這行,跑本地注掉這行 // 1. 窗口 最小化 ipcMain.on('window-min', function () { // 收到渲染進程的窗口最小化操作的通知,并調(diào)用窗口最小化函數(shù),執(zhí)行該操作 mainWindow.minimize() }) // 2. 窗口 最大化、恢復 ipcMain.on('window-max', function () { if (mainWindow.isMaximized()) { // 為true表示窗口已最大化 mainWindow.restore() // 將窗口恢復為之前的狀態(tài). } else { mainWindow.maximize() } }) // 3. 關閉窗口 ipcMain.on('window-close', function () { mainWindow.close() }) // 刷新窗口 ipcMain.on('window-reload', function () { // 收到渲染進程的窗口最小化操作的通知,并調(diào)用窗口最小化函數(shù),執(zhí)行該操作 mainWindow.reload() }) ipcMain.on('show-context-menu', function () { menuBuilder.popup({ window: BrowserWindow.getFocusedWindow() }) }) ipcMain.on('print-view', function () { const win = new BrowserWindow({ width: 800, height: 600 }) // 打開新窗口 BrosweWindow 初始化 win.loadURL('http://www.baidu.com') win.webContents.printToPDF({ pageSize: 'A4', printBackground: true }, (error, data) => { console.log('---------------------------------:', data) if (error) throw error debugger fs.writeFile('print.pdf', data, (error) => { if (error) throw error console.log('Write PDF successfully.') }) }) }) // json: { downloadUrl: "", targetPath: "C:\\...", fileName: "config.json" } ipcMain.on('system-update', function (event, { json, asar }) { console.log('system-update', asar) const request = require('request') const req = request({ method: 'GET', uri: json.downloadUrl }) const out = fs.createWriteStream(json.targetPath) req.pipe(out) req.on('end', function () { const batPath = getFilePath('download.bat') // console.log("batPath", batPath) const fileData = `MatchDownloader.exe /opt url ${asar.downloadUrl} process Match-EMR.exe src ~/resources/update.asar dest ~/resources/app.asar` fs.writeFileSync(batPath, fileData) shell.openPath(batPath) // 打開bat文件 app.quit() // 關閉應用 }) }) } app.whenReady().then(async () => { createWindow() app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow() }) }) // 除了 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', () => { if (process.platform !== 'darwin') app.quit() }) function getFilePath (localFileName) { console.log('localFileName', localFileName) if (getSystem() === 1) { return exePath + localFileUrlList[localFileName].mac } else { return exePath + localFileUrlList[localFileName].win } } function getSystem () { // 這是mac系統(tǒng) if (process.platform == 'darwin') { return 1 } // 這是windows系統(tǒng) if (process.platform == 'win32') { return 2 } // 這是linux系統(tǒng) if (process.platform == 'linux') { return 3 } }
關鍵配置就在102行附近,createWindow函數(shù)的new BrowserWindow里,nodeIntegration: true和enableRemoteModule: true。這2個配置,一個是允許頁面支持node環(huán)境及其api調(diào)用。一個允許頁面使用remote對象。
其次,新建一個getBaseUrl.js文件
const path = window.require && window.require("path"); const fs = window.require && window.require("fs"); const electron = window.require && window.require('electron') export function getSystem() { //這是mac系統(tǒng) if (process.platform == "darwin") { return 1; } //這是windows系統(tǒng) if (process.platform == "win32") { return 2; } //這是linux系統(tǒng) if (process.platform == "linux") { return 3; } } /** * * @returns 獲取安裝路徑 */ export function getExePath() { // return path.dirname("C:"); return path.dirname(electron.remote.app.getPath("exe")); } /** * * @returns 獲取配置文件路徑 */ export function getConfigPath() { if (getSystem() === 1) { return getExePath() + "/config.json"; } else { return getExePath() + "\\config.json"; } } /** * 讀取配置文件 */ export function readConfig() { return new Promise((res, rej) => { console.log("fs", fs) fs.readFile(getConfigPath(), "utf-8", (err, data) => { let config = "" if (data) { //有值 config = JSON.parse(data) } res(config) }) }) }
這個文件的readConfig函數(shù),就是獲取config文件的函數(shù)。所以外部只要調(diào)用這個readConfig函數(shù),就可以獲取外部配置文件的信息了(你可以在main.js里調(diào)用,就是在項目加載時,就讀取config.json這個配置文件)。
例如:
import { readConfig } from '@/utils/getBaseUrl.js' // let applicationType = 'website' // 如果最后打包的是網(wǎng)站,就打開這個 let applicationType = "exe" // 如果最后打包的是exe應用,就打開這個 if (applicationType === 'exe') { (async function () { const res = await readConfig() axios.defaults.baseURL = res.baseUrl Vue.prototype.$baseURL = res.baseUrl window.$config = res })() } // 因為我原來的項目是可以打包成網(wǎng)站與桌面應用,但是在網(wǎng)頁版中,window.require('electron')返回的是undefined,所以這里才會用applicationType來區(qū)分,如果打包后的是exe應用時,才去讀取安裝目錄下的config.json文件
最后
這篇文章就講這個外部配置文件的生成與獲取,如果大家有興趣的話,會找個時間分享一下,electron的桌面的版本更新下載的功能,就像其他桌面應用一樣,點擊更新按鈕,自動下載與更新應用的功能。
附上我當前項目的vue與electron版本
"vue": "^2.6.11", "electron": "^13.0.0", "electron-packager": "^15.4.0",
附:Electron 實現(xiàn)打包后動態(tài)配置應用參數(shù)
實現(xiàn)一款交互屏桌面應用軟件,類似醫(yī)院那張種給用戶操作辦理業(yè)務的應用程序。應用程序需要多點放置,根據(jù)放置地點的不同給應用做配置
- 開發(fā)框架:electron-vue
- vue版本:v2.6.14
- electron版本:v17.2.0
- node版本:v16.13.0
實現(xiàn)
在架構(gòu)的根目錄下創(chuàng)建一個config.conf文件,作為動態(tài)配置的入口。文件內(nèi)容就是正常的JSON個是就可以。例如:
{ "STADIUM_ID":"112" }
在主進程中,定義讀取配置文件的程序:
import { app } from 'electron' const path = require("path"); const fs = require("fs"); export function getExePath() { return path.dirname(app.getPath("exe")); } export function getConfigPath() { return getExePath() + "\\config.conf"; } export function readConfig(callback) { fs.readFile(getConfigPath(),"utf-8",(err,data) => { if(data) { const config = JSON.parse(data); callback(config) }else { callback({STADIUM_ID:102}) } }) }
在ipc中設置handle事件,作為被調(diào)用的入口:
ipcMain.handle("get-params", (event, args) => { readConfig(res => { BrowserWindow.fromWebContents(event.sender).webContents.send( "get-params-reply", res ); }); });
在渲染進程中,觸發(fā)并使用參數(shù):
ipcRenderer.invoke('get-params') ipcRenderer.once('get-params-reply',(event,args) => { this.getStadiumDetail(args.STADIUM_ID); })
到此這篇關于vue中electron框架自定義外部配置文件的配置與讀取辦法的文章就介紹到這了,更多相關electron自定義外部配置文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Vue+Express實現(xiàn)登錄狀態(tài)權(quán)限驗證的示例代碼
這篇文章主要介紹了Vue+Express實現(xiàn)登錄狀態(tài)權(quán)限驗證的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05vue 地區(qū)選擇器v-distpicker的常用功能
這篇文章主要介紹了vue 地區(qū)選擇器v-distpicker的常用功能,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07vue.js的狀態(tài)管理vuex中store的使用詳解
今天小編就為大家分享一篇vue.js的狀態(tài)管理vuex中store的使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11