feat: restart Electron after main or preload

update.
fix: preload config will error when preload
config is a function.
This commit is contained in:
xiaohui 2022-07-01 00:33:08 +08:00
parent e35552b4b6
commit f9cfcf9408
4 changed files with 162 additions and 62 deletions

View File

@ -18,6 +18,7 @@ English | [简体中文](./README.zh-CN.md)
- 📃Main process, renderer process and preload script Vite configuration combined into one file
- 📦Preset optimal build configuration
- 🚀HMR for renderer processes
- 🌈Restart Electron after `main` or `preload` update
## Usage
@ -162,7 +163,7 @@ See [vitejs.dev](https://vitejs.dev/config)
### Config presets
#### Build options for `main`:
#### Build options for `main`
- **outDir**: `out\main`(relative to project root)
- **target**: `node*`, automatically match node target of `Electron`. For example, the node target of Electron 17 is `node16.13`
@ -170,7 +171,7 @@ See [vitejs.dev](https://vitejs.dev/config)
- **lib.formats**: `cjs`
- **rollupOptions.external**: `electron` and all builtin modules
#### Build options for `preload`:
#### Build options for `preload`
- **outDir**: `out\preload`(relative to project root)
- **target**: the same as `main`
@ -178,7 +179,7 @@ See [vitejs.dev](https://vitejs.dev/config)
- **lib.formats**: `cjs`
- **rollupOptions.external**: the same as `main`
#### Build options for `renderer`:
#### Build options for `renderer`
- **root**: `src\renderer`(relative to project root)
- **outDir**: `out\renderer`(relative to project root)
@ -235,6 +236,28 @@ export default {
}
```
#### How to restart Electron after `main` or `preload` update
```js
export default defineConfig({
main: ({ command }) => ({
build: {
watch: command === 'serve' ? {} : undefined,
// ...
},
}),
preload: ({ command }) => ({
build: {
watch: command === 'serve' ? {} : undefined,
// ...
}
}),
renderer: {
// ...
}
})
```
## CLI options
For the full list of CLI options, you can run `npx electron-vite -h` in your project. The flags listed below are only available via the command line interface:

View File

@ -18,6 +18,7 @@
- 📃 统一所有配置,合并到一个文件中
- 📦 预设构建配置,无需关注配置
- 🚀 支持渲染进程热更新(HMR)
- 🌈 支持 `main` 更新后 Electron 重启和 `preload` 更新后重新挂载
## 用法
@ -162,7 +163,7 @@ export default defineConfig({
### 配置预设
#### `主进程`编译项预设
#### `主进程`编译项预设
- **outDir**`out\main`(相对于根目录)
- **target**`node*`,自动匹配 `Electron``node` 构建目标,如 Electron 17 为 `node16.13`
@ -170,7 +171,7 @@ export default defineConfig({
- **lib.formats**`cjs`
- **rollupOptions.external**`electron` 和所有内置 node 模块(如果用户配置了外部模块 ID将自动合并)
#### `preload` 脚本编译项预设
#### `preload` 脚本编译项预设
- **outDir**`out\preload`(相对于根目录)
- **target**:同`主进程`
@ -178,7 +179,7 @@ export default defineConfig({
- **lib.formats**`cjs`
- **rollupOptions.external**:同`主进程`
#### `渲染进程`编译项预设
#### `渲染进程`编译项预设
- **root**`src\renderer`(相对于根目录)
- **outDir**`out\renderer`(相对于根目录)
@ -187,7 +188,7 @@ export default defineConfig({
- **polyfillModulePreload**`false`,不需要为渲染进程 polyfill `Module Preload`
- **rollupOptions.external**:同`主进程`
#### `主进程``preload` 脚本的 `define` 项设置
#### `主进程``preload` 脚本的 `define` 项设置
在 Web 开发中Vite 会将 `'process.env.'` 替换为 `'({}).'`,这是合理和正确的。但在 nodejs 开发中,我们有时候需要使用 `process.env` ,所以 `electron-vite` 重新预设全局变量替换,恢复其使用,预设如下:
@ -235,6 +236,30 @@ export default {
}
```
#### 如何支持 `main` 更新后 Electron 重启和 `preload` 更新后重新挂载?
`serve` 命令下,`main``preload` 脚本更新后,你可能想要让 Electron 重启和 `preload` 重新挂载,你可以在配置中这样做:
```js
export default defineConfig({
main: ({ command }) => ({
build: {
watch: command === 'serve' ? {} : undefined,
// ...
},
}),
preload: ({ command }) => ({
build: {
watch: command === 'serve' ? {} : undefined,
// ...
}
}),
renderer: {
// ...
}
})
```
## 命令行选项
在项目中,可运行 `npx electron-vite -h` 获得完整的命令行选项列表。下面列出的标志只能通过命令行使用:

View File

@ -287,7 +287,7 @@ export async function loadConfigFromFile(
if (config.preload) {
const preloadViteConfig = config.preload
preloadConfig = await (typeof preloadViteConfig === 'function' ? preloadViteConfig(configEnv) : preloadViteConfig)
if (!isObject(preloadViteConfig)) {
if (!isObject(preloadConfig)) {
throw new Error(`preload config must export or return an object`)
}
} else {

View File

@ -1,34 +1,51 @@
import { spawn } from 'child_process'
import { createServer as ViteCreateServer, build as viteBuild, createLogger } from 'vite'
import { ChildProcessWithoutNullStreams, spawn } from 'child_process'
import {
createServer as ViteCreateServer,
build as viteBuild,
createLogger,
Logger,
ViteDevServer,
UserConfig,
mergeConfig
} from 'vite'
import colors from 'picocolors'
import { InlineConfig, resolveConfig } from './config'
import { ensureElectronEntryFile, getElectronPath, resolveHostname } from './utils'
import { PluginHooks } from 'rollup'
export async function createServer(inlineConfig: InlineConfig = {}): Promise<void> {
const config = await resolveConfig(inlineConfig, 'serve', 'development')
if (config.config) {
const logger = createLogger(inlineConfig.logLevel)
export function createElectron(root?: string, logger?: Logger): ChildProcessWithoutNullStreams {
ensureElectronEntryFile(root)
const electronPath = getElectronPath()
const ps = spawn(electronPath, ['.'])
const mainViteConfig = config.config?.main
if (mainViteConfig) {
await viteBuild(mainViteConfig)
ps.stdout.on('data', chunk => {
chunk.toString().trim() && logger && logger.info(chunk.toString())
})
ps.stderr.on('data', chunk => {
chunk.toString().trim() && logger && logger.error(chunk.toString())
})
ps.on('close', process.exit)
logger.info(colors.green(`\nbuild the electron main process successfully`))
return ps
}
export function build(config: UserConfig, closeBundle?: PluginHooks['closeBundle']): ReturnType<typeof viteBuild> {
const watchConfig: UserConfig = {
// Enable watch through `electron.vite.config.{ js | ts | mjs }`
// build: { watch: {} },
plugins: [
{
name: 'vite:electron-serve-build',
closeBundle
}
]
}
const preloadViteConfig = config.config?.preload
if (preloadViteConfig) {
logger.info(colors.gray(`\n-----\n`))
await viteBuild(preloadViteConfig)
return viteBuild(mergeConfig(watchConfig, config))
}
logger.info(colors.green(`\nbuild the electron preload files successfully`))
}
const rendererViteConfig = config.config?.renderer
if (rendererViteConfig) {
logger.info(colors.gray(`\n-----\n`))
const server = await ViteCreateServer(rendererViteConfig)
export async function createRenderServer(config: UserConfig): Promise<ViteDevServer> {
const server = await ViteCreateServer(config)
if (!server.httpServer) {
throw new Error('HTTP server not available')
@ -37,7 +54,6 @@ export async function createServer(inlineConfig: InlineConfig = {}): Promise<voi
await server.listen()
const conf = server.config.server
const protocol = conf.https ? 'https:' : 'http:'
const host = resolveHostname(conf.host)
const port = conf.port
@ -50,21 +66,57 @@ export async function createServer(inlineConfig: InlineConfig = {}): Promise<voi
})
server.printUrls()
}
ensureElectronEntryFile(inlineConfig.root)
const electronPath = getElectronPath()
const ps = spawn(electronPath, ['.'])
ps.stdout.on('data', chunk => {
chunk.toString().trim() && logger.info(chunk.toString())
})
ps.stderr.on('data', chunk => {
chunk.toString().trim() && logger.error(chunk.toString())
})
ps.on('close', process.exit)
logger.info(colors.green(`\nstart electron app...`))
}
return server
}
export async function createServer(inlineConfig: InlineConfig = {}): Promise<void> {
const config = await resolveConfig(inlineConfig, 'serve', 'development')
const { main, preload, renderer } = config.config || {}
const logger = createLogger(inlineConfig.logLevel)
let server: ViteDevServer | undefined
let ps: ChildProcessWithoutNullStreams | undefined
if (main) {
await build(main, () => {
logger.info(colors.green(`\nbuild the electron main process successfully`))
if (ps) {
logger.info(colors.green(`\nwaiting for electron to exit...`))
ps.removeAllListeners()
ps.kill()
ps = createElectron(inlineConfig.root, logger)
logger.info(colors.green(`\n🚀 restart electron app...`))
}
})
}
if (preload) {
logger.info(colors.gray(`\n-----\n`))
await build(preload, () => {
logger.info(colors.green(`\nbuild the electron preload files successfully`))
if (server) {
logger.info(colors.green(`\nwaiting for render page to reload...`))
server.ws.send({ type: 'full-reload' })
logger.info(colors.green(`\nreload render page successfully`))
}
})
}
if (renderer) {
logger.info(colors.gray(`\n-----\n`))
server = await createRenderServer(renderer)
}
ps = createElectron(inlineConfig.root, logger)
logger.info(colors.green(`\n🚀 start electron app...`))
}