请教一下vite-renderer.config中的resolveElectron函数
qianjiachun opened this issue · comments
resolveElectron似乎在plugins中删掉也是可以正常调试和打包的。
想请教一下这个函数的意图和作用。
最近在学习electron相关技术,该项目让我受益匪浅,感谢作者
一些前奏解释
一、 首先这个项目的本意不希望用户在 Renderer-process 中使用 Electron、NodeJs API
二、 resolveElectron 插件设计目的是为了一些仍然希望在 Renderer-process 中使用 Electron、NodeJs API 的用户
然后他们会在 Main-process 中开启 nodeIntegration: true
contextIsolation: true
这会直接导致一个报错 __dirname is not defined
三、 为此为了解决上述的潜在问题,我设计了 resolveElectron
这也解释了“如果不去触碰上述两点 resolveElectron
可有可无”
经典报错: __dirname is not defined
一切要从 ESModule 开始 👉 NodeJs 在 ESModule 下 No __filename or __dirname
vite 在开发时期强依赖 ESModule 打包时期默认也是 ESModule
众所周知 👉 electron 共有三种环境/三种状态即: NodeJs、Electron-Main、Electron-Renderer
使用 vite 启动 electron 时候,为 NodeJs 运行环境,node_modules/electron 包导出的只是一个 electron.exe 的文件路径
当使用 vite 且在 Electron-Renderer 中使用 import electron from 'electron'
时候 vite 的默认行为会使用 NodeJs 环境下的 electron —— 遂报错
node_modules/electron/index.js 👉 真实情况此文件会被编译到 .vite 缓存目录下
const fs = require('fs');
const path = require('path');
// 🐞 🐞 🐞 🐞 __dirname is not defined 报错就会出现在下面这行 🐛 🐛 🐛 🐛
const pathFile = path.join(__dirname, 'path.txt');
function getElectronPath () {
let executablePath;
if (fs.existsSync(pathFile)) {
executablePath = fs.readFileSync(pathFile, 'utf-8');
}
if (process.env.ELECTRON_OVERRIDE_DIST_PATH) {
return path.join(process.env.ELECTRON_OVERRIDE_DIST_PATH, executablePath || 'electron');
}
if (executablePath) {
return path.join(__dirname, 'dist', executablePath);
} else {
throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again');
}
}
module.exports = getElectronPath();
Renderer-process 中正确加载 Electron、NodeJs API
一、 设想下如果我们避开 vite 的默认行为,Renderer-process 中的 import electron 'electron'
本意是指的 Electron 的内置模块,就像 NodeJs 中集成了 fs、path 那样
二、 vite 最重要的概念 bundless
我喜欢叫 non-bundle
vite 在 web 开发下,也就是 Renderer-process 加载的通过 vite serve
启动的本地服务代码就是 bundless
形式,这种代码全部是 ESModule
格式
-
思考一:
Renderer-process 开启 NodeJs 集成后require
函数就有了,那么如果我用了require('electron')
可以工作么?答案是可以的
而且还能避开浏览器识别import
而向 vite 发出electron
请求!妙啊~
require('electron')
真是好从西啊 -- 但是我还想用import electron from 'electron'
啊啊啊啊~ -
思考二:
我让你用import electron from 'electron'
允许请求到 vite 服务器;我给你返回require('electron')
不就行了么~!哎 - 就是玩儿~!
import -- Electron、NodeJS API 设计
一、 在 vite 中通过配置 resolve.alias
把 electron
指向一个我做的文件 - 例如:
项目目录/node_modules/.自定义文件夹/electron.js
/**
* 🚧 下面的代码会被 vite 抛到 Renderer-process 中运行
*/
const electron = require("electron");
const {
clipboard,
nativeImage,
shell,
contextBridge,
crashReporter,
ipcRenderer,
webFrame,
desktopCapturer,
deprecate,
} = electron;
export {
electron as default,
clipboard,
nativeImage,
shell,
contextBridge,
crashReporter,
ipcRenderer,
webFrame,
desktopCapturer,
deprecate,
}
- alias 配置改一下
config.resolve.alias = {
electron: '项目目录/node_modules/.自定义文件夹/electron.js',
}
- 生成下缓存文件
// 生成缓存文件代码
🚧 实际中 “alias 配置,缓存文件生成” 这两件事儿交给 vite-plugin-resolve 去做!
二、 同理可证 NodeJs 模块也可以像 Electron 那样设计
就不一一列出了。。。
三、 最后 resolveElectron
中还有个 vite-plugin-electron-config
-
vite 会预构建所有依赖的模块,并且放到node_modeules/.vite
缓存目录中,且优先命中
我们需要 打断下 vite 的缓存命中 -- 不要编译我们辛辛苦苦做好的 Electron、NodeJs 内置模块的ESModule
版本 -
2022-01-30 该功能已内置到 vite-plugin-resolve 中
config.optimizeDeps.exclude = [
'electron',
'fs',
'path',
...其他 NodeJs 内置模块
];
感谢解答!
@caoxiemeihao I think this documentation is really helpful. If you don't mind, can you add an English
translation for this please?
@K3NZ11 Thanks for your feedback, I'll trying to do it, but my english is poor. 😅
文档已发布在 知乎专栏 :)