mirror of
https://github.com/alex8088/electron-vite.git
synced 2025-11-09 22:16:01 +08:00
feat: add isolatedEntries option for preload and renderer to build entries as standalone bundles #154
This commit is contained in:
parent
c3939ade45
commit
0a79da03db
@ -21,10 +21,37 @@ import workerPlugin from './plugins/worker'
|
||||
import importMetaPlugin from './plugins/importMeta'
|
||||
import esmShimPlugin from './plugins/esmShim'
|
||||
import modulePathPlugin from './plugins/modulePath'
|
||||
import isolateEntriesPlugin from './plugins/isolateEntries'
|
||||
import { isObject, isFilePathESM } from './utils'
|
||||
|
||||
export { defineConfig as defineViteConfig } from 'vite'
|
||||
|
||||
interface ElectronVitePreloadConfig {
|
||||
/**
|
||||
* Build each entry point as an isolated bundle without code splitting.
|
||||
*
|
||||
* When enabled, each entry will include all its dependencies inline,
|
||||
* preventing automatic code splitting across entries and ensuring each
|
||||
* output file is fully standalone.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
isolatedEntries?: boolean
|
||||
}
|
||||
|
||||
interface ElectronViteRendererConfig {
|
||||
/**
|
||||
* Build each entry point as an isolated bundle without code splitting.
|
||||
*
|
||||
* When enabled, each entry will include all its dependencies inline,
|
||||
* preventing automatic code splitting across entries and ensuring each
|
||||
* output file is fully standalone.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
isolatedEntries?: boolean
|
||||
}
|
||||
|
||||
export interface UserConfig {
|
||||
/**
|
||||
* Vite config options for electron main process
|
||||
@ -37,13 +64,13 @@ export interface UserConfig {
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
renderer?: ViteConfig & { configFile?: string | false }
|
||||
renderer?: ViteConfig & { configFile?: string | false } & ElectronViteRendererConfig
|
||||
/**
|
||||
* Vite config options for electron preload files
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
preload?: ViteConfig & { configFile?: string | false }
|
||||
preload?: ViteConfig & { configFile?: string | false } & ElectronVitePreloadConfig
|
||||
}
|
||||
|
||||
export interface ElectronViteConfig {
|
||||
@ -58,13 +85,13 @@ export interface ElectronViteConfig {
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
renderer?: ViteConfigExport
|
||||
renderer?: ViteConfigExport & ElectronViteRendererConfig
|
||||
/**
|
||||
* Vite config options for electron preload files
|
||||
*
|
||||
* https://vitejs.dev/config/
|
||||
*/
|
||||
preload?: ViteConfigExport
|
||||
preload?: ViteConfigExport & ElectronVitePreloadConfig
|
||||
}
|
||||
|
||||
export type InlineConfig = Omit<ViteConfig, 'base'> & {
|
||||
@ -167,7 +194,10 @@ export async function resolveConfig(
|
||||
}
|
||||
|
||||
if (loadResult.config.preload) {
|
||||
const preloadViteConfig: ViteConfig = mergeConfig(loadResult.config.preload, deepClone(config))
|
||||
const preloadViteConfig: ViteConfig & ElectronVitePreloadConfig = mergeConfig(
|
||||
loadResult.config.preload,
|
||||
deepClone(config)
|
||||
)
|
||||
|
||||
preloadViteConfig.mode = inlineConfig.mode || preloadViteConfig.mode || defaultMode
|
||||
|
||||
@ -178,7 +208,24 @@ export async function resolveConfig(
|
||||
...electronPreloadVitePlugin({ root }),
|
||||
assetPlugin(),
|
||||
importMetaPlugin(),
|
||||
esmShimPlugin()
|
||||
esmShimPlugin(),
|
||||
...(preloadViteConfig.isolatedEntries
|
||||
? [
|
||||
isolateEntriesPlugin(
|
||||
mergeConfig(
|
||||
{
|
||||
plugins: [
|
||||
electronPreloadVitePlugin({ root })[0],
|
||||
assetPlugin(),
|
||||
importMetaPlugin(),
|
||||
esmShimPlugin()
|
||||
]
|
||||
},
|
||||
preloadViteConfig
|
||||
)
|
||||
)
|
||||
]
|
||||
: [])
|
||||
])
|
||||
|
||||
loadResult.config.preload = preloadViteConfig
|
||||
@ -186,7 +233,10 @@ export async function resolveConfig(
|
||||
}
|
||||
|
||||
if (loadResult.config.renderer) {
|
||||
const rendererViteConfig: ViteConfig = mergeConfig(loadResult.config.renderer, deepClone(config))
|
||||
const rendererViteConfig: ViteConfig & ElectronViteRendererConfig = mergeConfig(
|
||||
loadResult.config.renderer,
|
||||
deepClone(config)
|
||||
)
|
||||
|
||||
rendererViteConfig.mode = inlineConfig.mode || rendererViteConfig.mode || defaultMode
|
||||
|
||||
@ -194,7 +244,21 @@ export async function resolveConfig(
|
||||
resetOutDir(rendererViteConfig, outDir, 'renderer')
|
||||
}
|
||||
|
||||
mergePlugins(rendererViteConfig, electronRendererVitePlugin({ root }))
|
||||
mergePlugins(rendererViteConfig, [
|
||||
...electronRendererVitePlugin({ root }),
|
||||
...(rendererViteConfig.isolatedEntries
|
||||
? [
|
||||
isolateEntriesPlugin(
|
||||
mergeConfig(
|
||||
{
|
||||
plugins: [electronRendererVitePlugin({ root })[0]]
|
||||
},
|
||||
rendererViteConfig
|
||||
)
|
||||
)
|
||||
]
|
||||
: [])
|
||||
])
|
||||
|
||||
loadResult.config.renderer = rendererViteConfig
|
||||
loadResult.config.renderer.configFile = false
|
||||
|
||||
148
src/plugins/isolateEntries.ts
Normal file
148
src/plugins/isolateEntries.ts
Normal file
@ -0,0 +1,148 @@
|
||||
import { type InlineConfig, type Plugin, type Logger, build as viteBuild, mergeConfig } from 'vite'
|
||||
import type { InputOptions, RollupOutput } from 'rollup'
|
||||
import colors from 'picocolors'
|
||||
|
||||
const VIRTUAL_ENTRY_ID = '\0virtual:isolate-entries'
|
||||
|
||||
export default function isolateEntriesPlugin(userConfig: InlineConfig): Plugin {
|
||||
let logger: Logger
|
||||
|
||||
let entries: string[] | Record<string, string>
|
||||
let transformedCount = 0
|
||||
|
||||
const assetCache = new Set<string>()
|
||||
|
||||
return {
|
||||
name: 'vite:isolate-entries',
|
||||
apply: 'build',
|
||||
configResolved(config): void {
|
||||
logger = config.logger
|
||||
},
|
||||
options(opts): InputOptions | void {
|
||||
const { input } = opts
|
||||
if (input && typeof input === 'object') {
|
||||
if ((Array.isArray(input) && input.length > 0) || Object.keys(input).length > 1) {
|
||||
opts.input = VIRTUAL_ENTRY_ID
|
||||
entries = input
|
||||
return opts
|
||||
}
|
||||
}
|
||||
},
|
||||
buildStart(): void {
|
||||
transformedCount = 0
|
||||
assetCache.clear()
|
||||
},
|
||||
resolveId(id): string | null {
|
||||
if (id === VIRTUAL_ENTRY_ID) {
|
||||
return id
|
||||
}
|
||||
return null
|
||||
},
|
||||
async load(id): Promise<string | void> {
|
||||
if (id === VIRTUAL_ENTRY_ID) {
|
||||
const _entries = Array.isArray(entries)
|
||||
? entries
|
||||
: Object.entries(entries).map(([key, value]) => ({ [key]: value }))
|
||||
const watchFiles = new Set<string>()
|
||||
for (const entry of _entries) {
|
||||
const re = await bundleEntryFile(entry, userConfig, this.meta.watchMode)
|
||||
const outputChunks = re.bundles.output
|
||||
for (const chunk of outputChunks) {
|
||||
if (chunk.type === 'asset' && assetCache.has(chunk.fileName)) {
|
||||
continue
|
||||
}
|
||||
this.emitFile({
|
||||
type: 'asset',
|
||||
fileName: chunk.fileName,
|
||||
source: chunk.type === 'chunk' ? chunk.code : chunk.source
|
||||
})
|
||||
if (chunk.type === 'asset') {
|
||||
assetCache.add(chunk.fileName)
|
||||
}
|
||||
}
|
||||
for (const id of re.watchFiles) {
|
||||
watchFiles.add(id)
|
||||
}
|
||||
transformedCount += re.transformedCount
|
||||
}
|
||||
for (const id of watchFiles) {
|
||||
this.addWatchFile(id)
|
||||
}
|
||||
return `
|
||||
// This is the virtual entry file
|
||||
console.log(1)`
|
||||
}
|
||||
},
|
||||
renderStart(): void {
|
||||
clearLine()
|
||||
logger.info(`${colors.green(`✓`)} ${transformedCount} modules transformed.`)
|
||||
},
|
||||
generateBundle(_, bundle): void {
|
||||
for (const chunkName in bundle) {
|
||||
if (chunkName.includes('virtual_isolate-entries')) {
|
||||
delete bundle[chunkName]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function bundleEntryFile(
|
||||
input: string | Record<string, string>,
|
||||
config: InlineConfig,
|
||||
watch: boolean
|
||||
): Promise<{ bundles: RollupOutput; watchFiles: string[]; transformedCount: number }> {
|
||||
const moduleIds: string[] = []
|
||||
let transformedCount = 0
|
||||
|
||||
const viteConfig = mergeConfig(config, {
|
||||
build: {
|
||||
write: false,
|
||||
watch: false
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
name: 'vite:transform-counter',
|
||||
transform(): void {
|
||||
transformedCount++
|
||||
}
|
||||
} as Plugin,
|
||||
...(watch
|
||||
? [
|
||||
{
|
||||
name: 'vite:get-watch-files',
|
||||
buildEnd(): void {
|
||||
const allModuleIds = Array.from(this.getModuleIds())
|
||||
|
||||
const sourceFiles = allModuleIds.filter(id => {
|
||||
const info = this.getModuleInfo(id)
|
||||
return info && !info.isExternal
|
||||
})
|
||||
|
||||
moduleIds.push(...sourceFiles)
|
||||
}
|
||||
} as Plugin
|
||||
]
|
||||
: [])
|
||||
],
|
||||
logLevel: 'warn',
|
||||
configFile: false
|
||||
}) as InlineConfig
|
||||
|
||||
// rewrite the input instead of merging
|
||||
viteConfig.build!.rollupOptions!.input = input
|
||||
|
||||
const bundles = await viteBuild(viteConfig)
|
||||
|
||||
return {
|
||||
bundles: bundles as RollupOutput,
|
||||
watchFiles: moduleIds,
|
||||
transformedCount
|
||||
}
|
||||
}
|
||||
|
||||
function clearLine(): void {
|
||||
process.stdout.moveCursor(0, -1)
|
||||
process.stdout.clearLine(0)
|
||||
process.stdout.cursorTo(0)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user