Electron如何調(diào)用本地模塊的方法

Electron 結(jié)合了 Chromium、Node.js 和用于調(diào)用操作系統(tǒng)本地功能的 API(如打開文件窗口、通知、圖標(biāo)等,基于 Electron 的開發(fā),就好像開發(fā)一個(gè)網(wǎng)頁一樣,而且能夠無縫地使用 Node?;蛘哒f:就好像構(gòu)建一個(gè) Node app,并通過 HTML 和 CSS 構(gòu)建界面。

創(chuàng)新互聯(lián)公司堅(jiān)實(shí)的技術(shù)研發(fā)基礎(chǔ)贏得了行業(yè)內(nèi)的良好口碑,公司成立10多年來,為數(shù)千家企業(yè)提供過網(wǎng)站建設(shè)、軟件開發(fā)、搜索引擎優(yōu)化技術(shù)、互聯(lián)網(wǎng)大數(shù)據(jù)整合營銷服務(wù),多年的技術(shù)服務(wù)成功經(jīng)驗(yàn)、眾多的客戶使我們能懂得更多,做得更好。"讓您的網(wǎng)站跑起來"是我們一直追求的目標(biāo)!

那么如何在頁面中調(diào)用 Node API 呢?

碰到了一些坑…

先從頁面加載方式說起,Electron 中加載頁面的方式有兩種:
一種是直接加載本地文件,另一種是通過 http 網(wǎng)絡(luò)請(qǐng)求頁面。

//方法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,所以在瀏覽器中無法使用。

var local = window.nodeRequire('local');

此時(shí)出現(xiàn)一個(gè)問題,使用方法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 為

Electron 如何調(diào)用本地模塊的方法

重點(diǎn)在下面兩個(gè)變量,從 Http 加載頁面時(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 作為搜索路徑。

Electron 如何調(diào)用本地模塊的方法

filename: "E:\WebStormWorkspace\electron_require\index.html"

從下面 module.js 源碼可以看到,文件名解析的時(shí)候正式利用了這個(gè) paths 中的路徑。因?yàn)?paths 中的空的,所以找不到所需要的模塊。

其實(shí) Electron 是從安全的角度考慮,在從 Http 請(qǐng)求中加載網(wǎng)頁時(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)用的生命周期(從打開到關(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 接口專門用于主進(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 模塊來直接調(diào)用:

const remote = window.nodeRequire('electron').remote;
var local = remote.require('local');

這樣子就可以直接使用外部模塊了,這里為什么能引用 electron 模塊,而其他的不可以呢?

繼續(xù)看源碼, Electron 重寫了 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í)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

分享題目:Electron如何調(diào)用本地模塊的方法
網(wǎng)站URL:http://muchs.cn/article12/ghchgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App設(shè)計(jì)移動(dòng)網(wǎng)站建設(shè)、定制網(wǎng)站網(wǎng)站營銷、搜索引擎優(yōu)化、網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站