refactor: build based vite alternative rollup

This commit is contained in:
草鞋没号 2021-11-08 19:16:16 +08:00
parent 27a059e5dd
commit 2273453449
8 changed files with 126 additions and 277 deletions

40
scripts/build.mjs Normal file
View File

@ -0,0 +1,40 @@
process.env.NODE_ENV = 'production'
import { build as viteBuild } from 'vite'
import { build as electronBuild2 } from 'electron-builder'
import { config as builderConfig } from './electron-builder.config.mjs'
import chalk from 'chalk'
const TAG = chalk.bgBlue('[build.mjs]')
const viteConfigs = {
main: 'src/main/vite.config.ts',
preload: 'src/preload/vite.config.ts',
reactTs: 'src/react-ts/vite.config.ts',
}
async function buildElectron() {
for (const [name, configPath] of Object.entries(viteConfigs)) {
console.group(TAG, name)
await viteBuild({ configFile: configPath, mode: process.env.NODE_ENV })
console.groupEnd()
console.log() // for beautiful log.
}
}
async function packElectron() {
return electronBuild2({ config: builderConfig })
.then(result => {
console.log(TAG, chalk.green(`electron-builder.build result - ${result}`))
})
}
; (async () => {
try {
await buildElectron()
await packElectron()
} catch (error) {
console.error(error)
process.exit(1)
}
})()

View File

@ -1,76 +0,0 @@
process.env.NODE_ENV = 'production'
import { join, relative } from 'path'
import { build as viteBuild2 } from 'vite'
import { build as electronBuild2 } from 'electron-builder'
import { rollup, RollupOptions, OutputOptions, RollupOutput } from 'rollup'
import { config as builderConfig } from './electron-builder.config'
import chalk from 'chalk'
import {
mainOptions,
preloadOptions,
BuildResult,
} from './utils'
const TAG = chalk.bgGray('[build.ts]')
// build main、preload
async function rollupBuild(options: RollupOptions): Promise<BuildResult> {
try {
const build = await rollup(options)
const optOutput = (options.output || {}) as OutputOptions
const output = await build.write(optOutput)
output.output.forEach(out => {
const relativePath = relative(__dirname, optOutput.dir as string)
console.log(TAG, chalk.green(`Build successful - ${join(relativePath, out.fileName)}`))
})
return [null, output]
} catch (error: any) {
console.error(TAG, chalk.red('Build failed:\n'), error)
return [error, null]
}
}
// build react-ts
async function buildReactTs(): Promise<BuildResult> {
try {
const output = await viteBuild2({
root: join(__dirname, '../react-ts'),
configFile: join(__dirname, '../react-ts/vite.config.ts'),
}) as RollupOutput
return [null, output]
} catch (error: any) {
return [error, null]
}
}
// build electron
async function electronBuild() {
try {
const result = await electronBuild2({ config: builderConfig })
console.log(TAG, chalk.green(`electron-builder.build result - ${result}`))
return [null, result]
} catch (error) {
return [error, null]
}
}
; (async () => {
console.log(TAG, chalk.blue('Build with rollup.'))
try {
await Promise.all([
// Avoid logs cleaned by vite
rollupBuild(mainOptions()),
rollupBuild(preloadOptions()),
])
await buildReactTs()
await electronBuild()
} catch (error) {
console.error(TAG, chalk.red(error))
process.exit(1)
}
})();

View File

@ -1,80 +0,0 @@
process.env.NODE_ENV = 'development'
import { join } from 'path'
import electron from 'electron'
import { spawn, ChildProcess } from 'child_process'
import { createServer as createViteServer } from 'vite'
import { RollupWatcher, RollupWatcherEvent, watch } from 'rollup'
import WebSocket from 'ws'
import chalk from 'chalk'
import pkg from '../package.json'
import {
mainOptions,
preloadOptions,
} from './utils'
import { createWsServer, formatWsSendData } from './ws'
const TAG = chalk.bgGray('[dev.ts]')
function eventHandle(ev: RollupWatcherEvent) {
if (ev.code === 'ERROR') {
console.error(TAG, chalk.red(ev.error))
} else if (ev.code === 'BUNDLE_START') {
console.log(TAG, chalk.blue(`Rebuild - ${ev.output}`))
}
}
function watchMain(): RollupWatcher {
let electronProcess: ChildProcess | null = null
return watch(mainOptions())
.on('event', ev => {
if (ev.code === 'END') {
electronProcess && electronProcess.kill()
electronProcess = spawn(
electron as unknown as string,
[join(__dirname, '..', pkg.main)],
{ stdio: 'inherit', env: Object.assign(process.env, pkg.env) },
)
} else if (ev.code === 'ERROR') {
electronProcess && electronProcess.kill()
electronProcess = null
}
eventHandle(ev)
})
}
function watchPreload(): RollupWatcher {
const wssObj = createWsServer({ TAG })
return watch(preloadOptions())
.on('event', ev => {
if (ev.code === 'END') {
// Hot reload renderer process !!!
if (wssObj.instance?.readyState === WebSocket.OPEN) {
console.log(TAG, chalk.yellow('Hot reload renderer process'))
wssObj.instance.send(formatWsSendData({ cmd: 'reload', data: Date.now() }))
}
}
eventHandle(ev)
})
}
; (async () => {
try {
const server = await (await createViteServer({
root: join(__dirname, '../react-ts'),
configFile: join(__dirname, '../react-ts/vite.config.ts'),
})).listen()
const { host = '127.0.0.1', port = 3000 } = server.config.server
console.log(TAG, chalk.yellow(`Server run at - http://${host}:${port}`))
watchPreload()
watchMain()
} catch (error) {
console.error(TAG, chalk.red(error))
}
})();

