vite-plugin-electron-renderer
Advanced tools
Comparing version 0.3.3 to 0.4.0
@@ -6,4 +6,12 @@ import { Plugin } from 'vite'; | ||
export interface Options { | ||
/** | ||
* Explicitly include/exclude some CJS modules | ||
* `modules` includes `dependencies` of package.json, Node.js's `builtinModules` and `electron` | ||
*/ | ||
resolve?: (modules: string[]) => typeof modules | undefined | ||
} | ||
export interface VitePluginElectronRenderer { | ||
(): Plugin[]; | ||
(options?: Options): Plugin[]; | ||
} |
250
index.js
@@ -0,4 +1,4 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const { builtinModules } = require('module'); | ||
const optimizer = require('vite-plugin-optimizer'); | ||
@@ -8,14 +8,130 @@ /** | ||
*/ | ||
module.exports = function () { | ||
module.exports = function renderer(options = {}) { | ||
const name = 'vite-plugin-electron-renderer'; | ||
const plugin = optimizer( | ||
builtinModulesExport(builtinModules.filter(e => !e.startsWith('_'))), | ||
{ dir: `.${name}` }, | ||
); | ||
plugin.name = name; | ||
const builtins = builtinModules.filter(e => !e.startsWith('_')).map(e => [e, `node:${e}`]).flat(); | ||
// dependencies of package.json | ||
const dependencies = []; | ||
let modules = []; | ||
const moduleCache = new Map(); | ||
/** | ||
* @type {import('vite').ResolvedConfig} | ||
*/ | ||
let config; | ||
return [ | ||
{ | ||
name: `${name}:config`, | ||
name: `${name}:node.js`, | ||
enforce: 'pre', | ||
configResolved(config) { | ||
// Resolve package.json dependencies | ||
const pkgId = path.join(config.root, 'package.json'); | ||
if (fs.existsSync(pkgId)) { | ||
const pkg = require(pkgId); | ||
// TODO: Nested package name | ||
dependencies.push(...Object.keys(pkg.dependencies || {})); | ||
} | ||
modules = builtins.concat(dependencies); | ||
if (options.resolve) { | ||
const tmp = options.resolve(modules); | ||
if (tmp) modules = tmp; | ||
} | ||
}, | ||
resolveId(source) { | ||
const id = source.replace('node:', ''); | ||
if (modules.includes(id)) return id; | ||
}, | ||
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 (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(); | ||
moduleCache.set(id, nodeModuleCodeSnippet); | ||
return nodeModuleCodeSnippet; | ||
} | ||
}, | ||
}, | ||
{ | ||
name: `${name}:serve`, | ||
apply: 'serve', | ||
// 🚧 Must be use config hook | ||
config(config) { | ||
// Vite ---- resolve.alias ---- | ||
if (!config.resolve) config.resolve = {}; | ||
// TODO: Compatible ESM module | ||
// If the package is ESM module, like node-fetch, execa | ||
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 = []; | ||
config.optimizeDeps.exclude.push('electron'); | ||
}, | ||
}, | ||
{ | ||
name: `${name}:build`, | ||
apply: 'build', | ||
config(config) { | ||
// make sure that Electron can be loaded into the local file using `loadFile` after packaging | ||
@@ -25,80 +141,76 @@ if (!config.base) config.base = './'; | ||
if (!config.build) config.build = {}; | ||
// TODO: Init `config.build.target` | ||
// ensure that static resources are loaded normally | ||
if (!config.build.assetsDir) config.build.assetsDir = ''; | ||
if (config.build.assetsDir === undefined) config.build.assetsDir = ''; | ||
// https://github.com/electron-vite/electron-vite-vue/issues/107 | ||
if (config.build.cssCodeSplit === undefined) config.build.cssCodeSplit = false; | ||
// Rollup ---- init ---- | ||
if (!config.build.rollupOptions) config.build.rollupOptions = {}; | ||
if (!config.build.rollupOptions.output) config.build.rollupOptions.output = {}; | ||
if (Array.isArray(config.build.rollupOptions.output)) { | ||
config.build.rollupOptions.output.forEach(output => { | ||
if (!output.format) { | ||
// the packaged Electron app should use "cjs" | ||
output.format = 'cjs'; | ||
// Rollup ---- external ---- | ||
let external = config.build.rollupOptions.external; | ||
const electronBuiltins = modules.concat('electron'); | ||
if ( | ||
Array.isArray(external) || | ||
typeof external === 'string' || | ||
external instanceof RegExp | ||
) { | ||
external = electronBuiltins.concat(external); | ||
} else if (typeof external === 'function') { | ||
const original = external; | ||
external = function (source, importer, isResolved) { | ||
if (electronBuiltins.includes(source)) { | ||
return true; | ||
} | ||
}); | ||
return original(source, importer, isResolved); | ||
}; | ||
} else { | ||
if (!config.build.rollupOptions.output.format) { | ||
// the packaged Electron app should use "cjs" | ||
config.build.rollupOptions.output.format = 'cjs'; | ||
} | ||
external = electronBuiltins; | ||
} | ||
// ---------------------------------------- | ||
// make builtin modules & electron external when rollup | ||
config.build.rollupOptions.external = external; | ||
if (!config.resolve) config.resolve = {}; | ||
if (!config.resolve.conditions) config.resolve.conditions = ['node']; | ||
if (!config.resolve.alias) config.resolve.alias = []; | ||
const electronjs = path.join(__dirname, 'modules/electron-renderer.js'); | ||
if (Array.isArray(config.resolve.alias)) { | ||
config.resolve.alias.push({ | ||
find: 'electron', | ||
replacement: electronjs, | ||
}); | ||
// Rollup ---- output.format ---- | ||
const output = config.build.rollupOptions.output; | ||
if (Array.isArray(output)) { | ||
for (const o of output) { | ||
if (o.format === undefined) o.format = 'cjs'; | ||
} | ||
} else { | ||
config.resolve.alias['electron'] = electronjs; | ||
// external modules such as `electron`, `fs` | ||
// they can only be loaded normally under CommonJs | ||
if (output.format === undefined) output.format = 'cjs'; | ||
} | ||
}, | ||
}, | ||
{ | ||
name: `${name}:polyfill-exports`, | ||
configResolved(_config) { | ||
config = _config; | ||
}, | ||
transformIndexHtml(html) { | ||
const output = config.build.rollupOptions.output; | ||
if (!output) return; | ||
// ---------------------------------------- | ||
const formats = ['cjs', 'commonjs']; | ||
if (!config.optimizeDeps) config.optimizeDeps = {}; | ||
if (!config.optimizeDeps.exclude) config.optimizeDeps.exclude = []; | ||
config.optimizeDeps.exclude.push('electron'); | ||
// https://github.com/electron-vite/vite-plugin-electron/issues/6 | ||
// https://github.com/electron-vite/vite-plugin-electron/commit/e6decf42164bc1e3801e27984322c41b9c2724b7#r75138942 | ||
if ( | ||
Array.isArray(output) | ||
// Once an `output.format` is CJS, it is considered as CommonJs | ||
? output.find(o => formats.includes(o.format)) | ||
: formats.includes(output.format) | ||
) { | ||
// fix(🐞): exports is not defined | ||
const polyfill = `<script>var exports = typeof module !== 'undefined' ? module.exports : {};</script>`; | ||
return html.replace(/(<\/[\s]*?head[\s]*?>)/, polyfill + '\n$1'); | ||
} | ||
}, | ||
}, | ||
plugin, | ||
]; | ||
}; | ||
/** | ||
* @typedef {Record<string, import('vite-plugin-optimizer').ResultDescription>} ExportCollected | ||
* @type {(modules: string[]) => ExportCollected} | ||
*/ | ||
function builtinModulesExport(modules) { | ||
return modules.map((moduleId) => { | ||
const nodeModule = require(moduleId) | ||
const requireModule = `const M = require("${moduleId}");` | ||
const exportDefault = `export default M;` | ||
const exportMembers = Object | ||
.keys(nodeModule) | ||
.map(attr => `export const ${attr} = M.${attr}`).join(';\n') + ';' | ||
const nodeModuleCode = ` | ||
${requireModule} | ||
${exportDefault} | ||
${exportMembers} | ||
` | ||
/** | ||
* @type {ExportCollected} | ||
*/ | ||
const collect = { | ||
// | ||
[moduleId]: { | ||
alias: { find: new RegExp(`^(node:)?${moduleId}$`) }, | ||
code: nodeModuleCode, | ||
}, | ||
}; | ||
return collect; | ||
}).reduce((memo, item) => Object.assign(memo, item), {}) | ||
} |
{ | ||
"name": "vite-plugin-electron-renderer", | ||
"version": "0.3.3", | ||
"description": "Use Electron and NodeJs API in Renderer-process", | ||
"version": "0.4.0", | ||
"description": "Support use Node.js API in Electron-Renderer", | ||
"main": "index.js", | ||
"repository": "https://github.com/caoxiemeihao/vite-plugins/tree/main/packages/electron-renderer", | ||
"readme": "https://github.com/caoxiemeihao/vite-plugins/tree/main/packages/electron-renderer#readme", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/electron-vite/vite-plugin-electron-renderer.git" | ||
}, | ||
"author": "草鞋没号 <308487730@qq.com>", | ||
"license": "MIT", | ||
"dependencies": { | ||
"vite-plugin-optimizer": "^1.3.2" | ||
}, | ||
"scripts": {}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"vite": "^2.x" | ||
"vite": "^2.9.9" | ||
}, | ||
@@ -16,0 +17,0 @@ "keywords": [ |
# vite-plugin-electron-renderer | ||
> 🚧 The package has deprecated. Please use [vite-plugin-electron](https://www.npmjs.com/package/vite-plugin-electron) | ||
Support use Node.js API in Electron-Renderer | ||
```js | ||
import electron from 'vite-plugin-electron/renderer' | ||
``` | ||
--- | ||
[![NPM version](https://img.shields.io/npm/v/vite-plugin-electron-renderer.svg?style=flat)](https://npmjs.org/package/vite-plugin-electron-renderer) | ||
[![NPM Downloads](https://img.shields.io/npm/dm/vite-plugin-electron-renderer.svg?style=flat)](https://npmjs.org/package/vite-plugin-electron-renderer) | ||
Use Electron and Node.js API in Renderer-process | ||
English | [简体中文](https://github.com/caoxiemeihao/vite-plugins/blob/main/packages/electron-renderer/README.zh-CN.md) | ||
**Example 👉 [electron-vite-vue](https://github.com/caoxiemeihao/electron-vite-vue)** | ||
![GitHub stars](https://img.shields.io/github/stars/caoxiemeihao/electron-vite-vue?color=fa6470) | ||
## Install | ||
```bash | ||
```sh | ||
npm i vite-plugin-electron-renderer -D | ||
@@ -29,16 +16,15 @@ ``` | ||
**vite.config.ts** | ||
vite.config.ts | ||
```ts | ||
import { defineConfig } from 'vite' | ||
import electron from 'vite-plugin-electron-renderer' | ||
```js | ||
import renderer from 'vite-plugin-electron-renderer' | ||
export default defineConfig({ | ||
export default { | ||
plugins: [ | ||
electron(), | ||
renderer(/* options */), | ||
], | ||
}) | ||
} | ||
``` | ||
**renderer.js** | ||
renderer.js | ||
@@ -53,34 +39,44 @@ ```ts | ||
## How to work | ||
## API | ||
- Using Electron API in Renderer-process | ||
`renderer(options: Options)` | ||
```js | ||
import { ipcRenderer } from 'electron' | ||
```ts | ||
export interface Options { | ||
/** | ||
* Explicitly include/exclude some CJS modules | ||
* `modules` includes `dependencies` of package.json, Node.js's `builtinModules` and `electron` | ||
*/ | ||
resolve?: (modules: string[]) => typeof modules | undefined | ||
} | ||
``` | ||
Actually redirect to "[node_modules/vite-plugin-electron-renderer/modules/electron-renderer.js](modules/electron-renderer.js)" by `resolve.alias` | ||
## How to work | ||
- Using Node.js API in Renderer-process | ||
Using Electron API in Electron-Renderer | ||
```js | ||
import { readFile } from 'fs' | ||
import { ipcRenderer } from 'electron' | ||
↓ | ||
// Actually will redirect by `resolve.alias` | ||
import { ipcRenderer } from 'vite-plugin-electron-renderer/electron-renderer.js' | ||
``` | ||
All Node.js API will be built into the `node_modules/.vite-plugin-electron-renderer` directory by [vite-plugin-optimizer](https://www.npmjs.com/package/vite-plugin-optimizer) | ||
[Using Node.js API and package in Electron-Renderer 👉](https://github.com/electron-vite/vite-plugin-electron-renderer/blob/4a2620d9ff9b3696cf55c1c5d4f2acdcf1ff806a/index.js#L37) | ||
#### Config presets | ||
## 🚧 Some additional instructions | ||
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.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. | ||
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. | ||
3. Add Electron and Node.js built-in modules to Rollup `output.external` option in the `vite build` phase. |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
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
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
12896
0
7
237
0
81
4
2
- Removedvite-plugin-optimizer@^1.3.2
- Removedvite-plugin-optimizer@1.4.3(transitive)