教你如何開發(fā)Vite3插件構建Electron開發(fā)環(huán)境
開發(fā)新版本 Vue 項目推薦你使用 Vite 腳手架構建開發(fā)環(huán)境,然而 Vite 腳手架更傾向于構建純 Web 頁面,而不是桌面應用,因此開發(fā)者要做很多額外的配置和開發(fā)工作才能把 Electron 引入到 Vue 項目中,這也是很多開發(fā)者都基于開源工具來構建 Electron+Vue 的開發(fā)環(huán)境的原因。
但這樣做有兩個問題:第一個是這些開源工具封裝了很多技術細節(jié),導致開發(fā)者想要修改某項配置非常不方便;另一個是這些開源工具的實現(xiàn)方式我認為也并不是很好。
所以,我還是建議你盡量 自己寫代碼構建 Electron+Vue 的開發(fā)環(huán)境 ,這樣可以讓自己更從容地控制整個項目。
具體應該怎么做呢?接下來我將帶你按如下幾個步驟構建一個 Vite+Electron 的開發(fā)環(huán)境:
創(chuàng)建項目
首先通過命令行創(chuàng)建一個 Vue 項目:
npm create vite@latest electron-jue-jin -- --template vue-ts
接著安裝 Electron 開發(fā)依賴:
npm install electron -D
安裝完成后,你的項目根目錄下的 package.json 文件應該與下面大體類似:
{ "name": "electron-jue-jin", "private": true, "version": "0.0.1", "scripts": { "dev": "vite", "build": "vue-tsc --noEmit && vite build", "preview": "vite preview" }, "dependencies": {}, "devDependencies": { "vue": "^3.2.37", "@vitejs/plugin-vue": "^3.0.0", "electron": "^19.0.8", "typescript": "^4.6.4", "vite": "^3.0.0", "vue-tsc": "^0.38.4" } }
注意:這里我們 把 vue 從 dependencies 配置節(jié)移至了 devDependencies 配置節(jié)。這是因為在 Vite 編譯項目的時候,Vue 庫會被編譯到輸出目錄下,輸出目錄下的內容是完整的,沒必要把 Vue 標記為生產依賴;而且在我們將來制作安裝包的時候,還要用到這個 package.json 文件,它的生產依賴里不應該有沒用的東西,所以我們在這里做了一些調整。
到這里,我們就創(chuàng)建了一個基本的 Vue+TypeScript 的項目,接下來我們就為這個項目引入 Electron 模塊。
創(chuàng)建主進程代碼
創(chuàng)建好項目之后,我們創(chuàng)建主進程的入口程序:src\main\mainEntry.ts。
這個入口程序的代碼很簡單,如下所示:
//src\main\mainEntry.ts import { app, BrowserWindow } from "electron"; let mainWindow: BrowserWindow; app.whenReady().then(() => { mainWindow = new BrowserWindow({}); mainWindow.loadURL(process.argv[2]); });
在這段代碼里,我們在 app ready 之后創(chuàng)建了一個簡單的 BrowserWindow 對象。app 是 Electron 的全局對象,用于控制整個應用程序的生命周期。在 Electron 初始化完成后,app 對象的 ready 事件被觸發(fā),這里我們使用 app.whenReady() 這個 Promise 方法來等待 ready 事件的發(fā)生。
mainWindow 被設置成一個全局變量,這樣可以避免主窗口被 JavaScript 的垃圾回收器回收掉。另外,窗口的所有配置都使用了默認的配置。
這個窗口加載了一個 Url 路徑,這個路徑是以命令行參數的方式傳遞給應用程序的,而且是命令行的第三個參數。
app 和 BrowserWindow 都是 Electron 的內置模塊,這些內置模塊是通過 ES Module 的形式導入進來的,我們知道 Electron 的內置模塊都是通過 CJS Module 的形式導出的,這里之所以可以用 ES Module 導入,是因為我們接下來做的主進程編譯工作幫我們完成了相關的轉化工作。
開發(fā)環(huán)境 Vite 插件
主進程的代碼寫好之后,只有編譯過之后才能被 Electron 加載,我們是 通過 Vite
插件的形式來完成這個編譯工作和加載工作 的,如下代碼所示:
//plugins\devPlugin.ts import { ViteDevServer } from "vite"; export let devPlugin = () => { return { name: "dev-plugin", configureServer(server: ViteDevServer) { require("esbuild").buildSync({ entryPoints: ["./src/main/mainEntry.ts"], bundle: true, platform: "node", outfile: "./dist/mainEntry.js", external: ["electron"], }); server.httpServer.once("listening", () => { let { spawn } = require("child_process"); let addressInfo = server.httpServer.address(); let httpAddress = `http://${addressInfo.address}:${addressInfo.port}`; let electronProcess = spawn(require("electron").toString(), ["./dist/mainEntry.js", httpAddress], { cwd: process.cwd(), stdio: "inherit", }); electronProcess.on("close", () => { server.close(); process.exit(); }); }); }, }; };
這是一個簡單的 Vite 插件,在這個插件中我們注冊了一個名為 configureServer
的鉤子,當 Vite 為我們啟動 Http 服務的時候,configureServer
鉤子會被執(zhí)行。
這個鉤子的輸入參數為一個類型為 ViteDevServer
的對象 server
,這個對象持有一個 http.Server
類型的屬性 httpServer
,這個屬性就代表著我們調試 Vue 頁面的 http 服務,一般情況下地址為:http://127.0.0.1:5173/
我們可以 通過監(jiān)聽 server.httpServer
的 listening
事件來判斷 httpServer 是否已經成功啟動,如果已經成功啟動了,那么就啟動 Electron 應用,并給它傳遞兩個命令行參數,第一個參數是主進程代碼編譯后的文件路徑,第二個參數是 Vue 頁面的 http 地址,這里就是 http://127.0.0.1:5173/
為什么這里傳遞了兩個命令行參數,而主進程的代碼接收第三個參數(process.argv[2]
)當做 http 頁面的地址呢?因為 默認情況下 electron.exe 的文件路徑將作為第一個參數。也就是我們通過 require("electron")
獲得的字符串。
這個路徑一般是:node_modules\electron\dist\electron.exe
,如果這個路徑下沒有對應的文件,說明你的 Electron 模塊沒有安裝好。
我們是 通過 Node.js
child_process
模塊的 spawn
方法啟動 electron
子進程的,除了兩個命令行參數外,還傳遞了一個配置對象。
這個對象的 cwd
屬性用于設置當前的工作目錄,process.cwd()
返回的值就是當前項目的根目錄。stdio
用于設置 electron 進程的控制臺輸出,這里設置 inherit
可以讓 electron 子進程的控制臺輸出數據同步到主進程的控制臺。這樣我們在主進程中 console.log
的內容就可以在 VSCode 的控制臺上看到了。
當 electron 子進程退出的時候,我們要關閉 Vite 的 http 服務,并且控制父進程退出,準備下一次啟動。
http 服務啟動之前,我們 使用 esbuild
模塊完成了主進程 TypeScript 代碼的編譯工作 ,這個模塊是 Vite
自帶的,所以我們不需要額外安裝,可以直接使用。
主進程的入口文件是通過 entryPoints
配置屬性設置的,編譯完成后的輸出文件時通過 outfile
屬性配置的。
編譯平臺 platform
設置為 node
,排除的模塊 external
設置為 electron
, 正是這兩個設置使我們可以在主進程代碼中可以通過 import
的方式導入 electron 內置的模塊 。非但如此,Node 的內置模塊也可以通過 import
的方式引入。
這個 Vite 插件的代碼編寫好后,在 vite.config.ts
文件中引入一下就可以使用了,如下代碼所示:
// vite.config.ts import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import { devPlugin } from "./plugins/devPlugin"; import optimizer from "vite-plugin-optimizer"; export default defineConfig({ plugins: [devPlugin(), vue()], });
現(xiàn)在執(zhí)行命令 npm run dev
,你會看到 Electron 應用加載了 Vue 的首頁,如下圖所示:
關閉窗口,主進程和子進程也會跟著退出。修改一下 Vue 組件里的內容,窗口內顯示的內容也會跟著變化,說明熱更新機制在起作用。
渲染進程集成內置模塊
現(xiàn)在主進程內可以自由的使用 Electron 和 Node.js 的內置模塊了,但渲染進程還不行,接下去我們就為渲染進程集成這些內置模塊。
首先我們修改一下主進程的代碼,打開渲染進程的一些開關,允許渲染進程使用 Node.js 的內置模塊,如下代碼所示:
// src\main\mainEntry.ts import { app, BrowserWindow } from "electron"; process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = "true"; let mainWindow: BrowserWindow; app.whenReady().then(() => { let config = { webPreferences: { nodeIntegration: true, webSecurity: false, allowRunningInsecureContent: true, contextIsolation: false, webviewTag: true, spellcheck: false, disableHtmlFullscreenWindowResize: true, }, }; mainWindow = new BrowserWindow(config); mainWindow.webContents.openDevTools({ mode: "undocked" }); mainWindow.loadURL(process.argv[2]); });
在這段代碼中,有以下幾點需要注意:
1:ELECTRON_DISABLE_SECURITY_WARNINGS
用于設置渲染進程開發(fā)者調試工具的警告,這里設置為 true 就不會再顯示任何警告了。
如果渲染進程的代碼可以訪問 Node.js 的內置模塊,而且渲染進程加載的頁面(或腳本)是第三方開發(fā)的,那么惡意第三方就有可能使用 Node.js 的內置模塊傷害最終用戶 。這就是為什么這里要有這些警告的原因。如果你的應用不會加載任何第三方的頁面或腳本。那么就不用擔心這些安全問題啦。
2:nodeIntegration
配置項的作用是把 Node.js 環(huán)境集成到渲染進程中,contextIsolation
配置項的作用是在同一個 JavaScript 上下文中使用 Electron API。其他配置項與本文主旨無關,大家感興趣的話可以自己翻閱官方文檔。
3: webContents
的openDevTools
方法用于打開開發(fā)者調試工具。
完成這些工作后我們就可以在開發(fā)者調試工具中訪問 Node.js 和 Electron 的內置模塊了。
設置 Vite 模塊別名與模塊解析鉤子
雖然我們可以在開發(fā)者調試工具中使用 Node.js 和 Electron 的內置模塊,但現(xiàn)在還不能在 Vue 的頁面內使用這些模塊。
這是因為 Vite 主動屏蔽了這些內置的模塊,如果開發(fā)者強行引入它們,那么大概率會得到如下報錯:
Module "xxxx" has been externalized for browser compatibility and cannot be accessed in client code.
接下去我們就介紹如何讓 Vite 加載 Electron 的內置模塊和 Node.js 的內置模塊。
首先我們?yōu)楣こ贪惭b一個 Vite 組件:vite-plugin-optimizer
npm i vite-plugin-optimizer -D
然后修改 vite.config.ts 的代碼,讓 Vite 加載這個插件,如下代碼所示:
// vite.config.ts import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import { devPlugin, getReplacer } from "./plugins/devPlugin"; import optimizer from "vite-plugin-optimizer"; export default defineConfig({ plugins: [optimizer(getReplacer()), devPlugin(), vue()], });
vite-plugin-optimizer 插件會為你創(chuàng)建一個臨時目錄:node_modules.vite-plugin-optimizer
然后把類似 const fs = require('fs'); export { fs as default }
這樣的代碼寫入這個目錄下的 fs.js 文件中。
渲染進程執(zhí)行到:import fs from "fs" 時,就會請求這個目錄下的 fs.js 文件,這樣就達到了在渲染進程中引入 Node 內置模塊的目的。
getReplacer 方法是我們?yōu)?vite-plugin-optimizer 插件提供的內置模塊列表。代碼如下所示:
// plugins\devPlugin.ts export let getReplacer = () => { let externalModels = ["os", "fs", "path", "events", "child_process", "crypto", "http", "buffer", "url", "better-sqlite3", "knex"]; let result = {}; for (let item of externalModels) { result[item] = () => ({ find: new RegExp(`^${item}$`), code: `const ${item} = require('${item}');export { ${item} as default }`, }); } result["electron"] = () => { let electronModules = ["clipboard", "ipcRenderer", "nativeImage", "shell", "webFrame"].join(","); return { find: new RegExp(`^electron$`), code: `const {${electronModules}} = require('electron');export {${electronModules}}`, }; }; return result; };
我們在這個方法中把一些常用的 Node 模塊和 electron 的內置模塊提供給了 vite-plugin-optimizer 插件,以后想要增加新的內置模塊只要修改這個方法即可。而且 vite-plugin-optimizer 插件不僅用于開發(fā)環(huán)境,編譯 Vue 項目時,它也會參與工作 。
再次運行你的應用,看看現(xiàn)在渲染進程是否可以正確加載內置模塊了呢?你可以通過如下代碼在 Vue 組件中做這項測試:
//src\App.vue import fs from "fs"; import { ipcRenderer } from "electron"; import { onMounted } from "vue"; onMounted(() => { console.log(fs.writeFileSync); console.log(ipcRenderer); });
不出意外的話,開發(fā)者調試工具將會輸出如下內容:
總結
現(xiàn)在我們邁出了萬里長征的第一步,構建好了 Vue3+Vite3+Electron 的開發(fā)環(huán)境 ,而且完成這項工作并不依賴于市面上任何一個現(xiàn)成的構建工具,這個開發(fā)環(huán)境是我們自己動手一點一點搭起來的,以后我們想增加或者修改一項功能,都可以很從容地自己動手處理。
非但如此,我們還通過本講內容向你介紹了 Vite 插件的開發(fā)技巧和如何創(chuàng)建一個簡單的 Electron 應用等知識。下一講我們將在本節(jié)課的基礎上,進一步介紹如何使用 Vite 插件制作 Electron 應用的安裝包。
到此這篇關于如何開發(fā)Vite3插件構建Electron開發(fā)環(huán)境的文章就介紹到這了,更多相關Vite3插件構建Electron開發(fā)環(huán)境內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spring boot 和Vue開發(fā)中CORS跨域問題解決
這篇文章主要介紹了Spring boot 和Vue開發(fā)中CORS跨域問題解決,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09vuejs2.0運用原生js實現(xiàn)簡單拖拽元素功能
這篇文章主要為大家詳細介紹了vuejs2.0運用原生js實現(xiàn)簡單拖拽元素功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12