View File

@ -1,14 +1,16 @@
import { Configuration } from 'electron-builder'
const config: Configuration = {
/**
* @type {import('electron-builder').Configuration}
*/
const config = {
appId: "308487730@qq.com",
asar: true,
directories: {
output: "release/${version}"
},
files: [
"!node_modules",
"dist/**"
"dist",
"package.json"
],
mac: {
artifactName: "${productName}_${version}.${ext}",

View File

@ -1,41 +0,0 @@
import { builtinModules } from 'module'
import { RollupOptions } from 'rollup'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import typescript from '@rollup/plugin-typescript'
import commonjs from '@rollup/plugin-commonjs'
import replace from '@rollup/plugin-replace'
// import swc from 'rollup-plugin-swc'
function optionsFactory(options: RollupOptions): RollupOptions {
return {
input: options.input,
output: {
name: '[name].js',
format: 'cjs',
...options.output,
},
plugins: [
commonjs(),
nodeResolve({
extensions: ['.ts', '.js', 'json'],
}),
typescript(),
// swc(), Error: Cannot find module 'regenerator-runtime',
replace({
...Object
.entries({ NODE_ENV: process.env.NODE_ENV })
.reduce(
(acc, [k, v]) => Object.assign(acc, { [`process.env.${k}`]: JSON.stringify(v) }),
{},
),
preventAssignment: true,
}),
],
external: [
'electron',
...builtinModules,
],
}
}
export { optionsFactory }

View File

@ -1,33 +0,0 @@
import { join } from 'path'
import { readdirSync } from 'fs'
import { OutputOptions, rollup, RollupOptions, RollupOutput, RollupError } from 'rollup'
import { optionsFactory } from './rollup.config'
export type BuildResult = [RollupError | null, RollupOutput | null]
function mainOptions(): RollupOptions {
return optionsFactory({
input: join(__dirname, '../main/index.ts'),
output: {
dir: 'dist/main',
},
})
}
function preloadOptions(): RollupOptions {
const dirs = readdirSync(join(__dirname, '../preload'))
const inputs = dirs.filter(name => /^index\..+\.ts$/.test(name))
return optionsFactory({
input: inputs.map(input => join(__dirname, '../preload', input)),
output: {
dir: 'dist/preload',
},
})
}
export {
mainOptions,
preloadOptions,
}

80
scripts/watch.mjs Normal file
View File

@ -0,0 +1,80 @@
process.env.NODE_ENV = 'production'
import { readFileSync } from 'fs'
import { join } from 'path'
import electron from 'electron'
import { spawn } from 'child_process'
import { createServer, build as viteBuild } from 'vite'
import chalk from 'chalk'
const TAG = chalk.bgGreen('[dev.mjs]')
const pkg = JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf8'))
/**
* @param {{ name: string; configFile: string; writeBundle: import('rollup').OutputPlugin['writeBundle'] }} param0
* @returns {import('rollup').RollupWatcher}
*/
function getWatcher({ name, configFile, writeBundle }) {
return viteBuild({
// Options here precedence over configFile
build: {
watch: {},
},
configFile,
plugins: [
{ name, writeBundle },
],
})
}
/**
* @returns {Promise<import('rollup').RollupWatcher>}
*/
async function watchMain() {
/**
* @type {import('child_process').ChildProcessWithoutNullStreams | null}
*/
let electronProcess = null
/**
* @type {import('rollup').RollupWatcher}
*/
const watcher = await getWatcher({
name: 'electron-main-watcher',
configFile: 'src/main/vite.config.ts',
writeBundle() {
electronProcess && electronProcess.kill()
electronProcess = spawn(electron, ['.'], {
stdio: 'inherit',
env: Object.assign(process.env, pkg.env), // Why don't work?
})
},
})
return watcher
}
/**
* @param {import('vite').ViteDevServer} viteDevServer
* @returns {Promise<import('rollup').RollupWatcher>}
*/
async function watchPreload(viteDevServer) {
return getWatcher({
name: 'electron-preload-watcher',
configFile: 'src/preload/vite.config.ts',
writeBundle() {
viteDevServer.ws.send({
type: 'full-reload',
})
},
})
}
; (async () => {
const viteDevServer = await createServer({ configFile: 'src/react-ts/vite.config.ts' })
await viteDevServer.listen()
await watchPreload(viteDevServer)
await watchMain()
})()

View File

@ -1,43 +0,0 @@
/**
* Hot reload from preload script during development
*/
import WebSocket from 'ws'
import chalk from 'chalk'
import pkg from '../package.json'
export interface CreateWsServerOptions {
TAG: string
}
export function createWsServer(options: CreateWsServerOptions) {
const { TAG } = options
const port = pkg.env.PORT_WS
const host = pkg.env.HOST || '127.0.0.1'
const wss = new WebSocket.Server({ host, port })
const wssObj: { wss: WebSocket.Server; instance: WebSocket | null } = { wss, instance: null }
console.log(TAG, 'Wss run at - ' + chalk.yellow(`ws://${host}:${port}`))
wss.on('connection', ws => {
console.log(TAG, chalk.yellow(`wss.on('connection')`))
wssObj.instance = ws
ws.on('message', message => {
console.log(TAG, `ws.on('message'):`, message.toString())
})
ws.send(formatWsSendData({ cmd: 'message', data: 'connected.' }))
})
wss.on('close', () => {
console.log(TAG, chalk.gray(`wss.on('close')`))
wssObj.instance = null
})
return wssObj
}
export function formatWsSendData(json: { cmd: string, data?: any }) {
return JSON.stringify(json)
}