vite-plugin-electron-renderer
Advanced tools
Comparing version 0.5.3 to 0.5.4
## [2022-07-10] v0.5.4 | ||
- 75b60c2 docs: v0.5.4 | ||
- 1b933d2 refactor(๐ฑ): better logic | ||
## [2022-07-07] v0.5.3 | ||
- 69eb531 docs: v0.5.3 | ||
- cc98ed9 feat: `ResolveModules['options']` optional | ||
- db03a72 chore: remove `useNodeJs.default = useNodeJs` | ||
- c30dc1b fix(๐): add `electron` to ` builtins | ||
## [2022-07-07] v0.5.2 | ||
@@ -3,0 +15,0 @@ |
{ | ||
"name": "vite-plugin-electron-renderer", | ||
"version": "0.5.3", | ||
"version": "0.5.4", | ||
"description": "Support use Node.js API in Electron-Renderer", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -9,2 +9,6 @@ const fs = require('fs'); | ||
function useNodeJs(options = {}) { | ||
/** | ||
* @type {import('vite').ConfigEnv} | ||
*/ | ||
let env; | ||
const builtins = []; | ||
@@ -14,4 +18,38 @@ const dependencies = []; | ||
const CJS_modules = []; // builtins + dependencies | ||
const moduleCache = new Map(); | ||
const moduleCache = new Map([ | ||
['electron', ` | ||
/** | ||
* All exports module see https://www.electronjs.org -> API -> Renderer Process Modules | ||
*/ | ||
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, | ||
}`], | ||
]); | ||
// When `electron` files or folders exist in the root directory, it will cause Vite to incorrectly splicing the `/@fs/` prefix. | ||
// Here, use `\0` prefix avoid this behavior | ||
const prefix = '\0'; | ||
return { | ||
@@ -22,27 +60,17 @@ name: 'vite-plugin-electron-renderer:use-node.js', | ||
// ๐ง Must be use config hook | ||
config(config, env) { | ||
config(config, _env) { | ||
env = _env; | ||
if (env.command === 'serve') { | ||
// Vite ---- resolve.alias ---- | ||
if (!config.resolve) config.resolve = {}; | ||
// TODO: Compatible ESM module | ||
// If the package is ESM module, like node-fetch | ||
if (!config.resolve.conditions) config.resolve.conditions = ['node']; | ||
if (!config.resolve.alias) config.resolve.alias = []; | ||
const electronjs = path.join(__dirname, 'electron-renderer.js'); | ||
if (Array.isArray(config.resolve.alias)) { | ||
config.resolve.alias.push({ find: 'electron', replacement: electronjs }); | ||
} else { | ||
config.resolve.alias['electron'] = electronjs; | ||
} | ||
// Vite ---- optimizeDeps.exclude ---- | ||
if (!config.optimizeDeps) config.optimizeDeps = {}; | ||
if (!config.optimizeDeps.exclude) config.optimizeDeps.exclude = []; | ||
if (!config.optimizeDeps.exclude.includes('electron')) config.optimizeDeps.exclude.push('electron'); | ||
config.optimizeDeps.exclude.push('electron'); | ||
return config; | ||
} | ||
} else if (env.command === 'build') { | ||
if (env.command === 'build') { | ||
// Rollup ---- init ---- | ||
@@ -55,3 +83,2 @@ if (!config.build) config.build = {}; | ||
let external = config.build.rollupOptions.external; | ||
const electronBuiltins = CJS_modules.concat('electron'); | ||
if ( | ||
@@ -62,7 +89,7 @@ Array.isArray(external) || | ||
) { | ||
external = electronBuiltins.concat(external); | ||
external = CJS_modules.concat(external); | ||
} else if (typeof external === 'function') { | ||
const original = external; | ||
external = function (source, importer, isResolved) { | ||
if (electronBuiltins.includes(source)) { | ||
if (CJS_modules.includes(source)) { | ||
return true; | ||
@@ -73,6 +100,4 @@ } | ||
} else { | ||
external = electronBuiltins; | ||
external = CJS_modules; | ||
} | ||
// make builtin modules & electron external when rollup | ||
config.build.rollupOptions.external = external; | ||
@@ -88,9 +113,13 @@ | ||
// external modules such as `electron`, `fs` | ||
// they can only be loaded normally under CommonJs | ||
// they can only be loaded normally on CommonJs | ||
if (output.format === undefined) output.format = 'cjs'; | ||
} | ||
return config; | ||
} | ||
}, | ||
configResolved(config) { | ||
const resolved = resolveModules(config, options); | ||
builtins.push(...resolved.builtins); | ||
@@ -102,68 +131,61 @@ dependencies.push(...resolved.dependencies); | ||
resolveId(source) { | ||
// TODO: Identify ESM | ||
const id = source.replace('node:', ''); | ||
if (CJS_modules.includes(id)) return id; | ||
if (env.command === 'serve') { | ||
if (ESM_deps.includes(source)) return; // by vite-plugin-esmodule | ||
if (CJS_modules.includes(source)) return prefix + source; | ||
} | ||
}, | ||
load(id) { | ||
/** | ||
* ## ๐ฏ Using Node.js package in Electron-Renderer | ||
* | ||
* Many times, many people want to use the Node.js package in Electron-Renderer, but it may not work correctly in Vite by default. | ||
* ๆๅพๅคๆถๅๅพๅคไบบๆณๅจ Electron-Renderer ไธญไฝฟ็จ Node.js ๆจกๅ๏ผไฝ่ฟๅจ Vite ๅฏ่ฝๆ ๆณๆญฃๅธธ็ๆๅปบใ | ||
* | ||
* e.g. | ||
* Let's use `serialport` as an example. | ||
* ่ฎฉๆไปฌไฝฟ็จ `serialport` ไธพไธชไพๅญ ๐ฐใ | ||
* | ||
* ```js | ||
* // โ May not work correctly in Vite by default. | ||
* import serialport, { SerialPort, SerialPortMock } from 'serialport'; | ||
* ``` | ||
* | ||
* At this time, we need to use load-hook to convert `serialport` to ensure that it works normally. | ||
* ่ฟๆถๅๆไปฌ้่ฆไฝฟ็จ load-hook ่ฝฌๆข `serialport`๏ผไปฅ็กฎไฟๅฎ่ฝๆญฃๅธธๅทฅไฝใ | ||
* | ||
* e.g. | ||
* | ||
* ```js | ||
* // serialport | ||
* const _M_ = require('serialport'); | ||
* const _D_ = _M_.default || _M_; | ||
* export { _D_ as default }; | ||
* export const SerialPort = _M_.SerialPort; | ||
* export const SerialPortMock = _M_.SerialPortMock; | ||
* ``` | ||
* | ||
* Try to use again. | ||
* | ||
* ```js | ||
* // โ This looks like nothing has changed, but it works normally after the load-hook converted. | ||
* import serialport, { SerialPort, SerialPortMock } from 'serialport'; | ||
* ``` | ||
* | ||
* ๐ง It should be noted that the Node.js package, as a dependency of the project, should be placed in `dependencies`; Unless you konw how to build them with Vite. | ||
* ้่ฆๆณจๆ็ไธ็นๆฏ๏ผNode.js ๆจกๅไฝไธบ้กน็ฎ็ไพ่ต๏ผๅบ่ฏฅๆพๅฐ `dependencies` ไธญ๏ผ้ค้ไฝ ็ฅ้ๅฆไฝไฝฟ็จ Vite ๆๅปบไปไปฌใ | ||
*/ | ||
if (env.command === 'serve') { | ||
/** | ||
* ``` | ||
* ๐ฏ Using Node.js packages(CJS) in Electron-Renderer(vite serve) | ||
* | ||
* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ | ||
* โ import { readFile } from 'fs' โ โ Vite dev server โ | ||
* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ | ||
* โ โ | ||
* โ 1. HTTP(Request): fs module โ | ||
* โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ> โ | ||
* โ โ | ||
* โ โ | ||
* โ 2. Intercept in load-hook(vite-plugin-electron-renderer) โ | ||
* โ 3. Generate a virtual module(fs) โ | ||
* โ โ โ | ||
* โ const _M_ = require('fs') โ | ||
* โ export const readFile = _M_.readFile โ | ||
* โ โ | ||
* โ โ | ||
* โ 4. HTTP(Response): fs module โ | ||
* โ <โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ | ||
* โ โ | ||
* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ | ||
* โ import { readFile } from 'fs' โ โ Vite dev server โ | ||
* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ | ||
* | ||
* ``` | ||
*/ | ||
if (CJS_modules.includes(id)) { | ||
const cache = moduleCache.get(id); | ||
if (cache) return cache; | ||
id = id.replace(prefix, '') | ||
if (CJS_modules.includes(id)) { | ||
const cache = moduleCache.get(id); | ||
if (cache) return cache; | ||
const nodeModule = require(id); | ||
const requireModule = `const _M_ = require("${id}");`; | ||
const exportDefault = `const _D_ = _M_.default || _M_;\nexport { _D_ as default };`; | ||
const exportMembers = Object | ||
.keys(nodeModule) | ||
.filter(n => n !== 'default') | ||
.map(attr => `export const ${attr} = _M_.${attr};`).join('\n') | ||
const nodeModuleCodeSnippet = ` | ||
${requireModule} | ||
${exportDefault} | ||
${exportMembers} | ||
`.trim(); | ||
const nodeModule = require(id); | ||
const requireModule = `const _M_ = require("${id}");`; | ||
const exportDefault = `const _D_ = _M_.default || _M_;\nexport { _D_ as default };`; | ||
const exportMembers = Object | ||
.keys(nodeModule) | ||
.filter(n => n !== 'default') | ||
.map(attr => `export const ${attr} = _M_.${attr};`).join('\n') | ||
const nodeModuleCodeSnippet = ` | ||
${requireModule} | ||
${exportDefault} | ||
${exportMembers} | ||
`.trim(); | ||
moduleCache.set(id, nodeModuleCodeSnippet); | ||
return nodeModuleCodeSnippet; | ||
moduleCache.set(id, nodeModuleCodeSnippet); | ||
return nodeModuleCodeSnippet; | ||
} | ||
} | ||
}, | ||
@@ -189,6 +211,6 @@ }; | ||
const pkg = require(pkgId); | ||
for (const package of Object.keys(pkg.dependencies || {})) { | ||
for (const npmPkg of Object.keys(pkg.dependencies || {})) { | ||
const _pkgId = lookupFile( | ||
'package.json', | ||
[root, cwd].map(r => `${r}/node_modules/${package}`), | ||
[root, cwd].map(r => `${r}/node_modules/${npmPkg}`), | ||
); | ||
@@ -198,3 +220,3 @@ if (_pkgId) { | ||
if (_pkg.type === 'module') { | ||
ESM_deps.push(package); | ||
ESM_deps.push(npmPkg); | ||
continue; | ||
@@ -205,3 +227,3 @@ } | ||
// TODO: Nested package name, but you can explicity include it by `options.resolve` | ||
dependencies.push(package); | ||
dependencies.push(npmPkg); | ||
} | ||
@@ -232,2 +254,4 @@ } | ||
useNodeJs.resolveModules = resolveModules; | ||
// useNodeJs.default = useNodeJs; | ||
// โ | ||
// Function { | ||
@@ -240,3 +264,2 @@ // default: <ref *1> [Function: useNodeJs] { | ||
// } | ||
// useNodeJs.default = useNodeJs; | ||
module.exports = useNodeJs; |
@@ -69,2 +69,3 @@ # vite-plugin-electron-renderer | ||
<!-- | ||
###### Electron-Main | ||
@@ -74,7 +75,6 @@ | ||
import { readFile } from 'fs' | ||
import { ipcRenderer } from 'electron' | ||
โ | ||
const { readFile } = require('fs') | ||
const { ipcRenderer } = require('electron') | ||
``` | ||
--> | ||
@@ -85,6 +85,4 @@ ###### Electron-Renderer(vite build) | ||
import { readFile } from 'fs' | ||
import { ipcRenderer } from 'electron' | ||
โ | ||
const { readFile } = require('fs') | ||
const { ipcRenderer } = require('electron') | ||
``` | ||
@@ -118,29 +116,13 @@ | ||
[๐ See Vite loading Node.js package source code.](https://github.com/electron-vite/vite-plugin-electron-renderer/blob/2bb38a1dbd50b462d33cbc314bb5db71119b52cf/plugins/use-node.js/index.js#L91) | ||
## ๐จ Node.js ESM packages | ||
```js | ||
import { ipcRenderer } from 'electron' | ||
โ | ||
// Actually redirect via `resolve.alias` | ||
import { ipcRenderer } from 'vite-plugin-electron-renderer/plugins/use-node.js/electron-renderer.js' | ||
``` | ||
**e.g.** `node-fetch` `execa` `got` ... | ||
## ๐จ ESM packages | ||
In general, Node.js ESM packages only need to be converted if they are used in Electron-Renderer, but not in Electron-Main. | ||
**e.g.** `node-fetch` `execa` `got` ...others | ||
*้ๅธธ็๏ผๅชๆๅจ Electron-Renderer ไธญไฝฟ็จ็ๆ ๅตไธๆ้่ฆ่ฝฌๆข Node.js ESM ๆจกๅ๏ผ่ๅจ Electron-Main ไธญไฝฟ็จๅไธๅฟ ่ฝฌๆขใ* | ||
1. `npm i vite-plugin-esmodule -D` | ||
2. Configure in vite.config.ts | ||
1. Use [vite-plugin-esmodule](https://github.com/vite-plugin/vite-plugin-esmodule) to load ESM packages | ||
2. It is recommended to put the ESM packages in the `devDependencies` | ||
```ts | ||
import esmodule from 'vite-plugin-esmodule' | ||
export default { | ||
plugins: [ | ||
esmodule(['got', 'execa', 'node-fetch']), | ||
], | ||
} | ||
``` | ||
[๐ See electron-renderer.js](https://github.com/electron-vite/vite-plugin-electron-renderer/blob/main/plugins/use-node.js/electron-renderer.js) | ||
## How to work | ||
@@ -150,17 +132,12 @@ | ||
###### Config presets | ||
## Config presets | ||
1. Fist, the plugin will configuration something. | ||
*If you do not configure the following options, the plugin will modify their default values* | ||
If you do not configure the following options, the plugin will modify their default values | ||
* `base = './'` | ||
* `build.assetsDir = ''` -> *TODO: Automatic splicing `build.assetsDir`* | ||
* ~~`build.emptyOutDir = false`~~ | ||
* `build.cssCodeSplit = false` | ||
* `build.rollupOptions.output.format = 'cjs'` | ||
* `resolve.conditions = ['node']` | ||
* Always insert the `electron` module into `optimizeDeps.exclude` | ||
2. The plugin transform Electron and Node.js built-in modules to ESModule format in `vite serve` phase. | ||
3. Add Electron and Node.js built-in modules to Rollup `output.external` option in the `vite build` phase. | ||
- `base = './'` | ||
- `build.assetsDir = ''` -> *TODO: Support nested dir* | ||
- `build.emptyOutDir = false` | ||
- `build.cssCodeSplit = false` | ||
- `build.rollupOptions.output.format = 'cjs'` | ||
- `resolve.conditions = ['node']` | ||
- `optimizeDeps.exclude = ['electron']` - always |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
22883
371
139