mirror of
https://github.com/alex8088/electron-vite.git
synced 2025-11-10 22:43:34 +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 importMetaPlugin from './plugins/importMeta'
|
||||||
import esmShimPlugin from './plugins/esmShim'
|
import esmShimPlugin from './plugins/esmShim'
|
||||||
import modulePathPlugin from './plugins/modulePath'
|
import modulePathPlugin from './plugins/modulePath'
|
||||||
|
import isolateEntriesPlugin from './plugins/isolateEntries'
|
||||||
import { isObject, isFilePathESM } from './utils'
|
import { isObject, isFilePathESM } from './utils'
|
||||||
|
|
||||||
export { defineConfig as defineViteConfig } from 'vite'
|
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 {
|
export interface UserConfig {
|
||||||
/**
|
/**
|
||||||
* Vite config options for electron main process
|
* Vite config options for electron main process
|
||||||
@ -37,13 +64,13 @@ export interface UserConfig {
|
|||||||
*
|
*
|
||||||
* https://vitejs.dev/config/
|
* https://vitejs.dev/config/
|
||||||
*/
|
*/
|
||||||
renderer?: ViteConfig & { configFile?: string | false }
|
renderer?: ViteConfig & { configFile?: string | false } & ElectronViteRendererConfig
|
||||||
/**
|
/**
|
||||||
* Vite config options for electron preload files
|
* Vite config options for electron preload files
|
||||||
*
|
*
|
||||||
* https://vitejs.dev/config/
|
* https://vitejs.dev/config/
|
||||||
*/
|
*/
|
||||||
preload?: ViteConfig & { configFile?: string | false }
|
preload?: ViteConfig & { configFile?: string | false } & ElectronVitePreloadConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ElectronViteConfig {
|
export interface ElectronViteConfig {
|
||||||
@ -58,13 +85,13 @@ export interface ElectronViteConfig {
|
|||||||
*
|
*
|
||||||
* https://vitejs.dev/config/
|
* https://vitejs.dev/config/
|
||||||
*/
|
*/
|
||||||
renderer?: ViteConfigExport
|
renderer?: ViteConfigExport & ElectronViteRendererConfig
|
||||||
/**
|
/**
|
||||||
* Vite config options for electron preload files
|
* Vite config options for electron preload files
|
||||||
*
|
*
|
||||||
* https://vitejs.dev/config/
|
* https://vitejs.dev/config/
|
||||||
*/
|
*/
|
||||||
preload?: ViteConfigExport
|
preload?: ViteConfigExport & ElectronVitePreloadConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InlineConfig = Omit<ViteConfig, 'base'> & {
|
export type InlineConfig = Omit<ViteConfig, 'base'> & {
|
||||||
@ -167,7 +194,10 @@ export async function resolveConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (loadResult.config.preload) {
|
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
|
preloadViteConfig.mode = inlineConfig.mode || preloadViteConfig.mode || defaultMode
|
||||||
|
|
||||||
@ -178,7 +208,24 @@ export async function resolveConfig(
|
|||||||
...electronPreloadVitePlugin({ root }),
|
...electronPreloadVitePlugin({ root }),
|
||||||
assetPlugin(),
|
assetPlugin(),
|
||||||
importMetaPlugin(),
|
importMetaPlugin(),
|
||||||
|
esmShimPlugin(),
|
||||||
|
...(preloadViteConfig.isolatedEntries
|
||||||
|
? [
|
||||||
|
isolateEntriesPlugin(
|
||||||
|
mergeConfig(
|
||||||
|
{
|
||||||
|
plugins: [
|
||||||
|
electronPreloadVitePlugin({ root })[0],
|
||||||
|
assetPlugin(),
|
||||||
|
importMetaPlugin(),
|
||||||
esmShimPlugin()
|
esmShimPlugin()
|
||||||
|
]
|
||||||
|
},
|
||||||
|
preloadViteConfig
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
: [])
|
||||||
])
|
])
|
||||||
|
|
||||||
loadResult.config.preload = preloadViteConfig
|
loadResult.config.preload = preloadViteConfig
|
||||||
@ -186,7 +233,10 @@ export async function resolveConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (loadResult.config.renderer) {
|
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
|
rendererViteConfig.mode = inlineConfig.mode || rendererViteConfig.mode || defaultMode
|
||||||
|
|
||||||
@ -194,7 +244,21 @@ export async function resolveConfig(
|
|||||||
resetOutDir(rendererViteConfig, outDir, 'renderer')
|
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 = rendererViteConfig
|
||||||
loadResult.config.renderer.configFile = false
|
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