修改前端架构到Electron ,增加llm_api页面,增加chat SSE渲染,修改若安按钮,卡片名称修改等小功能,增加agent-core,增加SQlite,增加llm UDS Pipe websocke
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022, Alex Wei
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
<p align="center">
|
||||
<img src="https://alex8088.github.io/assets/electron-vite.svg" width="150px" height="150px">
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
<h1>electron-vite</h1>
|
||||
</div>
|
||||
<p align="center">Next generation Electron build tooling based on Vite</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/npm/v/electron-vite?color=6988e6&label=version">
|
||||
<img src="https://img.shields.io/github/license/alex8088/electron-vite?color=blue" alt="license" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://electron-vite.org">Documentation</a> |
|
||||
<a href="https://electron-vite.org/guide">Getting Started</a> |
|
||||
<a href="https://github.com/alex8088/quick-start/tree/master/packages/create-electron">create-electron</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://cn.electron-vite.org">中文文档</a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
|
||||
## Features
|
||||
|
||||
- ⚡️ [Vite](https://vitejs.dev) powered and use the same way.
|
||||
- 🛠 Pre-configured for Electron, don't worry about configuration.
|
||||
- 💡 Optimize asset handling (Node.js addons, WebAssembly, Worker Thread, etc).
|
||||
- 🚀 Fast HMR for renderer processes.
|
||||
- 🔥 Hot reloading for main process and preload scripts.
|
||||
- 🔌 Easy to debug in IDEs like VSCode or WebStorm.
|
||||
- 🔒 Compile to v8 bytecode to protect source code.
|
||||
- 🏷️ Support for TypeScript decorators.
|
||||
- 📦 Out-of-the-box support for TypeScript, Vue, React, Svelte, SolidJS and more.
|
||||
|
||||
## Usage
|
||||
|
||||
### Install
|
||||
|
||||
```sh
|
||||
npm i electron-vite -D
|
||||
```
|
||||
|
||||
### Development & Build
|
||||
|
||||
In a project where `electron-vite` is installed, you can use `electron-vite` binary directly with `npx electron-vite` or add the npm scripts to your `package.json` file like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start": "electron-vite preview",
|
||||
"dev": "electron-vite dev",
|
||||
"prebuild": "electron-vite build"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
When running `electron-vite` from the command line, electron-vite will automatically try to resolve a config file named `electron.vite.config.js` inside project root. The most basic config file looks like this:
|
||||
|
||||
```js
|
||||
// electron.vite.config.js
|
||||
export default {
|
||||
main: {
|
||||
// vite config options
|
||||
},
|
||||
preload: {
|
||||
// vite config options
|
||||
},
|
||||
renderer: {
|
||||
// vite config options
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Getting Started
|
||||
|
||||
Clone the [electron-vite-boilerplate](https://github.com/alex8088/electron-vite-boilerplate) or use the [create-electron](https://github.com/alex8088/quick-start/tree/master/packages/create-electron) tool to scaffold your project.
|
||||
|
||||
```bash
|
||||
npm create @quick-start/electron
|
||||
```
|
||||
|
||||
Currently supported template presets include:
|
||||
|
||||
| JavaScript | TypeScript |
|
||||
| :--------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: |
|
||||
| [vanilla](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/vanilla) | [vanilla-ts](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/vanilla-ts) |
|
||||
| [vue](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/vue) | [vue-ts](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/vue-ts) |
|
||||
| [react](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/react) | [react-ts](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/react-ts) |
|
||||
| [svelte](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/svelte) | [svelte-ts](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/svelte-ts) |
|
||||
| [solid](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/solid) | [solid-ts](https://github.com/alex8088/quick-start/tree/master/packages/create-electron/playground/solid-ts) |
|
||||
|
||||
## Contribution
|
||||
|
||||
See [Contributing Guide](CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
[MIT](./LICENSE) © alex.wei
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
const vm = require('vm')
|
||||
const v8 = require('v8')
|
||||
const wrap = require('module').wrap
|
||||
|
||||
v8.setFlagsFromString('--no-lazy')
|
||||
v8.setFlagsFromString('--no-flush-bytecode')
|
||||
|
||||
let code = ''
|
||||
|
||||
process.stdin.setEncoding('utf-8')
|
||||
|
||||
process.stdin.on('readable', () => {
|
||||
const data = process.stdin.read()
|
||||
if (data !== null) {
|
||||
code += data
|
||||
}
|
||||
})
|
||||
|
||||
process.stdin.on('end', () => {
|
||||
try {
|
||||
if (typeof code !== 'string') {
|
||||
throw new Error(`javascript code must be string. ${typeof code} was given.`)
|
||||
}
|
||||
|
||||
const script = new vm.Script(wrap(code), { produceCachedData: true })
|
||||
const bytecodeBuffer = script.createCachedData()
|
||||
|
||||
process.stdout.write(bytecodeBuffer)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
})
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const debugIndex = process.argv.findIndex(arg => /^(?:-d|--debug)$/.test(arg))
|
||||
const filterIndex = process.argv.findIndex(arg => /^(?:-f|--filter)$/.test(arg))
|
||||
|
||||
if (debugIndex > 0) {
|
||||
let value = process.argv[debugIndex + 1]
|
||||
if (!value || value.startsWith('-')) {
|
||||
value = 'vite:*'
|
||||
} else {
|
||||
value = value
|
||||
.split(',')
|
||||
.map(v => `vite:${v}`)
|
||||
.join(',')
|
||||
}
|
||||
process.env.DEBUG = `${process.env.DEBUG ? process.env.DEBUG + ',' : ''}${value}`
|
||||
|
||||
if (filterIndex > 0) {
|
||||
const filter = process.argv[filterIndex + 1]
|
||||
if (filter && !filter.startsWith('-')) {
|
||||
process.env.VITE_DEBUG_FILTER = filter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function run() {
|
||||
import('../dist/cli.mjs')
|
||||
}
|
||||
|
||||
run()
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
import colors from 'picocolors';
|
||||
import { createLogger } from 'vite';
|
||||
import { s as startElectron } from './lib-BmEkZIgk.mjs';
|
||||
import { build } from './lib-D1n7TA6K.mjs';
|
||||
import 'node:path';
|
||||
import 'node:fs';
|
||||
import 'node:url';
|
||||
import 'node:module';
|
||||
import 'esbuild';
|
||||
import 'node:child_process';
|
||||
import 'node:crypto';
|
||||
import 'node:fs/promises';
|
||||
import 'magic-string';
|
||||
|
||||
async function preview(inlineConfig = {}, options) {
|
||||
if (!options.skipBuild) {
|
||||
await build(inlineConfig);
|
||||
}
|
||||
const logger = createLogger(inlineConfig.logLevel);
|
||||
startElectron(inlineConfig.root);
|
||||
logger.info(colors.green(`\nstart electron app...\n`));
|
||||
}
|
||||
|
||||
export { preview };
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
'use strict';
|
||||
|
||||
var vite = require('vite');
|
||||
var colors = require('picocolors');
|
||||
var config = require('./lib-CMs-qhOt.cjs');
|
||||
require('node:path');
|
||||
require('node:fs');
|
||||
require('node:url');
|
||||
require('node:module');
|
||||
require('esbuild');
|
||||
require('node:child_process');
|
||||
require('node:crypto');
|
||||
require('node:fs/promises');
|
||||
require('magic-string');
|
||||
|
||||
async function createServer(inlineConfig = {}, options) {
|
||||
process.env.NODE_ENV_ELECTRON_VITE = 'development';
|
||||
const config$1 = await config.resolveConfig(inlineConfig, 'serve', 'development');
|
||||
if (config$1.config) {
|
||||
const logger = vite.createLogger(inlineConfig.logLevel);
|
||||
let server;
|
||||
let ps;
|
||||
const errorHook = (e) => {
|
||||
logger.error(`${colors.bgRed(colors.white(' ERROR '))} ${colors.red(e.message)}`);
|
||||
};
|
||||
const mainViteConfig = config$1.config?.main;
|
||||
if (mainViteConfig && !options.rendererOnly) {
|
||||
const watchHook = () => {
|
||||
logger.info(colors.green(`\nrebuild the electron main process successfully`));
|
||||
if (ps) {
|
||||
logger.info(colors.cyan(`\n waiting for electron to exit...`));
|
||||
ps.removeAllListeners();
|
||||
ps.kill();
|
||||
ps = config.startElectron(inlineConfig.root);
|
||||
logger.info(colors.green(`\nrestart electron app...`));
|
||||
}
|
||||
};
|
||||
await doBuild(mainViteConfig, watchHook, errorHook);
|
||||
logger.info(colors.green(`\nbuild the electron main process successfully`));
|
||||
}
|
||||
const preloadViteConfig = config$1.config?.preload;
|
||||
if (preloadViteConfig && !options.rendererOnly) {
|
||||
logger.info(colors.gray(`\n-----\n`));
|
||||
const watchHook = () => {
|
||||
logger.info(colors.green(`\nrebuild the electron preload files successfully`));
|
||||
if (server) {
|
||||
logger.info(colors.cyan(`\n trigger renderer reload`));
|
||||
server.ws.send({ type: 'full-reload' });
|
||||
}
|
||||
};
|
||||
await doBuild(preloadViteConfig, watchHook, errorHook);
|
||||
logger.info(colors.green(`\nbuild the electron preload files successfully`));
|
||||
}
|
||||
if (options.rendererOnly) {
|
||||
logger.warn(`\n${colors.yellow(colors.bold('warn'))}:${colors.yellow(' you have skipped the main process and preload scripts building')}`);
|
||||
}
|
||||
const rendererViteConfig = config$1.config?.renderer;
|
||||
if (rendererViteConfig) {
|
||||
logger.info(colors.gray(`\n-----\n`));
|
||||
server = await vite.createServer(rendererViteConfig);
|
||||
if (!server.httpServer) {
|
||||
throw new Error('HTTP server not available');
|
||||
}
|
||||
await server.listen();
|
||||
const conf = server.config.server;
|
||||
const protocol = conf.https ? 'https:' : 'http:';
|
||||
const host = config.resolveHostname(conf.host);
|
||||
const port = conf.port;
|
||||
process.env.ELECTRON_RENDERER_URL = `${protocol}//${host}:${port}`;
|
||||
const slogger = server.config.logger;
|
||||
slogger.info(colors.green(`dev server running for the electron renderer process at:\n`), {
|
||||
clear: !slogger.hasWarned && !options.rendererOnly
|
||||
});
|
||||
server.printUrls();
|
||||
}
|
||||
ps = config.startElectron(inlineConfig.root);
|
||||
logger.info(colors.green(`\nstart electron app...\n`));
|
||||
}
|
||||
}
|
||||
async function doBuild(config, watchHook, errorHook) {
|
||||
return new Promise(resolve => {
|
||||
if (config.build?.watch) {
|
||||
let firstBundle = true;
|
||||
const closeBundle = () => {
|
||||
if (firstBundle) {
|
||||
firstBundle = false;
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
watchHook();
|
||||
}
|
||||
};
|
||||
config = vite.mergeConfig(config, {
|
||||
plugins: [
|
||||
{
|
||||
name: 'vite:electron-watcher',
|
||||
closeBundle
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
vite.build(config)
|
||||
.then(() => {
|
||||
if (!config.build?.watch) {
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
.catch(e => errorHook(e));
|
||||
});
|
||||
}
|
||||
|
||||
exports.createServer = createServer;
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
|
||||
var vite = require('vite');
|
||||
var config = require('./lib-CMs-qhOt.cjs');
|
||||
require('node:path');
|
||||
require('node:fs');
|
||||
require('node:url');
|
||||
require('node:module');
|
||||
require('picocolors');
|
||||
require('esbuild');
|
||||
require('node:child_process');
|
||||
require('node:crypto');
|
||||
require('node:fs/promises');
|
||||
require('magic-string');
|
||||
|
||||
/**
|
||||
* Bundles the electron app for production.
|
||||
*/
|
||||
async function build(inlineConfig = {}) {
|
||||
process.env.NODE_ENV_ELECTRON_VITE = 'production';
|
||||
const config$1 = await config.resolveConfig(inlineConfig, 'build', 'production');
|
||||
if (config$1.config) {
|
||||
const mainViteConfig = config$1.config?.main;
|
||||
if (mainViteConfig) {
|
||||
if (mainViteConfig.build?.watch) {
|
||||
mainViteConfig.build.watch = null;
|
||||
}
|
||||
await vite.build(mainViteConfig);
|
||||
}
|
||||
const preloadViteConfig = config$1.config?.preload;
|
||||
if (preloadViteConfig) {
|
||||
if (preloadViteConfig.build?.watch) {
|
||||
preloadViteConfig.build.watch = null;
|
||||
}
|
||||
await vite.build(preloadViteConfig);
|
||||
}
|
||||
const rendererViteConfig = config$1.config?.renderer;
|
||||
if (rendererViteConfig) {
|
||||
if (rendererViteConfig.build?.watch) {
|
||||
rendererViteConfig.build.watch = null;
|
||||
}
|
||||
await vite.build(rendererViteConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.build = build;
|
||||
+1184
File diff suppressed because it is too large
Load Diff
+1195
File diff suppressed because it is too large
Load Diff
+45
@@ -0,0 +1,45 @@
|
||||
import { build as build$1 } from 'vite';
|
||||
import { r as resolveConfig } from './lib-BmEkZIgk.mjs';
|
||||
import 'node:path';
|
||||
import 'node:fs';
|
||||
import 'node:url';
|
||||
import 'node:module';
|
||||
import 'picocolors';
|
||||
import 'esbuild';
|
||||
import 'node:child_process';
|
||||
import 'node:crypto';
|
||||
import 'node:fs/promises';
|
||||
import 'magic-string';
|
||||
|
||||
/**
|
||||
* Bundles the electron app for production.
|
||||
*/
|
||||
async function build(inlineConfig = {}) {
|
||||
process.env.NODE_ENV_ELECTRON_VITE = 'production';
|
||||
const config = await resolveConfig(inlineConfig, 'build', 'production');
|
||||
if (config.config) {
|
||||
const mainViteConfig = config.config?.main;
|
||||
if (mainViteConfig) {
|
||||
if (mainViteConfig.build?.watch) {
|
||||
mainViteConfig.build.watch = null;
|
||||
}
|
||||
await build$1(mainViteConfig);
|
||||
}
|
||||
const preloadViteConfig = config.config?.preload;
|
||||
if (preloadViteConfig) {
|
||||
if (preloadViteConfig.build?.watch) {
|
||||
preloadViteConfig.build.watch = null;
|
||||
}
|
||||
await build$1(preloadViteConfig);
|
||||
}
|
||||
const rendererViteConfig = config.config?.renderer;
|
||||
if (rendererViteConfig) {
|
||||
if (rendererViteConfig.build?.watch) {
|
||||
rendererViteConfig.build.watch = null;
|
||||
}
|
||||
await build$1(rendererViteConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { build };
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
import { createLogger, createServer as createServer$1, mergeConfig, build } from 'vite';
|
||||
import colors from 'picocolors';
|
||||
import { r as resolveConfig, c as resolveHostname, s as startElectron } from './lib-BmEkZIgk.mjs';
|
||||
import 'node:path';
|
||||
import 'node:fs';
|
||||
import 'node:url';
|
||||
import 'node:module';
|
||||
import 'esbuild';
|
||||
import 'node:child_process';
|
||||
import 'node:crypto';
|
||||
import 'node:fs/promises';
|
||||
import 'magic-string';
|
||||
|
||||
async function createServer(inlineConfig = {}, options) {
|
||||
process.env.NODE_ENV_ELECTRON_VITE = 'development';
|
||||
const config = await resolveConfig(inlineConfig, 'serve', 'development');
|
||||
if (config.config) {
|
||||
const logger = createLogger(inlineConfig.logLevel);
|
||||
let server;
|
||||
let ps;
|
||||
const errorHook = (e) => {
|
||||
logger.error(`${colors.bgRed(colors.white(' ERROR '))} ${colors.red(e.message)}`);
|
||||
};
|
||||
const mainViteConfig = config.config?.main;
|
||||
if (mainViteConfig && !options.rendererOnly) {
|
||||
const watchHook = () => {
|
||||
logger.info(colors.green(`\nrebuild the electron main process successfully`));
|
||||
if (ps) {
|
||||
logger.info(colors.cyan(`\n waiting for electron to exit...`));
|
||||
ps.removeAllListeners();
|
||||
ps.kill();
|
||||
ps = startElectron(inlineConfig.root);
|
||||
logger.info(colors.green(`\nrestart electron app...`));
|
||||
}
|
||||
};
|
||||
await doBuild(mainViteConfig, watchHook, errorHook);
|
||||
logger.info(colors.green(`\nbuild the electron main process successfully`));
|
||||
}
|
||||
const preloadViteConfig = config.config?.preload;
|
||||
if (preloadViteConfig && !options.rendererOnly) {
|
||||
logger.info(colors.gray(`\n-----\n`));
|
||||
const watchHook = () => {
|
||||
logger.info(colors.green(`\nrebuild the electron preload files successfully`));
|
||||
if (server) {
|
||||
logger.info(colors.cyan(`\n trigger renderer reload`));
|
||||
server.ws.send({ type: 'full-reload' });
|
||||
}
|
||||
};
|
||||
await doBuild(preloadViteConfig, watchHook, errorHook);
|
||||
logger.info(colors.green(`\nbuild the electron preload files successfully`));
|
||||
}
|
||||
if (options.rendererOnly) {
|
||||
logger.warn(`\n${colors.yellow(colors.bold('warn'))}:${colors.yellow(' you have skipped the main process and preload scripts building')}`);
|
||||
}
|
||||
const rendererViteConfig = config.config?.renderer;
|
||||
if (rendererViteConfig) {
|
||||
logger.info(colors.gray(`\n-----\n`));
|
||||
server = await createServer$1(rendererViteConfig);
|
||||
if (!server.httpServer) {
|
||||
throw new Error('HTTP server not available');
|
||||
}
|
||||
await server.listen();
|
||||
const conf = server.config.server;
|
||||
const protocol = conf.https ? 'https:' : 'http:';
|
||||
const host = resolveHostname(conf.host);
|
||||
const port = conf.port;
|
||||
process.env.ELECTRON_RENDERER_URL = `${protocol}//${host}:${port}`;
|
||||
const slogger = server.config.logger;
|
||||
slogger.info(colors.green(`dev server running for the electron renderer process at:\n`), {
|
||||
clear: !slogger.hasWarned && !options.rendererOnly
|
||||
});
|
||||
server.printUrls();
|
||||
}
|
||||
ps = startElectron(inlineConfig.root);
|
||||
logger.info(colors.green(`\nstart electron app...\n`));
|
||||
}
|
||||
}
|
||||
async function doBuild(config, watchHook, errorHook) {
|
||||
return new Promise(resolve => {
|
||||
if (config.build?.watch) {
|
||||
let firstBundle = true;
|
||||
const closeBundle = () => {
|
||||
if (firstBundle) {
|
||||
firstBundle = false;
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
watchHook();
|
||||
}
|
||||
};
|
||||
config = mergeConfig(config, {
|
||||
plugins: [
|
||||
{
|
||||
name: 'vite:electron-watcher',
|
||||
closeBundle
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
build(config)
|
||||
.then(() => {
|
||||
if (!config.build?.watch) {
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
.catch(e => errorHook(e));
|
||||
});
|
||||
}
|
||||
|
||||
export { createServer };
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
var colors = require('picocolors');
|
||||
var vite = require('vite');
|
||||
var config = require('./lib-CMs-qhOt.cjs');
|
||||
var build = require('./lib-BVIIv3aq.cjs');
|
||||
require('node:path');
|
||||
require('node:fs');
|
||||
require('node:url');
|
||||
require('node:module');
|
||||
require('esbuild');
|
||||
require('node:child_process');
|
||||
require('node:crypto');
|
||||
require('node:fs/promises');
|
||||
require('magic-string');
|
||||
|
||||
async function preview(inlineConfig = {}, options) {
|
||||
if (!options.skipBuild) {
|
||||
await build.build(inlineConfig);
|
||||
}
|
||||
const logger = vite.createLogger(inlineConfig.logLevel);
|
||||
config.startElectron(inlineConfig.root);
|
||||
logger.info(colors.green(`\nstart electron app...\n`));
|
||||
}
|
||||
|
||||
exports.preview = preview;
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
'use strict';
|
||||
|
||||
var cac = require('cac');
|
||||
var colors = require('picocolors');
|
||||
var vite = require('vite');
|
||||
|
||||
var version = "2.3.0";
|
||||
|
||||
const cli = cac.cac('electron-vite');
|
||||
function createInlineConfig(root, options) {
|
||||
return {
|
||||
root,
|
||||
mode: options.mode,
|
||||
configFile: options.config,
|
||||
logLevel: options.logLevel,
|
||||
clearScreen: options.clearScreen,
|
||||
ignoreConfigWarning: options.ignoreConfigWarning,
|
||||
build: {
|
||||
sourcemap: options.sourcemap,
|
||||
outDir: options.outDir,
|
||||
...(options.w || options.watch ? { watch: {} } : null)
|
||||
}
|
||||
};
|
||||
}
|
||||
cli
|
||||
.option('-c, --config <file>', `[string] use specified config file`)
|
||||
.option('-l, --logLevel <level>', `[string] info | warn | error | silent`)
|
||||
.option('--clearScreen', `[boolean] allow/disable clear screen when logging`)
|
||||
.option('-d, --debug [feat]', `[string | boolean] show debug logs`)
|
||||
.option('-f, --filter <filter>', `[string] filter debug logs`)
|
||||
.option('-m, --mode <mode>', `[string] set env mode`)
|
||||
.option('--ignoreConfigWarning', `[boolean] ignore config warning`)
|
||||
.option('--sourcemap', `[boolean] output source maps for debug (default: false)`)
|
||||
.option('--outDir <dir>', `[string] output directory (default: out)`)
|
||||
.option('--entry <file>', `[string] specify electron entry file`);
|
||||
// dev
|
||||
cli
|
||||
.command('[root]', 'start dev server and electron app')
|
||||
.alias('serve')
|
||||
.alias('dev')
|
||||
.option('-w, --watch', `[boolean] rebuilds when main process or preload script modules have changed on disk`)
|
||||
.option('--inspect [port]', `[boolean | number] enable V8 inspector on the specified port`)
|
||||
.option('--inspectBrk [port]', `[boolean | number] enable V8 inspector on the specified port`)
|
||||
.option('--remoteDebuggingPort <port>', `[string] port for remote debugging`)
|
||||
.option('--noSandbox', `[boolean] forces renderer process to run un-sandboxed`)
|
||||
.option('--rendererOnly', `[boolean] only dev server for the renderer`)
|
||||
.action(async (root, options) => {
|
||||
if (options.remoteDebuggingPort) {
|
||||
process.env.REMOTE_DEBUGGING_PORT = options.remoteDebuggingPort;
|
||||
}
|
||||
if (options.inspect) {
|
||||
process.env.V8_INSPECTOR_PORT = typeof options.inspect === 'number' ? `${options.inspect}` : '5858';
|
||||
}
|
||||
if (options.inspectBrk) {
|
||||
process.env.V8_INSPECTOR_BRK_PORT = typeof options.inspectBrk === 'number' ? `${options.inspectBrk}` : '5858';
|
||||
}
|
||||
if (options.noSandbox) {
|
||||
process.env.NO_SANDBOX = '1';
|
||||
}
|
||||
if (options['--']) {
|
||||
process.env.ELECTRON_CLI_ARGS = JSON.stringify(options['--']);
|
||||
}
|
||||
if (options.entry) {
|
||||
process.env.ELECTRON_ENTRY = options.entry;
|
||||
}
|
||||
const { createServer } = await Promise.resolve().then(function () { return require('./chunks/lib-BSnPjVZB.cjs'); });
|
||||
const inlineConfig = createInlineConfig(root, options);
|
||||
try {
|
||||
await createServer(inlineConfig, { rendererOnly: options.rendererOnly });
|
||||
}
|
||||
catch (e) {
|
||||
const error = e;
|
||||
vite.createLogger(options.logLevel).error(colors.red(`error during start dev server and electron app:\n${error.stack}`), { error });
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
// build
|
||||
cli.command('build [root]', 'build for production').action(async (root, options) => {
|
||||
const { build } = await Promise.resolve().then(function () { return require('./chunks/lib-BVIIv3aq.cjs'); });
|
||||
const inlineConfig = createInlineConfig(root, options);
|
||||
if (options.entry) {
|
||||
process.env.ELECTRON_ENTRY = options.entry;
|
||||
}
|
||||
try {
|
||||
await build(inlineConfig);
|
||||
}
|
||||
catch (e) {
|
||||
const error = e;
|
||||
vite.createLogger(options.logLevel).error(colors.red(`error during build:\n${error.stack}`), { error });
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
// preview
|
||||
cli
|
||||
.command('preview [root]', 'start electron app to preview production build')
|
||||
.option('--noSandbox', `[boolean] forces renderer process to run un-sandboxed`)
|
||||
.option('--skipBuild', `[boolean] skip build`)
|
||||
.action(async (root, options) => {
|
||||
const { preview } = await Promise.resolve().then(function () { return require('./chunks/lib-yyd5PWBM.cjs'); });
|
||||
const inlineConfig = createInlineConfig(root, options);
|
||||
if (options.noSandbox) {
|
||||
process.env.NO_SANDBOX = '1';
|
||||
}
|
||||
if (options.entry) {
|
||||
process.env.ELECTRON_ENTRY = options.entry;
|
||||
}
|
||||
if (options['--']) {
|
||||
process.env.ELECTRON_CLI_ARGS = JSON.stringify(options['--']);
|
||||
}
|
||||
try {
|
||||
await preview(inlineConfig, { skipBuild: options.skipBuild });
|
||||
}
|
||||
catch (e) {
|
||||
const error = e;
|
||||
vite.createLogger(options.logLevel).error(colors.red(`error during preview electron app:\n${error.stack}`), { error });
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
cli.help();
|
||||
cli.version(version);
|
||||
cli.parse();
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
import { cac } from 'cac';
|
||||
import colors from 'picocolors';
|
||||
import { createLogger } from 'vite';
|
||||
|
||||
var version = "2.3.0";
|
||||
|
||||
const cli = cac('electron-vite');
|
||||
function createInlineConfig(root, options) {
|
||||
return {
|
||||
root,
|
||||
mode: options.mode,
|
||||
configFile: options.config,
|
||||
logLevel: options.logLevel,
|
||||
clearScreen: options.clearScreen,
|
||||
ignoreConfigWarning: options.ignoreConfigWarning,
|
||||
build: {
|
||||
sourcemap: options.sourcemap,
|
||||
outDir: options.outDir,
|
||||
...(options.w || options.watch ? { watch: {} } : null)
|
||||
}
|
||||
};
|
||||
}
|
||||
cli
|
||||
.option('-c, --config <file>', `[string] use specified config file`)
|
||||
.option('-l, --logLevel <level>', `[string] info | warn | error | silent`)
|
||||
.option('--clearScreen', `[boolean] allow/disable clear screen when logging`)
|
||||
.option('-d, --debug [feat]', `[string | boolean] show debug logs`)
|
||||
.option('-f, --filter <filter>', `[string] filter debug logs`)
|
||||
.option('-m, --mode <mode>', `[string] set env mode`)
|
||||
.option('--ignoreConfigWarning', `[boolean] ignore config warning`)
|
||||
.option('--sourcemap', `[boolean] output source maps for debug (default: false)`)
|
||||
.option('--outDir <dir>', `[string] output directory (default: out)`)
|
||||
.option('--entry <file>', `[string] specify electron entry file`);
|
||||
// dev
|
||||
cli
|
||||
.command('[root]', 'start dev server and electron app')
|
||||
.alias('serve')
|
||||
.alias('dev')
|
||||
.option('-w, --watch', `[boolean] rebuilds when main process or preload script modules have changed on disk`)
|
||||
.option('--inspect [port]', `[boolean | number] enable V8 inspector on the specified port`)
|
||||
.option('--inspectBrk [port]', `[boolean | number] enable V8 inspector on the specified port`)
|
||||
.option('--remoteDebuggingPort <port>', `[string] port for remote debugging`)
|
||||
.option('--noSandbox', `[boolean] forces renderer process to run un-sandboxed`)
|
||||
.option('--rendererOnly', `[boolean] only dev server for the renderer`)
|
||||
.action(async (root, options) => {
|
||||
if (options.remoteDebuggingPort) {
|
||||
process.env.REMOTE_DEBUGGING_PORT = options.remoteDebuggingPort;
|
||||
}
|
||||
if (options.inspect) {
|
||||
process.env.V8_INSPECTOR_PORT = typeof options.inspect === 'number' ? `${options.inspect}` : '5858';
|
||||
}
|
||||
if (options.inspectBrk) {
|
||||
process.env.V8_INSPECTOR_BRK_PORT = typeof options.inspectBrk === 'number' ? `${options.inspectBrk}` : '5858';
|
||||
}
|
||||
if (options.noSandbox) {
|
||||
process.env.NO_SANDBOX = '1';
|
||||
}
|
||||
if (options['--']) {
|
||||
process.env.ELECTRON_CLI_ARGS = JSON.stringify(options['--']);
|
||||
}
|
||||
if (options.entry) {
|
||||
process.env.ELECTRON_ENTRY = options.entry;
|
||||
}
|
||||
const { createServer } = await import('./chunks/lib-t2ExBjL5.mjs');
|
||||
const inlineConfig = createInlineConfig(root, options);
|
||||
try {
|
||||
await createServer(inlineConfig, { rendererOnly: options.rendererOnly });
|
||||
}
|
||||
catch (e) {
|
||||
const error = e;
|
||||
createLogger(options.logLevel).error(colors.red(`error during start dev server and electron app:\n${error.stack}`), { error });
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
// build
|
||||
cli.command('build [root]', 'build for production').action(async (root, options) => {
|
||||
const { build } = await import('./chunks/lib-D1n7TA6K.mjs');
|
||||
const inlineConfig = createInlineConfig(root, options);
|
||||
if (options.entry) {
|
||||
process.env.ELECTRON_ENTRY = options.entry;
|
||||
}
|
||||
try {
|
||||
await build(inlineConfig);
|
||||
}
|
||||
catch (e) {
|
||||
const error = e;
|
||||
createLogger(options.logLevel).error(colors.red(`error during build:\n${error.stack}`), { error });
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
// preview
|
||||
cli
|
||||
.command('preview [root]', 'start electron app to preview production build')
|
||||
.option('--noSandbox', `[boolean] forces renderer process to run un-sandboxed`)
|
||||
.option('--skipBuild', `[boolean] skip build`)
|
||||
.action(async (root, options) => {
|
||||
const { preview } = await import('./chunks/lib-AgEz08--.mjs');
|
||||
const inlineConfig = createInlineConfig(root, options);
|
||||
if (options.noSandbox) {
|
||||
process.env.NO_SANDBOX = '1';
|
||||
}
|
||||
if (options.entry) {
|
||||
process.env.ELECTRON_ENTRY = options.entry;
|
||||
}
|
||||
if (options['--']) {
|
||||
process.env.ELECTRON_CLI_ARGS = JSON.stringify(options['--']);
|
||||
}
|
||||
try {
|
||||
await preview(inlineConfig, { skipBuild: options.skipBuild });
|
||||
}
|
||||
catch (e) {
|
||||
const error = e;
|
||||
createLogger(options.logLevel).error(colors.red(`error during preview electron app:\n${error.stack}`), { error });
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
cli.help();
|
||||
cli.version(version);
|
||||
cli.parse();
|
||||
+513
@@ -0,0 +1,513 @@
|
||||
'use strict';
|
||||
|
||||
var vite = require('vite');
|
||||
var config = require('./chunks/lib-CMs-qhOt.cjs');
|
||||
var server = require('./chunks/lib-BSnPjVZB.cjs');
|
||||
var build = require('./chunks/lib-BVIIv3aq.cjs');
|
||||
var preview = require('./chunks/lib-yyd5PWBM.cjs');
|
||||
var path = require('node:path');
|
||||
var fs = require('node:fs');
|
||||
var node_child_process = require('node:child_process');
|
||||
var node_module = require('node:module');
|
||||
var colors = require('picocolors');
|
||||
var babel = require('@babel/core');
|
||||
var MagicString = require('magic-string');
|
||||
require('node:url');
|
||||
require('esbuild');
|
||||
require('node:crypto');
|
||||
require('node:fs/promises');
|
||||
|
||||
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
||||
function _interopNamespaceDefault(e) {
|
||||
var n = Object.create(null);
|
||||
if (e) {
|
||||
Object.keys(e).forEach(function (k) {
|
||||
if (k !== 'default') {
|
||||
var d = Object.getOwnPropertyDescriptor(e, k);
|
||||
Object.defineProperty(n, k, d.get ? d : {
|
||||
enumerable: true,
|
||||
get: function () { return e[k]; }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
n.default = e;
|
||||
return Object.freeze(n);
|
||||
}
|
||||
|
||||
var babel__namespace = /*#__PURE__*/_interopNamespaceDefault(babel);
|
||||
|
||||
// Inspired by https://github.com/bytenode/bytenode
|
||||
const _require = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
||||
function getBytecodeCompilerPath() {
|
||||
return path.join(path.dirname(_require.resolve('electron-vite/package.json')), 'bin', 'electron-bytecode.cjs');
|
||||
}
|
||||
function compileToBytecode(code) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let data = Buffer.from([]);
|
||||
const electronPath = config.getElectronPath();
|
||||
const bytecodePath = getBytecodeCompilerPath();
|
||||
const proc = node_child_process.spawn(electronPath, [bytecodePath], {
|
||||
env: { ELECTRON_RUN_AS_NODE: '1' },
|
||||
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
|
||||
});
|
||||
if (proc.stdin) {
|
||||
proc.stdin.write(code);
|
||||
proc.stdin.end();
|
||||
}
|
||||
if (proc.stdout) {
|
||||
proc.stdout.on('data', chunk => {
|
||||
data = Buffer.concat([data, chunk]);
|
||||
});
|
||||
proc.stdout.on('error', err => {
|
||||
console.error(err);
|
||||
});
|
||||
proc.stdout.on('end', () => {
|
||||
resolve(data);
|
||||
});
|
||||
}
|
||||
if (proc.stderr) {
|
||||
proc.stderr.on('data', chunk => {
|
||||
console.error('Error: ', chunk.toString());
|
||||
});
|
||||
proc.stderr.on('error', err => {
|
||||
console.error('Error: ', err);
|
||||
});
|
||||
}
|
||||
proc.addListener('message', message => console.log(message));
|
||||
proc.addListener('error', err => console.error(err));
|
||||
proc.on('error', err => reject(err));
|
||||
proc.on('exit', () => {
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
const bytecodeModuleLoaderCode = [
|
||||
`"use strict";`,
|
||||
`const fs = require("fs");`,
|
||||
`const path = require("path");`,
|
||||
`const vm = require("vm");`,
|
||||
`const v8 = require("v8");`,
|
||||
`const Module = require("module");`,
|
||||
`v8.setFlagsFromString("--no-lazy");`,
|
||||
`v8.setFlagsFromString("--no-flush-bytecode");`,
|
||||
`const FLAG_HASH_OFFSET = 12;`,
|
||||
`const SOURCE_HASH_OFFSET = 8;`,
|
||||
`let dummyBytecode;`,
|
||||
`function setFlagHashHeader(bytecodeBuffer) {`,
|
||||
` if (!dummyBytecode) {`,
|
||||
` const script = new vm.Script("", {`,
|
||||
` produceCachedData: true`,
|
||||
` });`,
|
||||
` dummyBytecode = script.createCachedData();`,
|
||||
` }`,
|
||||
` dummyBytecode.slice(FLAG_HASH_OFFSET, FLAG_HASH_OFFSET + 4).copy(bytecodeBuffer, FLAG_HASH_OFFSET);`,
|
||||
`};`,
|
||||
`function getSourceHashHeader(bytecodeBuffer) {`,
|
||||
` return bytecodeBuffer.slice(SOURCE_HASH_OFFSET, SOURCE_HASH_OFFSET + 4);`,
|
||||
`};`,
|
||||
`function buffer2Number(buffer) {`,
|
||||
` let ret = 0;`,
|
||||
` ret |= buffer[3] << 24;`,
|
||||
` ret |= buffer[2] << 16;`,
|
||||
` ret |= buffer[1] << 8;`,
|
||||
` ret |= buffer[0];`,
|
||||
` return ret;`,
|
||||
`};`,
|
||||
`Module._extensions[".jsc"] = Module._extensions[".cjsc"] = function (module, filename) {`,
|
||||
` const bytecodeBuffer = fs.readFileSync(filename);`,
|
||||
` if (!Buffer.isBuffer(bytecodeBuffer)) {`,
|
||||
` throw new Error("BytecodeBuffer must be a buffer object.");`,
|
||||
` }`,
|
||||
` setFlagHashHeader(bytecodeBuffer);`,
|
||||
` const length = buffer2Number(getSourceHashHeader(bytecodeBuffer));`,
|
||||
` let dummyCode = "";`,
|
||||
` if (length > 1) {`,
|
||||
` dummyCode = "\\"" + "\\u200b".repeat(length - 2) + "\\"";`,
|
||||
` }`,
|
||||
` const script = new vm.Script(dummyCode, {`,
|
||||
` filename: filename,`,
|
||||
` lineOffset: 0,`,
|
||||
` displayErrors: true,`,
|
||||
` cachedData: bytecodeBuffer`,
|
||||
` });`,
|
||||
` if (script.cachedDataRejected) {`,
|
||||
` throw new Error("Invalid or incompatible cached data (cachedDataRejected)");`,
|
||||
` }`,
|
||||
` const require = function (id) {`,
|
||||
` return module.require(id);`,
|
||||
` };`,
|
||||
` require.resolve = function (request, options) {`,
|
||||
` return Module._resolveFilename(request, module, false, options);`,
|
||||
` };`,
|
||||
` if (process.mainModule) {`,
|
||||
` require.main = process.mainModule;`,
|
||||
` }`,
|
||||
` require.extensions = Module._extensions;`,
|
||||
` require.cache = Module._cache;`,
|
||||
` const compiledWrapper = script.runInThisContext({`,
|
||||
` filename: filename,`,
|
||||
` lineOffset: 0,`,
|
||||
` columnOffset: 0,`,
|
||||
` displayErrors: true`,
|
||||
` });`,
|
||||
` const dirname = path.dirname(filename);`,
|
||||
` const args = [module.exports, require, module, filename, dirname, process, global];`,
|
||||
` return compiledWrapper.apply(module.exports, args);`,
|
||||
`};`
|
||||
];
|
||||
/**
|
||||
* Compile to v8 bytecode to protect source code.
|
||||
*/
|
||||
function bytecodePlugin(options = {}) {
|
||||
if (process.env.NODE_ENV_ELECTRON_VITE !== 'production') {
|
||||
return null;
|
||||
}
|
||||
const { chunkAlias = [], transformArrowFunctions = true, removeBundleJS = true, protectedStrings = [] } = options;
|
||||
const _chunkAlias = Array.isArray(chunkAlias) ? chunkAlias : [chunkAlias];
|
||||
const filter = vite.createFilter(/\.(m?[jt]s|[jt]sx)$/);
|
||||
const escapeRegExpString = (str) => {
|
||||
return str
|
||||
.replace(/\\/g, '\\\\\\\\')
|
||||
.replace(/[|{}()[\]^$+*?.]/g, '\\$&')
|
||||
.replace(/-/g, '\\u002d');
|
||||
};
|
||||
const transformAllChunks = _chunkAlias.length === 0;
|
||||
const isBytecodeChunk = (chunkName) => {
|
||||
return transformAllChunks || _chunkAlias.some(alias => alias === chunkName);
|
||||
};
|
||||
const _transform = (code) => {
|
||||
const re = babel__namespace.transform(code, {
|
||||
plugins: ['@babel/plugin-transform-arrow-functions']
|
||||
});
|
||||
return re.code || '';
|
||||
};
|
||||
const useStrict = '"use strict";';
|
||||
const bytecodeModuleLoader = 'bytecode-loader.cjs';
|
||||
let config$1;
|
||||
let useInRenderer = false;
|
||||
let bytecodeRequired = false;
|
||||
let bytecodeFiles = [];
|
||||
return {
|
||||
name: 'vite:bytecode',
|
||||
apply: 'build',
|
||||
enforce: 'post',
|
||||
configResolved(resolvedConfig) {
|
||||
config$1 = resolvedConfig;
|
||||
useInRenderer = config$1.plugins.some(p => p.name === 'vite:electron-renderer-preset-config');
|
||||
if (useInRenderer) {
|
||||
config$1.logger.warn(colors.yellow('bytecodePlugin does not support renderer.'));
|
||||
}
|
||||
if (resolvedConfig.build.minify && protectedStrings.length > 0) {
|
||||
config$1.logger.warn(colors.yellow('Strings cannot be protected when minification is enabled.'));
|
||||
}
|
||||
},
|
||||
transform(code, id) {
|
||||
if (config$1.build.minify || protectedStrings.length === 0 || !filter(id))
|
||||
return;
|
||||
let match;
|
||||
let s;
|
||||
protectedStrings.forEach(str => {
|
||||
const escapedStr = escapeRegExpString(str);
|
||||
const re = new RegExp(`\\u0027${escapedStr}\\u0027|\\u0022${escapedStr}\\u0022`, 'g');
|
||||
const charCodes = Array.from(str).map(s => s.charCodeAt(0));
|
||||
const replacement = `String.fromCharCode(${charCodes.toString()})`;
|
||||
while ((match = re.exec(code))) {
|
||||
s ||= new MagicString(code);
|
||||
const [full] = match;
|
||||
s.overwrite(match.index, match.index + full.length, replacement, {
|
||||
contentOnly: true
|
||||
});
|
||||
}
|
||||
});
|
||||
if (s) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: config$1.build.sourcemap ? s.generateMap({ hires: 'boundary' }) : null
|
||||
};
|
||||
}
|
||||
},
|
||||
renderChunk(code, chunk, options) {
|
||||
if (options.format === 'es') {
|
||||
config$1.logger.warn(colors.yellow('bytecodePlugin does not support ES module, please remove "type": "module" ' +
|
||||
'in package.json or set the "build.rollupOptions.output.format" option to "cjs".'));
|
||||
return null;
|
||||
}
|
||||
if (useInRenderer) {
|
||||
return null;
|
||||
}
|
||||
if (chunk.type === 'chunk' && isBytecodeChunk(chunk.name)) {
|
||||
bytecodeRequired = true;
|
||||
if (transformArrowFunctions) {
|
||||
return {
|
||||
code: _transform(code)
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
generateBundle(options) {
|
||||
if (options.format !== 'es' && !useInRenderer && bytecodeRequired) {
|
||||
this.emitFile({
|
||||
type: 'asset',
|
||||
source: bytecodeModuleLoaderCode.join('\n') + '\n',
|
||||
name: 'Bytecode Loader File',
|
||||
fileName: bytecodeModuleLoader
|
||||
});
|
||||
}
|
||||
},
|
||||
async writeBundle(options, output) {
|
||||
if (options.format === 'es' || useInRenderer || !bytecodeRequired) {
|
||||
return;
|
||||
}
|
||||
const outDir = options.dir;
|
||||
bytecodeFiles = [];
|
||||
const bundles = Object.keys(output);
|
||||
const chunks = Object.values(output).filter(chunk => chunk.type === 'chunk' && isBytecodeChunk(chunk.name) && chunk.fileName !== bytecodeModuleLoader);
|
||||
const bytecodeChunks = chunks.map(chunk => chunk.fileName);
|
||||
const nonEntryChunks = chunks.filter(chunk => !chunk.isEntry).map(chunk => path.basename(chunk.fileName));
|
||||
const pattern = nonEntryChunks.map(chunk => `(${chunk})`).join('|');
|
||||
const bytecodeRE = pattern ? new RegExp(`require\\(\\S*(?=(${pattern})\\S*\\))`, 'g') : null;
|
||||
const keepBundle = (chunkFileName) => {
|
||||
const newFileName = path.resolve(path.dirname(chunkFileName), `_${path.basename(chunkFileName)}`);
|
||||
fs.renameSync(chunkFileName, newFileName);
|
||||
};
|
||||
const getBytecodeLoaderBlock = (chunkFileName) => {
|
||||
return `require("${config.toRelativePath(bytecodeModuleLoader, vite.normalizePath(chunkFileName))}");`;
|
||||
};
|
||||
await Promise.all(bundles.map(async (name) => {
|
||||
const chunk = output[name];
|
||||
if (chunk.type === 'chunk') {
|
||||
let _code = chunk.code;
|
||||
if (bytecodeRE && _code.match(bytecodeRE)) {
|
||||
let match;
|
||||
const s = new MagicString(_code);
|
||||
while ((match = bytecodeRE.exec(_code))) {
|
||||
const [prefix, chunkName] = match;
|
||||
const len = prefix.length + chunkName.length;
|
||||
s.overwrite(match.index, match.index + len, prefix + chunkName + 'c', {
|
||||
contentOnly: true
|
||||
});
|
||||
}
|
||||
_code = s.toString();
|
||||
}
|
||||
const chunkFileName = path.resolve(outDir, name);
|
||||
if (bytecodeChunks.includes(name)) {
|
||||
const bytecodeBuffer = await compileToBytecode(_code);
|
||||
fs.writeFileSync(path.resolve(outDir, name + 'c'), bytecodeBuffer);
|
||||
if (chunk.isEntry) {
|
||||
if (!removeBundleJS) {
|
||||
keepBundle(chunkFileName);
|
||||
}
|
||||
const bytecodeLoaderBlock = getBytecodeLoaderBlock(chunk.fileName);
|
||||
const bytecodeModuleBlock = `require("./${path.basename(name) + 'c'}");`;
|
||||
const code = `${useStrict}\n${bytecodeLoaderBlock}\n${bytecodeModuleBlock}\n`;
|
||||
fs.writeFileSync(chunkFileName, code);
|
||||
}
|
||||
else {
|
||||
if (removeBundleJS) {
|
||||
fs.unlinkSync(chunkFileName);
|
||||
}
|
||||
else {
|
||||
keepBundle(chunkFileName);
|
||||
}
|
||||
}
|
||||
bytecodeFiles.push({ name: name + 'c', size: bytecodeBuffer.length });
|
||||
}
|
||||
else {
|
||||
if (chunk.isEntry) {
|
||||
let hasBytecodeMoudle = false;
|
||||
const idsToHandle = new Set([...chunk.imports, ...chunk.dynamicImports]);
|
||||
for (const moduleId of idsToHandle) {
|
||||
if (bytecodeChunks.includes(moduleId)) {
|
||||
hasBytecodeMoudle = true;
|
||||
break;
|
||||
}
|
||||
const moduleInfo = this.getModuleInfo(moduleId);
|
||||
if (moduleInfo && !moduleInfo.isExternal) {
|
||||
const { importers, dynamicImporters } = moduleInfo;
|
||||
for (const importerId of importers)
|
||||
idsToHandle.add(importerId);
|
||||
for (const importerId of dynamicImporters)
|
||||
idsToHandle.add(importerId);
|
||||
}
|
||||
}
|
||||
const bytecodeLoaderBlock = getBytecodeLoaderBlock(chunk.fileName);
|
||||
_code = hasBytecodeMoudle ? _code.replace(useStrict, `${useStrict}\n${bytecodeLoaderBlock}`) : _code;
|
||||
}
|
||||
fs.writeFileSync(chunkFileName, _code);
|
||||
}
|
||||
}
|
||||
}));
|
||||
},
|
||||
closeBundle() {
|
||||
if (!useInRenderer) {
|
||||
const chunkLimit = config$1.build.chunkSizeWarningLimit;
|
||||
const outDir = vite.normalizePath(path.relative(config$1.root, path.resolve(config$1.root, config$1.build.outDir))) + '/';
|
||||
config$1.logger.info(`${colors.green(`✓`)} ${bytecodeFiles.length} bundles compiled into bytecode.`);
|
||||
let longest = 0;
|
||||
bytecodeFiles.forEach(file => {
|
||||
const len = file.name.length;
|
||||
if (len > longest)
|
||||
longest = len;
|
||||
});
|
||||
bytecodeFiles.forEach(file => {
|
||||
const kbs = file.size / 1000;
|
||||
config$1.logger.info(`${colors.gray(colors.white(colors.dim(outDir)))}${colors.green(file.name.padEnd(longest + 2))} ${kbs > chunkLimit ? colors.yellow(`${kbs.toFixed(2)} kB`) : colors.dim(`${kbs.toFixed(2)} kB`)}`);
|
||||
});
|
||||
bytecodeFiles = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically externalize dependencies
|
||||
*/
|
||||
function externalizeDepsPlugin(options = {}) {
|
||||
const { exclude = [], include = [] } = options;
|
||||
const pkg = config.loadPackageData() || {};
|
||||
let deps = Object.keys(pkg.dependencies || {});
|
||||
if (include.length) {
|
||||
deps = deps.concat(include.filter(dep => dep.trim() !== ''));
|
||||
}
|
||||
if (exclude.length) {
|
||||
deps = deps.filter(dep => !exclude.includes(dep));
|
||||
}
|
||||
deps = [...new Set(deps)];
|
||||
return {
|
||||
name: 'vite:externalize-deps',
|
||||
enforce: 'pre',
|
||||
config(config) {
|
||||
const defaultConfig = {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: deps.length > 0 ? [...deps, new RegExp(`^(${deps.join('|')})/.+`)] : []
|
||||
}
|
||||
}
|
||||
};
|
||||
const buildConfig = vite.mergeConfig(defaultConfig.build, config.build || {});
|
||||
config.build = buildConfig;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function transformWithSWC(code, id, options) {
|
||||
const { sourcemap = false, minify = false } = options;
|
||||
delete options.sourcemap;
|
||||
delete options.minify;
|
||||
const isTs = /\.tsx?$/.test(id);
|
||||
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
||||
let swc;
|
||||
try {
|
||||
swc = require$1('@swc/core');
|
||||
}
|
||||
catch {
|
||||
throw new Error('swc plugin require @swc/core, you need to install it.');
|
||||
}
|
||||
const jsc = {
|
||||
parser: {
|
||||
syntax: isTs ? 'typescript' : 'ecmascript',
|
||||
decorators: true
|
||||
},
|
||||
transform: {
|
||||
legacyDecorator: true,
|
||||
decoratorMetadata: true,
|
||||
...options
|
||||
},
|
||||
keepClassNames: true,
|
||||
target: 'es2022',
|
||||
minify: {
|
||||
format: {
|
||||
comments: false
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = await swc.transform(code, {
|
||||
jsc,
|
||||
sourceMaps: sourcemap,
|
||||
minify,
|
||||
configFile: false,
|
||||
swcrc: false
|
||||
});
|
||||
const map = sourcemap && result.map ? JSON.parse(result.map) : { mappings: '' };
|
||||
return {
|
||||
code: result.code,
|
||||
map
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Use SWC to support for emitting type metadata for decorators.
|
||||
* When using `swcPlugin`, you need to install `@swc/core`.
|
||||
*/
|
||||
function swcPlugin(options = {}) {
|
||||
const filter = vite.createFilter(options.include || /\.(m?ts|[jt]sx)$/, options.exclude || /\.js$/);
|
||||
let sourcemap = false;
|
||||
let minify = false;
|
||||
return {
|
||||
name: 'vite:swc',
|
||||
config() {
|
||||
return {
|
||||
esbuild: false
|
||||
};
|
||||
},
|
||||
async configResolved(resolvedConfig) {
|
||||
sourcemap = resolvedConfig.build?.sourcemap === 'inline' ? 'inline' : !!resolvedConfig.build?.sourcemap;
|
||||
minify = resolvedConfig.build?.minify;
|
||||
},
|
||||
async transform(code, id) {
|
||||
if (filter(id)) {
|
||||
const result = await transformWithSWC(code, id, { sourcemap, ...(options.transformOptions || {}) });
|
||||
return {
|
||||
code: result.code,
|
||||
map: result.map
|
||||
};
|
||||
}
|
||||
},
|
||||
async renderChunk(code, chunk) {
|
||||
if (!minify || minify === 'terser') {
|
||||
return null;
|
||||
}
|
||||
const result = await transformWithSWC(code, chunk.fileName, {
|
||||
sourcemap,
|
||||
minify: true,
|
||||
...(options.transformOptions || {})
|
||||
});
|
||||
return {
|
||||
code: result.code,
|
||||
map: result.map
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Object.defineProperty(exports, "createLogger", {
|
||||
enumerable: true,
|
||||
get: function () { return vite.createLogger; }
|
||||
});
|
||||
Object.defineProperty(exports, "defineViteConfig", {
|
||||
enumerable: true,
|
||||
get: function () { return vite.defineConfig; }
|
||||
});
|
||||
Object.defineProperty(exports, "mergeConfig", {
|
||||
enumerable: true,
|
||||
get: function () { return vite.mergeConfig; }
|
||||
});
|
||||
Object.defineProperty(exports, "splitVendorChunk", {
|
||||
enumerable: true,
|
||||
get: function () { return vite.splitVendorChunk; }
|
||||
});
|
||||
Object.defineProperty(exports, "splitVendorChunkPlugin", {
|
||||
enumerable: true,
|
||||
get: function () { return vite.splitVendorChunkPlugin; }
|
||||
});
|
||||
exports.defineConfig = config.defineConfig;
|
||||
exports.loadConfigFromFile = config.loadConfigFromFile;
|
||||
exports.loadEnv = config.loadEnv;
|
||||
exports.resolveConfig = config.resolveConfig;
|
||||
exports.createServer = server.createServer;
|
||||
exports.build = build.build;
|
||||
exports.preview = preview.preview;
|
||||
exports.bytecodePlugin = bytecodePlugin;
|
||||
exports.externalizeDepsPlugin = externalizeDepsPlugin;
|
||||
exports.swcPlugin = swcPlugin;
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/// <reference types="node" />
|
||||
import { UserConfig as UserConfig$1, UserConfigExport, ConfigEnv, LogLevel, Plugin, FilterPattern } from 'vite';
|
||||
export { LogLevel, createLogger, defineConfig as defineViteConfig, mergeConfig, splitVendorChunk, splitVendorChunkPlugin } from 'vite';
|
||||
import { TransformConfig } from '@swc/core';
|
||||
|
||||
interface UserConfig {
|
||||
/**
|
||||
* Vite config options for electron main process
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
main?: UserConfig$1 & {
|
||||
configFile?: string | false;
|
||||
};
|
||||
/**
|
||||
* Vite config options for electron renderer process
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
renderer?: UserConfig$1 & {
|
||||
configFile?: string | false;
|
||||
};
|
||||
/**
|
||||
* Vite config options for electron preload files
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
preload?: UserConfig$1 & {
|
||||
configFile?: string | false;
|
||||
};
|
||||
}
|
||||
interface ElectronViteConfig {
|
||||
/**
|
||||
* Vite config options for electron main process
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
main?: UserConfigExport;
|
||||
/**
|
||||
* Vite config options for electron renderer process
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
renderer?: UserConfigExport;
|
||||
/**
|
||||
* Vite config options for electron preload files
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
preload?: UserConfigExport;
|
||||
}
|
||||
type InlineConfig = Omit<UserConfig$1, 'base'> & {
|
||||
configFile?: string | false;
|
||||
envFile?: false;
|
||||
ignoreConfigWarning?: boolean;
|
||||
};
|
||||
type ElectronViteConfigFnObject = (env: ConfigEnv) => ElectronViteConfig;
|
||||
type ElectronViteConfigFnPromise = (env: ConfigEnv) => Promise<ElectronViteConfig>;
|
||||
type ElectronViteConfigFn = (env: ConfigEnv) => ElectronViteConfig | Promise<ElectronViteConfig>;
|
||||
type ElectronViteConfigExport = ElectronViteConfig | Promise<ElectronViteConfig> | ElectronViteConfigFnObject | ElectronViteConfigFnPromise | ElectronViteConfigFn;
|
||||
/**
|
||||
* Type helper to make it easier to use `electron.vite.config.*`
|
||||
* accepts a direct {@link ElectronViteConfig} object, or a function that returns it.
|
||||
* The function receives a object that exposes two properties:
|
||||
* `command` (either `'build'` or `'serve'`), and `mode`.
|
||||
*/
|
||||
declare function defineConfig(config: ElectronViteConfig): ElectronViteConfig;
|
||||
declare function defineConfig(config: Promise<ElectronViteConfig>): Promise<ElectronViteConfig>;
|
||||
declare function defineConfig(config: ElectronViteConfigFnObject): ElectronViteConfigFnObject;
|
||||
declare function defineConfig(config: ElectronViteConfigExport): ElectronViteConfigExport;
|
||||
interface ResolvedConfig {
|
||||
config?: UserConfig;
|
||||
configFile?: string;
|
||||
configFileDependencies: string[];
|
||||
}
|
||||
declare function resolveConfig(inlineConfig: InlineConfig, command: 'build' | 'serve', defaultMode?: string): Promise<ResolvedConfig>;
|
||||
declare function loadConfigFromFile(configEnv: ConfigEnv, configFile?: string, configRoot?: string, logLevel?: LogLevel, ignoreConfigWarning?: boolean): Promise<{
|
||||
path: string;
|
||||
config: UserConfig;
|
||||
dependencies: string[];
|
||||
}>;
|
||||
|
||||
declare function createServer(inlineConfig: InlineConfig | undefined, options: {
|
||||
rendererOnly?: boolean;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Bundles the electron app for production.
|
||||
*/
|
||||
declare function build(inlineConfig?: InlineConfig): Promise<void>;
|
||||
|
||||
declare function preview(inlineConfig: InlineConfig | undefined, options: {
|
||||
skipBuild?: boolean;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Load `.env` files within the `envDir` (default: `process.cwd()`) .
|
||||
* By default, only env variables prefixed with `VITE_`, `MAIN_VITE_`, `PRELOAD_VITE_` and
|
||||
* `RENDERER_VITE_` are loaded, unless `prefixes` is changed.
|
||||
*/
|
||||
declare function loadEnv(mode: string, envDir?: string, prefixes?: string | string[]): Record<string, string>;
|
||||
|
||||
interface BytecodeOptions {
|
||||
chunkAlias?: string | string[];
|
||||
transformArrowFunctions?: boolean;
|
||||
removeBundleJS?: boolean;
|
||||
protectedStrings?: string[];
|
||||
}
|
||||
/**
|
||||
* Compile to v8 bytecode to protect source code.
|
||||
*/
|
||||
declare function bytecodePlugin(options?: BytecodeOptions): Plugin | null;
|
||||
|
||||
interface ExternalOptions {
|
||||
exclude?: string[];
|
||||
include?: string[];
|
||||
}
|
||||
/**
|
||||
* Automatically externalize dependencies
|
||||
*/
|
||||
declare function externalizeDepsPlugin(options?: ExternalOptions): Plugin | null;
|
||||
|
||||
type SwcOptions = {
|
||||
include?: FilterPattern;
|
||||
exclude?: FilterPattern;
|
||||
transformOptions?: TransformConfig;
|
||||
};
|
||||
/**
|
||||
* Use SWC to support for emitting type metadata for decorators.
|
||||
* When using `swcPlugin`, you need to install `@swc/core`.
|
||||
*/
|
||||
declare function swcPlugin(options?: SwcOptions): Plugin;
|
||||
|
||||
export { type BytecodeOptions, type ElectronViteConfig, type ElectronViteConfigExport, type ElectronViteConfigFn, type ElectronViteConfigFnObject, type ElectronViteConfigFnPromise, type ExternalOptions, type InlineConfig, type ResolvedConfig, type SwcOptions, type UserConfig, build, bytecodePlugin, createServer, defineConfig, externalizeDepsPlugin, loadConfigFromFile, loadEnv, preview, resolveConfig, swcPlugin };
|
||||
+464
@@ -0,0 +1,464 @@
|
||||
import { createFilter, normalizePath, mergeConfig } from 'vite';
|
||||
export { createLogger, defineConfig as defineViteConfig, mergeConfig, splitVendorChunk, splitVendorChunkPlugin } from 'vite';
|
||||
import { g as getElectronPath, t as toRelativePath, l as loadPackageData } from './chunks/lib-BmEkZIgk.mjs';
|
||||
export { d as defineConfig, b as loadConfigFromFile, a as loadEnv, r as resolveConfig } from './chunks/lib-BmEkZIgk.mjs';
|
||||
export { createServer } from './chunks/lib-t2ExBjL5.mjs';
|
||||
export { build } from './chunks/lib-D1n7TA6K.mjs';
|
||||
export { preview } from './chunks/lib-AgEz08--.mjs';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { createRequire } from 'node:module';
|
||||
import colors from 'picocolors';
|
||||
import * as babel from '@babel/core';
|
||||
import MagicString from 'magic-string';
|
||||
import 'node:url';
|
||||
import 'esbuild';
|
||||
import 'node:crypto';
|
||||
import 'node:fs/promises';
|
||||
|
||||
// Inspired by https://github.com/bytenode/bytenode
|
||||
const _require = createRequire(import.meta.url);
|
||||
function getBytecodeCompilerPath() {
|
||||
return path.join(path.dirname(_require.resolve('electron-vite/package.json')), 'bin', 'electron-bytecode.cjs');
|
||||
}
|
||||
function compileToBytecode(code) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let data = Buffer.from([]);
|
||||
const electronPath = getElectronPath();
|
||||
const bytecodePath = getBytecodeCompilerPath();
|
||||
const proc = spawn(electronPath, [bytecodePath], {
|
||||
env: { ELECTRON_RUN_AS_NODE: '1' },
|
||||
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
|
||||
});
|
||||
if (proc.stdin) {
|
||||
proc.stdin.write(code);
|
||||
proc.stdin.end();
|
||||
}
|
||||
if (proc.stdout) {
|
||||
proc.stdout.on('data', chunk => {
|
||||
data = Buffer.concat([data, chunk]);
|
||||
});
|
||||
proc.stdout.on('error', err => {
|
||||
console.error(err);
|
||||
});
|
||||
proc.stdout.on('end', () => {
|
||||
resolve(data);
|
||||
});
|
||||
}
|
||||
if (proc.stderr) {
|
||||
proc.stderr.on('data', chunk => {
|
||||
console.error('Error: ', chunk.toString());
|
||||
});
|
||||
proc.stderr.on('error', err => {
|
||||
console.error('Error: ', err);
|
||||
});
|
||||
}
|
||||
proc.addListener('message', message => console.log(message));
|
||||
proc.addListener('error', err => console.error(err));
|
||||
proc.on('error', err => reject(err));
|
||||
proc.on('exit', () => {
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
const bytecodeModuleLoaderCode = [
|
||||
`"use strict";`,
|
||||
`const fs = require("fs");`,
|
||||
`const path = require("path");`,
|
||||
`const vm = require("vm");`,
|
||||
`const v8 = require("v8");`,
|
||||
`const Module = require("module");`,
|
||||
`v8.setFlagsFromString("--no-lazy");`,
|
||||
`v8.setFlagsFromString("--no-flush-bytecode");`,
|
||||
`const FLAG_HASH_OFFSET = 12;`,
|
||||
`const SOURCE_HASH_OFFSET = 8;`,
|
||||
`let dummyBytecode;`,
|
||||
`function setFlagHashHeader(bytecodeBuffer) {`,
|
||||
` if (!dummyBytecode) {`,
|
||||
` const script = new vm.Script("", {`,
|
||||
` produceCachedData: true`,
|
||||
` });`,
|
||||
` dummyBytecode = script.createCachedData();`,
|
||||
` }`,
|
||||
` dummyBytecode.slice(FLAG_HASH_OFFSET, FLAG_HASH_OFFSET + 4).copy(bytecodeBuffer, FLAG_HASH_OFFSET);`,
|
||||
`};`,
|
||||
`function getSourceHashHeader(bytecodeBuffer) {`,
|
||||
` return bytecodeBuffer.slice(SOURCE_HASH_OFFSET, SOURCE_HASH_OFFSET + 4);`,
|
||||
`};`,
|
||||
`function buffer2Number(buffer) {`,
|
||||
` let ret = 0;`,
|
||||
` ret |= buffer[3] << 24;`,
|
||||
` ret |= buffer[2] << 16;`,
|
||||
` ret |= buffer[1] << 8;`,
|
||||
` ret |= buffer[0];`,
|
||||
` return ret;`,
|
||||
`};`,
|
||||
`Module._extensions[".jsc"] = Module._extensions[".cjsc"] = function (module, filename) {`,
|
||||
` const bytecodeBuffer = fs.readFileSync(filename);`,
|
||||
` if (!Buffer.isBuffer(bytecodeBuffer)) {`,
|
||||
` throw new Error("BytecodeBuffer must be a buffer object.");`,
|
||||
` }`,
|
||||
` setFlagHashHeader(bytecodeBuffer);`,
|
||||
` const length = buffer2Number(getSourceHashHeader(bytecodeBuffer));`,
|
||||
` let dummyCode = "";`,
|
||||
` if (length > 1) {`,
|
||||
` dummyCode = "\\"" + "\\u200b".repeat(length - 2) + "\\"";`,
|
||||
` }`,
|
||||
` const script = new vm.Script(dummyCode, {`,
|
||||
` filename: filename,`,
|
||||
` lineOffset: 0,`,
|
||||
` displayErrors: true,`,
|
||||
` cachedData: bytecodeBuffer`,
|
||||
` });`,
|
||||
` if (script.cachedDataRejected) {`,
|
||||
` throw new Error("Invalid or incompatible cached data (cachedDataRejected)");`,
|
||||
` }`,
|
||||
` const require = function (id) {`,
|
||||
` return module.require(id);`,
|
||||
` };`,
|
||||
` require.resolve = function (request, options) {`,
|
||||
` return Module._resolveFilename(request, module, false, options);`,
|
||||
` };`,
|
||||
` if (process.mainModule) {`,
|
||||
` require.main = process.mainModule;`,
|
||||
` }`,
|
||||
` require.extensions = Module._extensions;`,
|
||||
` require.cache = Module._cache;`,
|
||||
` const compiledWrapper = script.runInThisContext({`,
|
||||
` filename: filename,`,
|
||||
` lineOffset: 0,`,
|
||||
` columnOffset: 0,`,
|
||||
` displayErrors: true`,
|
||||
` });`,
|
||||
` const dirname = path.dirname(filename);`,
|
||||
` const args = [module.exports, require, module, filename, dirname, process, global];`,
|
||||
` return compiledWrapper.apply(module.exports, args);`,
|
||||
`};`
|
||||
];
|
||||
/**
|
||||
* Compile to v8 bytecode to protect source code.
|
||||
*/
|
||||
function bytecodePlugin(options = {}) {
|
||||
if (process.env.NODE_ENV_ELECTRON_VITE !== 'production') {
|
||||
return null;
|
||||
}
|
||||
const { chunkAlias = [], transformArrowFunctions = true, removeBundleJS = true, protectedStrings = [] } = options;
|
||||
const _chunkAlias = Array.isArray(chunkAlias) ? chunkAlias : [chunkAlias];
|
||||
const filter = createFilter(/\.(m?[jt]s|[jt]sx)$/);
|
||||
const escapeRegExpString = (str) => {
|
||||
return str
|
||||
.replace(/\\/g, '\\\\\\\\')
|
||||
.replace(/[|{}()[\]^$+*?.]/g, '\\$&')
|
||||
.replace(/-/g, '\\u002d');
|
||||
};
|
||||
const transformAllChunks = _chunkAlias.length === 0;
|
||||
const isBytecodeChunk = (chunkName) => {
|
||||
return transformAllChunks || _chunkAlias.some(alias => alias === chunkName);
|
||||
};
|
||||
const _transform = (code) => {
|
||||
const re = babel.transform(code, {
|
||||
plugins: ['@babel/plugin-transform-arrow-functions']
|
||||
});
|
||||
return re.code || '';
|
||||
};
|
||||
const useStrict = '"use strict";';
|
||||
const bytecodeModuleLoader = 'bytecode-loader.cjs';
|
||||
let config;
|
||||
let useInRenderer = false;
|
||||
let bytecodeRequired = false;
|
||||
let bytecodeFiles = [];
|
||||
return {
|
||||
name: 'vite:bytecode',
|
||||
apply: 'build',
|
||||
enforce: 'post',
|
||||
configResolved(resolvedConfig) {
|
||||
config = resolvedConfig;
|
||||
useInRenderer = config.plugins.some(p => p.name === 'vite:electron-renderer-preset-config');
|
||||
if (useInRenderer) {
|
||||
config.logger.warn(colors.yellow('bytecodePlugin does not support renderer.'));
|
||||
}
|
||||
if (resolvedConfig.build.minify && protectedStrings.length > 0) {
|
||||
config.logger.warn(colors.yellow('Strings cannot be protected when minification is enabled.'));
|
||||
}
|
||||
},
|
||||
transform(code, id) {
|
||||
if (config.build.minify || protectedStrings.length === 0 || !filter(id))
|
||||
return;
|
||||
let match;
|
||||
let s;
|
||||
protectedStrings.forEach(str => {
|
||||
const escapedStr = escapeRegExpString(str);
|
||||
const re = new RegExp(`\\u0027${escapedStr}\\u0027|\\u0022${escapedStr}\\u0022`, 'g');
|
||||
const charCodes = Array.from(str).map(s => s.charCodeAt(0));
|
||||
const replacement = `String.fromCharCode(${charCodes.toString()})`;
|
||||
while ((match = re.exec(code))) {
|
||||
s ||= new MagicString(code);
|
||||
const [full] = match;
|
||||
s.overwrite(match.index, match.index + full.length, replacement, {
|
||||
contentOnly: true
|
||||
});
|
||||
}
|
||||
});
|
||||
if (s) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: config.build.sourcemap ? s.generateMap({ hires: 'boundary' }) : null
|
||||
};
|
||||
}
|
||||
},
|
||||
renderChunk(code, chunk, options) {
|
||||
if (options.format === 'es') {
|
||||
config.logger.warn(colors.yellow('bytecodePlugin does not support ES module, please remove "type": "module" ' +
|
||||
'in package.json or set the "build.rollupOptions.output.format" option to "cjs".'));
|
||||
return null;
|
||||
}
|
||||
if (useInRenderer) {
|
||||
return null;
|
||||
}
|
||||
if (chunk.type === 'chunk' && isBytecodeChunk(chunk.name)) {
|
||||
bytecodeRequired = true;
|
||||
if (transformArrowFunctions) {
|
||||
return {
|
||||
code: _transform(code)
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
generateBundle(options) {
|
||||
if (options.format !== 'es' && !useInRenderer && bytecodeRequired) {
|
||||
this.emitFile({
|
||||
type: 'asset',
|
||||
source: bytecodeModuleLoaderCode.join('\n') + '\n',
|
||||
name: 'Bytecode Loader File',
|
||||
fileName: bytecodeModuleLoader
|
||||
});
|
||||
}
|
||||
},
|
||||
async writeBundle(options, output) {
|
||||
if (options.format === 'es' || useInRenderer || !bytecodeRequired) {
|
||||
return;
|
||||
}
|
||||
const outDir = options.dir;
|
||||
bytecodeFiles = [];
|
||||
const bundles = Object.keys(output);
|
||||
const chunks = Object.values(output).filter(chunk => chunk.type === 'chunk' && isBytecodeChunk(chunk.name) && chunk.fileName !== bytecodeModuleLoader);
|
||||
const bytecodeChunks = chunks.map(chunk => chunk.fileName);
|
||||
const nonEntryChunks = chunks.filter(chunk => !chunk.isEntry).map(chunk => path.basename(chunk.fileName));
|
||||
const pattern = nonEntryChunks.map(chunk => `(${chunk})`).join('|');
|
||||
const bytecodeRE = pattern ? new RegExp(`require\\(\\S*(?=(${pattern})\\S*\\))`, 'g') : null;
|
||||
const keepBundle = (chunkFileName) => {
|
||||
const newFileName = path.resolve(path.dirname(chunkFileName), `_${path.basename(chunkFileName)}`);
|
||||
fs.renameSync(chunkFileName, newFileName);
|
||||
};
|
||||
const getBytecodeLoaderBlock = (chunkFileName) => {
|
||||
return `require("${toRelativePath(bytecodeModuleLoader, normalizePath(chunkFileName))}");`;
|
||||
};
|
||||
await Promise.all(bundles.map(async (name) => {
|
||||
const chunk = output[name];
|
||||
if (chunk.type === 'chunk') {
|
||||
let _code = chunk.code;
|
||||
if (bytecodeRE && _code.match(bytecodeRE)) {
|
||||
let match;
|
||||
const s = new MagicString(_code);
|
||||
while ((match = bytecodeRE.exec(_code))) {
|
||||
const [prefix, chunkName] = match;
|
||||
const len = prefix.length + chunkName.length;
|
||||
s.overwrite(match.index, match.index + len, prefix + chunkName + 'c', {
|
||||
contentOnly: true
|
||||
});
|
||||
}
|
||||
_code = s.toString();
|
||||
}
|
||||
const chunkFileName = path.resolve(outDir, name);
|
||||
if (bytecodeChunks.includes(name)) {
|
||||
const bytecodeBuffer = await compileToBytecode(_code);
|
||||
fs.writeFileSync(path.resolve(outDir, name + 'c'), bytecodeBuffer);
|
||||
if (chunk.isEntry) {
|
||||
if (!removeBundleJS) {
|
||||
keepBundle(chunkFileName);
|
||||
}
|
||||
const bytecodeLoaderBlock = getBytecodeLoaderBlock(chunk.fileName);
|
||||
const bytecodeModuleBlock = `require("./${path.basename(name) + 'c'}");`;
|
||||
const code = `${useStrict}\n${bytecodeLoaderBlock}\n${bytecodeModuleBlock}\n`;
|
||||
fs.writeFileSync(chunkFileName, code);
|
||||
}
|
||||
else {
|
||||
if (removeBundleJS) {
|
||||
fs.unlinkSync(chunkFileName);
|
||||
}
|
||||
else {
|
||||
keepBundle(chunkFileName);
|
||||
}
|
||||
}
|
||||
bytecodeFiles.push({ name: name + 'c', size: bytecodeBuffer.length });
|
||||
}
|
||||
else {
|
||||
if (chunk.isEntry) {
|
||||
let hasBytecodeMoudle = false;
|
||||
const idsToHandle = new Set([...chunk.imports, ...chunk.dynamicImports]);
|
||||
for (const moduleId of idsToHandle) {
|
||||
if (bytecodeChunks.includes(moduleId)) {
|
||||
hasBytecodeMoudle = true;
|
||||
break;
|
||||
}
|
||||
const moduleInfo = this.getModuleInfo(moduleId);
|
||||
if (moduleInfo && !moduleInfo.isExternal) {
|
||||
const { importers, dynamicImporters } = moduleInfo;
|
||||
for (const importerId of importers)
|
||||
idsToHandle.add(importerId);
|
||||
for (const importerId of dynamicImporters)
|
||||
idsToHandle.add(importerId);
|
||||
}
|
||||
}
|
||||
const bytecodeLoaderBlock = getBytecodeLoaderBlock(chunk.fileName);
|
||||
_code = hasBytecodeMoudle ? _code.replace(useStrict, `${useStrict}\n${bytecodeLoaderBlock}`) : _code;
|
||||
}
|
||||
fs.writeFileSync(chunkFileName, _code);
|
||||
}
|
||||
}
|
||||
}));
|
||||
},
|
||||
closeBundle() {
|
||||
if (!useInRenderer) {
|
||||
const chunkLimit = config.build.chunkSizeWarningLimit;
|
||||
const outDir = normalizePath(path.relative(config.root, path.resolve(config.root, config.build.outDir))) + '/';
|
||||
config.logger.info(`${colors.green(`✓`)} ${bytecodeFiles.length} bundles compiled into bytecode.`);
|
||||
let longest = 0;
|
||||
bytecodeFiles.forEach(file => {
|
||||
const len = file.name.length;
|
||||
if (len > longest)
|
||||
longest = len;
|
||||
});
|
||||
bytecodeFiles.forEach(file => {
|
||||
const kbs = file.size / 1000;
|
||||
config.logger.info(`${colors.gray(colors.white(colors.dim(outDir)))}${colors.green(file.name.padEnd(longest + 2))} ${kbs > chunkLimit ? colors.yellow(`${kbs.toFixed(2)} kB`) : colors.dim(`${kbs.toFixed(2)} kB`)}`);
|
||||
});
|
||||
bytecodeFiles = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically externalize dependencies
|
||||
*/
|
||||
function externalizeDepsPlugin(options = {}) {
|
||||
const { exclude = [], include = [] } = options;
|
||||
const pkg = loadPackageData() || {};
|
||||
let deps = Object.keys(pkg.dependencies || {});
|
||||
if (include.length) {
|
||||
deps = deps.concat(include.filter(dep => dep.trim() !== ''));
|
||||
}
|
||||
if (exclude.length) {
|
||||
deps = deps.filter(dep => !exclude.includes(dep));
|
||||
}
|
||||
deps = [...new Set(deps)];
|
||||
return {
|
||||
name: 'vite:externalize-deps',
|
||||
enforce: 'pre',
|
||||
config(config) {
|
||||
const defaultConfig = {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: deps.length > 0 ? [...deps, new RegExp(`^(${deps.join('|')})/.+`)] : []
|
||||
}
|
||||
}
|
||||
};
|
||||
const buildConfig = mergeConfig(defaultConfig.build, config.build || {});
|
||||
config.build = buildConfig;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function transformWithSWC(code, id, options) {
|
||||
const { sourcemap = false, minify = false } = options;
|
||||
delete options.sourcemap;
|
||||
delete options.minify;
|
||||
const isTs = /\.tsx?$/.test(id);
|
||||
const require = createRequire(import.meta.url);
|
||||
let swc;
|
||||
try {
|
||||
swc = require('@swc/core');
|
||||
}
|
||||
catch {
|
||||
throw new Error('swc plugin require @swc/core, you need to install it.');
|
||||
}
|
||||
const jsc = {
|
||||
parser: {
|
||||
syntax: isTs ? 'typescript' : 'ecmascript',
|
||||
decorators: true
|
||||
},
|
||||
transform: {
|
||||
legacyDecorator: true,
|
||||
decoratorMetadata: true,
|
||||
...options
|
||||
},
|
||||
keepClassNames: true,
|
||||
target: 'es2022',
|
||||
minify: {
|
||||
format: {
|
||||
comments: false
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = await swc.transform(code, {
|
||||
jsc,
|
||||
sourceMaps: sourcemap,
|
||||
minify,
|
||||
configFile: false,
|
||||
swcrc: false
|
||||
});
|
||||
const map = sourcemap && result.map ? JSON.parse(result.map) : { mappings: '' };
|
||||
return {
|
||||
code: result.code,
|
||||
map
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Use SWC to support for emitting type metadata for decorators.
|
||||
* When using `swcPlugin`, you need to install `@swc/core`.
|
||||
*/
|
||||
function swcPlugin(options = {}) {
|
||||
const filter = createFilter(options.include || /\.(m?ts|[jt]sx)$/, options.exclude || /\.js$/);
|
||||
let sourcemap = false;
|
||||
let minify = false;
|
||||
return {
|
||||
name: 'vite:swc',
|
||||
config() {
|
||||
return {
|
||||
esbuild: false
|
||||
};
|
||||
},
|
||||
async configResolved(resolvedConfig) {
|
||||
sourcemap = resolvedConfig.build?.sourcemap === 'inline' ? 'inline' : !!resolvedConfig.build?.sourcemap;
|
||||
minify = resolvedConfig.build?.minify;
|
||||
},
|
||||
async transform(code, id) {
|
||||
if (filter(id)) {
|
||||
const result = await transformWithSWC(code, id, { sourcemap, ...(options.transformOptions || {}) });
|
||||
return {
|
||||
code: result.code,
|
||||
map: result.map
|
||||
};
|
||||
}
|
||||
},
|
||||
async renderChunk(code, chunk) {
|
||||
if (!minify || minify === 'terser') {
|
||||
return null;
|
||||
}
|
||||
const result = await transformWithSWC(code, chunk.fileName, {
|
||||
sourcemap,
|
||||
minify: true,
|
||||
...(options.transformOptions || {})
|
||||
});
|
||||
return {
|
||||
code: result.code,
|
||||
map: result.map
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { bytecodePlugin, externalizeDepsPlugin, swcPlugin };
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
// node worker
|
||||
declare module '*?nodeWorker' {
|
||||
import { Worker, WorkerOptions } from 'node:worker_threads'
|
||||
export default function (options: WorkerOptions): Worker
|
||||
}
|
||||
|
||||
// module path
|
||||
declare module '*?modulePath' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
// node asset
|
||||
declare module '*?asset' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*?asset&asarUnpack' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
declare module '*.json?commonjs-external&asset' {
|
||||
const src: string
|
||||
export default src
|
||||
}
|
||||
|
||||
// native node module
|
||||
declare module '*.node' {
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const node: any
|
||||
export default node
|
||||
}
|
||||
|
||||
// node wasm
|
||||
declare module '*.wasm?loader' {
|
||||
const loadWasm: (options?: WebAssembly.Imports) => Promise<WebAssembly.Instance>
|
||||
export default loadWasm
|
||||
}
|
||||
|
||||
// build-in process env
|
||||
declare namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
/**
|
||||
* Vite's dev server address for Electron renderers.
|
||||
*/
|
||||
readonly ELECTRON_RENDERER_URL?: string
|
||||
}
|
||||
}
|
||||
|
||||
// Refer to Vite's ImportMeta type declarations
|
||||
// <https://github.com/vitejs/vite/blob/main/packages/vite/types/importMeta.d.ts>
|
||||
|
||||
interface ImportMetaEnv {
|
||||
MODE: string
|
||||
DEV: boolean
|
||||
PROD: boolean
|
||||
}
|
||||
|
||||
interface ImportGlobOptions<Eager extends boolean, AsType extends string> {
|
||||
/**
|
||||
* Import type for the import url.
|
||||
*/
|
||||
as?: AsType
|
||||
/**
|
||||
* Import as static or dynamic
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
eager?: Eager
|
||||
/**
|
||||
* Import only the specific named export. Set to `default` to import the default export.
|
||||
*/
|
||||
import?: string
|
||||
/**
|
||||
* Custom queries
|
||||
*/
|
||||
query?: string | Record<string, string | number | boolean>
|
||||
/**
|
||||
* Search files also inside `node_modules/` and hidden directories (e.g. `.git/`). This might have impact on performance.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
exhaustive?: boolean
|
||||
}
|
||||
|
||||
interface KnownAsTypeMap {
|
||||
raw: string
|
||||
url: string
|
||||
worker: Worker
|
||||
}
|
||||
|
||||
interface ImportGlobFunction {
|
||||
/**
|
||||
* Import a list of files with a glob pattern.
|
||||
*
|
||||
* https://vitejs.dev/guide/features.html#glob-import
|
||||
*/
|
||||
<Eager extends boolean, As extends string, T = As extends keyof KnownAsTypeMap ? KnownAsTypeMap[As] : unknown>(
|
||||
glob: string | string[],
|
||||
options?: ImportGlobOptions<Eager, As>
|
||||
): (Eager extends true ? true : false) extends true ? Record<string, T> : Record<string, () => Promise<T>>
|
||||
<M>(glob: string | string[], options?: ImportGlobOptions<false, string>): Record<string, () => Promise<M>>
|
||||
<M>(glob: string | string[], options: ImportGlobOptions<true, string>): Record<string, M>
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
url: string
|
||||
readonly env: ImportMetaEnv
|
||||
glob: ImportGlobFunction
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"name": "electron-vite",
|
||||
"version": "2.3.0",
|
||||
"description": "Electron build tooling based on Vite",
|
||||
"type": "module",
|
||||
"main": "dist/index.cjs",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs"
|
||||
},
|
||||
"./node": {
|
||||
"types": "./node.d.ts"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"bin": {
|
||||
"electron-vite": "bin/electron-vite.js"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist",
|
||||
"node.d.ts"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
},
|
||||
"packageManager": "pnpm@8.6.10",
|
||||
"author": "Alex Wei<https://github.com/alex8088>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/alex8088/electron-vite.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/alex8088/electron-vite/issues"
|
||||
},
|
||||
"homepage": "https://electron-vite.org",
|
||||
"keywords": [
|
||||
"electron",
|
||||
"vite",
|
||||
"cli",
|
||||
"plugin"
|
||||
],
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint --ext .ts src/**",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"build": "pnpm run lint && rollup -c rollup.config.ts --configPlugin typescript"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "npx lint-staged",
|
||||
"commit-msg": "node scripts/verifyCommit.js $1"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.ts?(x)": [
|
||||
"eslint",
|
||||
"prettier --parser=typescript --write"
|
||||
]
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/core": "^1.0.0",
|
||||
"vite": "^4.0.0 || ^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/core": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@swc/core": "^1.6.5",
|
||||
"@types/node": "^18.19.39",
|
||||
"@typescript-eslint/eslint-plugin": "^7.13.1",
|
||||
"@typescript-eslint/parser": "^7.13.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"lint-staged": "^15.2.7",
|
||||
"prettier": "^3.3.2",
|
||||
"rollup": "^4.18.0",
|
||||
"rollup-plugin-dts": "^6.1.1",
|
||||
"rollup-plugin-rm": "^1.0.2",
|
||||
"simple-git-hooks": "^2.11.1",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.24.7",
|
||||
"@babel/plugin-transform-arrow-functions": "^7.24.7",
|
||||
"cac": "^6.7.14",
|
||||
"esbuild": "^0.21.5",
|
||||
"magic-string": "^0.30.10",
|
||||
"picocolors": "^1.0.1"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user