Electron如何调⽤本地模块的⽅法
Electron 结合了 Chromium、Node.js 和⽤于调⽤操作系统本地功能的 API(如打开⽂件窗⼝、通知、图标等,基于 Electron 的开发,就好像开发⼀个⽹页⼀样,⽽且能够⽆缝地使⽤ Node。或者说:就好像构建⼀个 Node app,并通过 HTML 和 CSS 构建界⾯。
那么如何在页⾯中调⽤ Node API 呢?
碰到了⼀些坑…
先从页⾯加载⽅式说起,Electron 中加载页⾯的⽅式有两种:
⼀种是直接加载本地⽂件,另⼀种是通过 http ⽹络请求页⾯。
//⽅法1 本地路径
win.loadURL(url.format({
pathname: path.join(__dirname, '/dist/index.html'),
protocol: 'file:',
slashes: true
}));
//⽅法2 ⽹络路径
win.loadURL('localhost:3000');
现在我想要在某个js⽂件中引⽤⼀个本地的 npm 包,其中包含 Node API,所以在浏览器中⽆法使⽤。
var local = deRequire('local');
此时出现⼀个问题,使⽤⽅法1运⾏正常,但使⽤⽅法2时报错,但是如果使⽤⽅法1,每次修改完代码都需要先打包⼀遍,再使⽤ Electron 启动,耗时耗⼒啊。继续寻解决⽅法。
can not find module xxx
调试发现在使⽤⽹络⽂件时,在调⽤ module.js 中的 Module._load 函数时参⼊的参数 parent 为
重点在下⾯两个变量,从 Http 加载页⾯时,由于路径是⽹络地址,所以 Electron 将⽂件名设置为 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 时,pathname 指向正确的路径,⽽且 paths 中也包含了多个 node_modules 路径,module在初始化时会将当前路径以及上⼀级、上上⼀级…直到根⽬录的 node_modules 作为搜索路径。
filename: "E:\WebStormWorkspace\electron_require\index.html"
从下⾯ module.js 源码可以看到,⽂件名解析的时候正式利⽤了这个 paths 中的路径。因为 paths 中的空的,所以不到所需要的模块。
其实 Electron 是从安全的⾓度考虑,在从 Http 请求中加载⽹页时,如果能直接调⽤本地的⼀些模块,会⽐较危险。
Module._resolveFilename = function(request, parent, isMain) {
if (InternalExists(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 + "'");
throw err;
}
return filename;
};
此时很⾃然地想到可以把所需要模块的路径加⼊到 paths 中去,但这其实是不可⾏的,Electron 包含
主进程和渲染进程,主进程就是这⾥命名main.js 的⽂件,该⽂件是每个 Electron 应⽤的⼊⼝。它控制了应⽤的⽣命周期(从打开到关闭)。它能调⽤原⽣元素和创建新的(多个)渲染进程,⽽且整个 Node API 是内置其中的。
渲染进程就是⼀个浏览器窗⼝,现在我们的 js 跑在渲染进程⾥⾯,所以我们并不能直接在主进程⾥⾯修改渲染进程的数据。
Electron 提供了 IPC 接⼝专门⽤于主进程和渲染进程之间的通信,他提供了同步和异步两种⽅法,同步⽅法直接设置urnValue,异步⽅法使⽤ event.sender.send(…).
// In main process.
electron vue教程
const {ipcMain} = require('electron')
<('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.sender.send('asynchronous-reply', 'pong')
})
<('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
})
// In renderer process (web page).
const {ipcRenderer} = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
<('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')
但其实有更简单的⽅法,使⽤模块来直接调⽤:
const remote = deRequire('electron').remote;
var local = quire('local');
这样⼦就可以直接使⽤外部模块了,这⾥为什么能引⽤ electron 模块,⽽其他的不可以呢?
继续看源码, Electron 重写了 Module._resolveFilename 函数,在 require(‘electron') 时,就直接返回路径,所以就可以到啦。
// Patch Module._resolveFilename to always require the Electron API when
// require('electron') is done.
const electronPath = path.join(__dirname, '..', pe, '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); });
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。