mirror of
https://github.com/alex8088/electron-vite.git
synced 2026-11-03 07:05:32 +08:00
134 lines
4.0 KiB
TypeScript
134 lines
4.0 KiB
TypeScript
import path from 'node:path'
|
|
import { type Plugin, type InlineConfig, build as viteBuild, mergeConfig } from 'vite'
|
|
import type { SourceMapInput, RollupOutput, OutputOptions } from 'rollup'
|
|
import MagicString from 'magic-string'
|
|
import { cleanUrl, toRelativePath } from '../utils'
|
|
import { supportImportMetaPaths } from '../electron'
|
|
|
|
const modulePathRE = /__VITE_MODULE_PATH__([\w$]+)__/g
|
|
|
|
/**
|
|
* Resolve `?modulePath` import and return the module bundle path.
|
|
*/
|
|
export default function modulePathPlugin(config: InlineConfig): Plugin {
|
|
const isImportMetaPathSupported = supportImportMetaPaths()
|
|
const assetCache = new Set<string>()
|
|
return {
|
|
name: 'vite:module-path',
|
|
apply: 'build',
|
|
enforce: 'pre',
|
|
buildStart(): void {
|
|
assetCache.clear()
|
|
},
|
|
async load(id): Promise<string | void> {
|
|
if (id.endsWith('?modulePath')) {
|
|
// id resolved by Vite resolve plugin
|
|
const re = await bundleEntryFile(cleanUrl(id), config, this.meta.watchMode)
|
|
const [outputChunk, ...outputChunks] = re.bundles.output
|
|
const hash = this.emitFile({
|
|
type: 'asset',
|
|
fileName: outputChunk.fileName,
|
|
source: outputChunk.code
|
|
})
|
|
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) {
|
|
this.addWatchFile(id)
|
|
}
|
|
const refId = `__VITE_MODULE_PATH__${hash}__`
|
|
const dirnameExpr = isImportMetaPathSupported ? 'import.meta.dirname' : '__dirname'
|
|
return `
|
|
import { join } from 'path'
|
|
export default join(${dirnameExpr}, ${refId})`
|
|
}
|
|
},
|
|
renderChunk(code, chunk, { sourcemap }): { code: string; map: SourceMapInput } | null {
|
|
let match: RegExpExecArray | null
|
|
let s: MagicString | undefined
|
|
|
|
modulePathRE.lastIndex = 0
|
|
while ((match = modulePathRE.exec(code))) {
|
|
s ||= new MagicString(code)
|
|
const [full, hash] = match
|
|
const filename = this.getFileName(hash)
|
|
const outputFilepath = toRelativePath(filename, chunk.fileName)
|
|
const replacement = JSON.stringify(outputFilepath)
|
|
s.overwrite(match.index, match.index + full.length, replacement, {
|
|
contentOnly: true
|
|
})
|
|
}
|
|
|
|
if (s) {
|
|
return {
|
|
code: s.toString(),
|
|
map: sourcemap ? s.generateMap({ hires: 'boundary' }) : null
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
|
|
async function bundleEntryFile(
|
|
input: string,
|
|
config: InlineConfig,
|
|
watch: boolean
|
|
): Promise<{ bundles: RollupOutput; watchFiles: string[] }> {
|
|
const moduleIds: string[] = []
|
|
const viteConfig = mergeConfig(config, {
|
|
build: {
|
|
rollupOptions: { input },
|
|
write: false,
|
|
watch: false
|
|
},
|
|
plugins: [
|
|
{
|
|
name: 'vite:entry-file-name',
|
|
outputOptions(output): OutputOptions {
|
|
if (typeof output.entryFileNames !== 'function' && output.entryFileNames) {
|
|
output.entryFileNames = '[name]-[hash]' + path.extname(output.entryFileNames)
|
|
}
|
|
return output
|
|
}
|
|
},
|
|
...(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
|
|
})
|
|
const bundles = await viteBuild(viteConfig)
|
|
|
|
return {
|
|
bundles: bundles as RollupOutput,
|
|
watchFiles: moduleIds
|
|
}
|
|
}
|