Electron 如何調(diào)用本地模塊的方法
Electron 結(jié)合了 Chromium、Node.js 和用于調(diào)用操作系統(tǒng)本地功能的 API(如打開(kāi)文件窗口、通知、圖標(biāo)等,基于 Electron 的開(kāi)發(fā),就好像開(kāi)發(fā)一個(gè)網(wǎng)頁(yè)一樣,而且能夠無(wú)縫地使用 Node。或者說(shuō):就好像構(gòu)建一個(gè) Node app,并通過(guò) HTML 和 CSS 構(gòu)建界面。
那么如何在頁(yè)面中調(diào)用 Node API 呢?
碰到了一些坑…
先從頁(yè)面加載方式說(shuō)起,Electron 中加載頁(yè)面的方式有兩種:
一種是直接加載本地文件,另一種是通過(guò) http 網(wǎng)絡(luò)請(qǐng)求頁(yè)面。
//方法1 本地路徑 win.loadURL(url.format({ pathname: path.join(__dirname, '/dist/index.html'), protocol: 'file:', slashes: true }));
//方法2 網(wǎng)絡(luò)路徑 win.loadURL('http://localhost:3000');
現(xiàn)在我想要在某個(gè)js文件中引用一個(gè)本地的 npm 包,其中包含 Node API,所以在瀏覽器中無(wú)法使用。
var local = window.nodeRequire('local');
此時(shí)出現(xiàn)一個(gè)問(wèn)題,使用方法1運(yùn)行正常,但使用方法2時(shí)報(bào)錯(cuò),但是如果使用方法1,每次修改完代碼都需要先打包一遍,再使用 Electron 啟動(dòng),耗時(shí)耗力啊。繼續(xù)尋找解決方法。
can not find module xxx
調(diào)試發(fā)現(xiàn)在使用網(wǎng)絡(luò)文件時(shí),在調(diào)用 module.js 中的 Module._load 函數(shù)時(shí)參入的參數(shù) parent 為
重點(diǎn)在下面兩個(gè)變量,從 Http 加載頁(yè)面時(shí),由于路徑是網(wǎng)絡(luò)地址,所以 Electron 將文件名設(shè)置為 Electron 安裝目錄下的 init.js.
filename: "C:\Users\asus\AppData\Roaming\npm\node_modules\electron\dist\resources\electron.asar\renderer\init.js"
paths: Array[0]
而在使用本地 index.html 時(shí),pathname 指向正確的路徑,而且 paths 中也包含了多個(gè) node_modules 路徑,module在初始化時(shí)會(huì)將當(dāng)前路徑以及上一級(jí)、上上一級(jí)…直到根目錄的 node_modules 作為搜索路徑。
filename: "E:\WebStormWorkspace\electron_require\index.html"
從下面 module.js 源碼可以看到,文件名解析的時(shí)候正式利用了這個(gè) paths 中的路徑。因?yàn)?paths 中的空的,所以找不到所需要的模塊。
其實(shí) Electron 是從安全的角度考慮,在從 Http 請(qǐng)求中加載網(wǎng)頁(yè)時(shí),如果能直接調(diào)用本地的一些模塊,會(huì)比較危險(xiǎn)。
Module._resolveFilename = function(request, parent, isMain) { if (NativeModule.nonInternalExists(request)) { return request; } var resolvedModule = Module._resolveLookupPaths(request, parent); var id = resolvedModule[0]; var paths = resolvedModule[1]; // look up the filename first, since that's the cache key. debug('looking for %j in %j', id, paths); var filename = Module._findPath(request, paths, isMain); if (!filename) { var err = new Error("Cannot find module '" + request + "'"); err.code = 'MODULE_NOT_FOUND'; throw err; } return filename; };
此時(shí)很自然地想到可以把所需要模塊的路徑加入到 paths 中去,但這其實(shí)是不可行的,Electron 包含主進(jìn)程和渲染進(jìn)程,主進(jìn)程就是這里命名main.js 的文件,該文件是每個(gè) Electron 應(yīng)用的入口。它控制了應(yīng)用的生命周期(從打開(kāi)到關(guān)閉)。它能調(diào)用原生元素和創(chuàng)建新的(多個(gè))渲染進(jìn)程,而且整個(gè) Node API 是內(nèi)置其中的。
渲染進(jìn)程就是一個(gè)瀏覽器窗口,現(xiàn)在我們的 js 跑在渲染進(jìn)程里面,所以我們并不能直接在主進(jìn)程里面修改渲染進(jìn)程的數(shù)據(jù)。
Electron 提供了 IPC 接口專(zhuān)門(mén)用于主進(jìn)程和渲染進(jìn)程之間的通信,他提供了同步和異步兩種方法,同步方法直接設(shè)置 event.returnValue,異步方法使用 event.sender.send(…).
// In main process. const {ipcMain} = require('electron') ipcMain.on('asynchronous-message', (event, arg) => { console.log(arg) // prints "ping" event.sender.send('asynchronous-reply', 'pong') }) ipcMain.on('synchronous-message', (event, arg) => { console.log(arg) // prints "ping" event.returnValue = 'pong' })
// In renderer process (web page). const {ipcRenderer} = require('electron') console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong" ipcRenderer.on('asynchronous-reply', (event, arg) => { console.log(arg) // prints "pong" }) ipcRenderer.send('asynchronous-message', 'ping')
但其實(shí)有更簡(jiǎn)單的方法,使用 remote 模塊來(lái)直接調(diào)用:
const remote = window.nodeRequire('electron').remote; var local = remote.require('local');
這樣子就可以直接使用外部模塊了,這里為什么能引用 electron 模塊,而其他的不可以呢?
繼續(xù)看源碼, Electron 重寫(xiě)了 Module._resolveFilename 函數(shù),在 require(‘electron') 時(shí),就直接返回路徑,所以就可以找到啦。
// Patch Module._resolveFilename to always require the Electron API when // require('electron') is done. const electronPath = path.join(__dirname, '..', process.type, 'api', 'exports', 'electron.js') const originalResolveFilename = Module._resolveFilename Module._resolveFilename = function (request, parent, isMain) { if (request === 'electron') { return electronPath } else { return originalResolveFilename(request, parent, isMain) } } }.call(this, exports, require, module, __filename, __dirname); });
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- electron + vue項(xiàng)目實(shí)現(xiàn)打印小票功能及實(shí)現(xiàn)代碼
- Electron 調(diào)用命令行(cmd)
- electron 如何將任意資源打包的方法步驟
- 使用electron將vue-cli項(xiàng)目打包成exe的方法
- electron-builder打包配置詳解
- electron實(shí)現(xiàn)靜默打印的示例代碼
- Electron + vue 打包桌面操作流程詳解
- electron打包vue項(xiàng)目的方法 步驟
- 用Electron寫(xiě)個(gè)帶界面的nodejs爬蟲(chóng)的實(shí)現(xiàn)方法
- electron原理,以及electron生成可執(zhí)行文件的方法實(shí)例分析
相關(guān)文章
vue組件傳值的實(shí)現(xiàn)方式小結(jié)【三種方式】
這篇文章主要介紹了vue組件傳值的實(shí)現(xiàn)方式,結(jié)合實(shí)例形式總結(jié)分析了vue.js組建傳值的三種實(shí)現(xiàn)方式,包括父?jìng)髯?、子傳父及非父子傳?需要的朋友可以參考下2020-02-02vue項(xiàng)目中更改名字和圖標(biāo)的簡(jiǎn)單實(shí)現(xiàn)步驟
今天在寫(xiě)vue項(xiàng)目時(shí)碰到的問(wèn)題是怎么修改vue的網(wǎng)頁(yè)圖標(biāo),所以下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目中更改名字和圖標(biāo)的簡(jiǎn)單實(shí)現(xiàn),文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08vue使用vue-json-viewer展示JSON數(shù)據(jù)的詳細(xì)步驟
最近在開(kāi)發(fā)一個(gè)公司的投放管理系統(tǒng)的操作日志模塊,要查看某條操作日志的請(qǐng)求參數(shù),要將請(qǐng)求的參數(shù)以JSON格式的形式展示出來(lái),下面這篇文章主要給大家介紹了vue使用vue-json-viewer展示JSON數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2022-09-09vue-cli 3.0 引入mint-ui報(bào)錯(cuò)問(wèn)題及解決
這篇文章主要介紹了vue-cli 3.0 引入mint-ui報(bào)錯(cuò)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05VUE使用day.js顯示時(shí)分秒并實(shí)時(shí)更新時(shí)間效果實(shí)例
vue.js是目前比較流行的前端框架之一,它提供了非常多的基礎(chǔ)組件和工具庫(kù),以方便開(kāi)發(fā)者快速搭建具有可重用性的web應(yīng)用,下面這篇文章主要給大家介紹了關(guān)于VUE使用day.js顯示時(shí)分秒并實(shí)時(shí)更新時(shí)間效果的相關(guān)資料,需要的朋友可以參考下2024-04-04如何用electron把vue項(xiàng)目打包為桌面應(yīng)用exe文件
這篇文章主要介紹了如何用electron把vue項(xiàng)目打包為桌面應(yīng)用exe文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05vue-cli axios請(qǐng)求方式及跨域處理問(wèn)題
這篇文章主要介紹了vue-cli axios請(qǐng)求方式及跨域處理問(wèn)題,文中還給大家提到了vue中axios解決跨域問(wèn)題和攔截器使用,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2018-03-03