feat: support ESM in Electron
This commit is contained in:
parent
cb58ef8649
commit
c1e1ca0471
|
@ -18,6 +18,7 @@ import { build } from 'esbuild'
|
||||||
import { electronMainVitePlugin, electronPreloadVitePlugin, electronRendererVitePlugin } from './plugins/electron'
|
import { electronMainVitePlugin, electronPreloadVitePlugin, electronRendererVitePlugin } from './plugins/electron'
|
||||||
import assetPlugin from './plugins/asset'
|
import assetPlugin from './plugins/asset'
|
||||||
import workerPlugin from './plugins/worker'
|
import workerPlugin from './plugins/worker'
|
||||||
|
import esmShimPlugin from './plugins/esm'
|
||||||
import { isObject, dynamicImport } from './utils'
|
import { isObject, dynamicImport } from './utils'
|
||||||
|
|
||||||
export { defineConfig as defineViteConfig } from 'vite'
|
export { defineConfig as defineViteConfig } from 'vite'
|
||||||
|
@ -131,7 +132,12 @@ export async function resolveConfig(
|
||||||
resetOutDir(mainViteConfig, outDir, 'main')
|
resetOutDir(mainViteConfig, outDir, 'main')
|
||||||
}
|
}
|
||||||
|
|
||||||
mergePlugins(mainViteConfig, [...electronMainVitePlugin({ root }), assetPlugin(), workerPlugin()])
|
mergePlugins(mainViteConfig, [
|
||||||
|
...electronMainVitePlugin({ root }),
|
||||||
|
assetPlugin(),
|
||||||
|
workerPlugin(),
|
||||||
|
esmShimPlugin()
|
||||||
|
])
|
||||||
|
|
||||||
loadResult.config.main = mainViteConfig
|
loadResult.config.main = mainViteConfig
|
||||||
loadResult.config.main.configFile = false
|
loadResult.config.main.configFile = false
|
||||||
|
@ -143,7 +149,7 @@ export async function resolveConfig(
|
||||||
if (outDir) {
|
if (outDir) {
|
||||||
resetOutDir(preloadViteConfig, outDir, 'preload')
|
resetOutDir(preloadViteConfig, outDir, 'preload')
|
||||||
}
|
}
|
||||||
mergePlugins(preloadViteConfig, [...electronPreloadVitePlugin({ root }), assetPlugin()])
|
mergePlugins(preloadViteConfig, [...electronPreloadVitePlugin({ root }), assetPlugin(), esmShimPlugin()])
|
||||||
|
|
||||||
loadResult.config.preload = preloadViteConfig
|
loadResult.config.preload = preloadViteConfig
|
||||||
loadResult.config.preload.configFile = false
|
loadResult.config.preload.configFile = false
|
||||||
|
|
|
@ -36,6 +36,11 @@ const getElectronMajorVer = (): string => {
|
||||||
return majorVer
|
return majorVer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function supportESM(): boolean {
|
||||||
|
const majorVer = getElectronMajorVer()
|
||||||
|
return parseInt(majorVer) >= 28
|
||||||
|
}
|
||||||
|
|
||||||
export function getElectronPath(): string {
|
export function getElectronPath(): string {
|
||||||
let electronExecPath = process.env.ELECTRON_EXEC_PATH || ''
|
let electronExecPath = process.env.ELECTRON_EXEC_PATH || ''
|
||||||
if (!electronExecPath) {
|
if (!electronExecPath) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { toRelativePath } from '../utils'
|
||||||
const _require = createRequire(import.meta.url)
|
const _require = createRequire(import.meta.url)
|
||||||
|
|
||||||
function getBytecodeCompilerPath(): string {
|
function getBytecodeCompilerPath(): string {
|
||||||
return path.join(path.dirname(_require.resolve('electron-vite/package.json')), 'bin', 'electron-bytecode.js')
|
return path.join(path.dirname(_require.resolve('electron-vite/package.json')), 'bin', 'electron-bytecode.cjs')
|
||||||
}
|
}
|
||||||
|
|
||||||
function compileToBytecode(code: string): Promise<Buffer> {
|
function compileToBytecode(code: string): Promise<Buffer> {
|
||||||
|
@ -98,7 +98,7 @@ const bytecodeModuleLoaderCode = [
|
||||||
` ret |= buffer[0];`,
|
` ret |= buffer[0];`,
|
||||||
` return ret;`,
|
` return ret;`,
|
||||||
`};`,
|
`};`,
|
||||||
`Module._extensions[".jsc"] = function (module, filename) {`,
|
`Module._extensions[".jsc"] = Module._extensions[".cjsc"] = function (module, filename) {`,
|
||||||
` const bytecodeBuffer = fs.readFileSync(filename);`,
|
` const bytecodeBuffer = fs.readFileSync(filename);`,
|
||||||
` if (!Buffer.isBuffer(bytecodeBuffer)) {`,
|
` if (!Buffer.isBuffer(bytecodeBuffer)) {`,
|
||||||
` throw new Error("BytecodeBuffer must be a buffer object.");`,
|
` throw new Error("BytecodeBuffer must be a buffer object.");`,
|
||||||
|
@ -181,7 +181,7 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStrict = '"use strict";'
|
const useStrict = '"use strict";'
|
||||||
const bytecodeModuleLoader = 'bytecode-loader.js'
|
const bytecodeModuleLoader = 'bytecode-loader.cjs'
|
||||||
|
|
||||||
let config: ResolvedConfig
|
let config: ResolvedConfig
|
||||||
let useInRenderer = false
|
let useInRenderer = false
|
||||||
|
@ -196,7 +196,7 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
|
||||||
config = resolvedConfig
|
config = resolvedConfig
|
||||||
useInRenderer = config.plugins.some(p => p.name === 'vite:electron-renderer-preset-config')
|
useInRenderer = config.plugins.some(p => p.name === 'vite:electron-renderer-preset-config')
|
||||||
if (useInRenderer) {
|
if (useInRenderer) {
|
||||||
config.logger.warn(colors.yellow('bytecodePlugin is not support renderers'))
|
config.logger.warn(colors.yellow('bytecodePlugin does not support renderer.'))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
transform(code, id): void | { code: string; map: SourceMapInput } {
|
transform(code, id): void | { code: string; map: SourceMapInput } {
|
||||||
|
@ -226,7 +226,16 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderChunk(code, chunk): { code: string } | null {
|
renderChunk(code, chunk, options): { code: string } | null {
|
||||||
|
if (options.format === 'es') {
|
||||||
|
config.logger.warn(
|
||||||
|
colors.yellow(
|
||||||
|
'bytecodePlugin does not support ES module, please remove "type": "module" ' +
|
||||||
|
'in package.json or set the "build.rollupOptions.output.format" option to "cjs".'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
}
|
||||||
if (useInRenderer) {
|
if (useInRenderer) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -240,8 +249,8 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
generateBundle(): void {
|
generateBundle(options): void {
|
||||||
if (!useInRenderer && bytecodeRequired) {
|
if (options.format !== 'es' && !useInRenderer && bytecodeRequired) {
|
||||||
this.emitFile({
|
this.emitFile({
|
||||||
type: 'asset',
|
type: 'asset',
|
||||||
source: bytecodeModuleLoaderCode.join('\n') + '\n',
|
source: bytecodeModuleLoaderCode.join('\n') + '\n',
|
||||||
|
@ -251,7 +260,7 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async writeBundle(options, output): Promise<void> {
|
async writeBundle(options, output): Promise<void> {
|
||||||
if (useInRenderer || !bytecodeRequired) {
|
if (options.format === 'es' || useInRenderer || !bytecodeRequired) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@ import path from 'node:path'
|
||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
import { builtinModules } from 'node:module'
|
import { builtinModules } from 'node:module'
|
||||||
import colors from 'picocolors'
|
import colors from 'picocolors'
|
||||||
import { type Plugin, mergeConfig, normalizePath } from 'vite'
|
import { type Plugin, type LibraryOptions, mergeConfig, normalizePath } from 'vite'
|
||||||
import { getElectronNodeTarget, getElectronChromeTarget } from '../electron'
|
import type { OutputOptions } from 'rollup'
|
||||||
|
import { getElectronNodeTarget, getElectronChromeTarget, supportESM } from '../electron'
|
||||||
|
import { loadPackageData } from '../utils'
|
||||||
|
|
||||||
export interface ElectronPluginOptions {
|
export interface ElectronPluginOptions {
|
||||||
root?: string
|
root?: string
|
||||||
|
@ -37,6 +39,17 @@ function processEnvDefine(): Record<string, string> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveBuildOutputs(
|
||||||
|
outputs: OutputOptions | OutputOptions[] | undefined,
|
||||||
|
libOptions: LibraryOptions | false
|
||||||
|
): OutputOptions | OutputOptions[] | undefined {
|
||||||
|
if (libOptions && !Array.isArray(outputs)) {
|
||||||
|
const libFormats = libOptions.formats || []
|
||||||
|
return libFormats.map(format => ({ ...outputs, format }))
|
||||||
|
}
|
||||||
|
return outputs
|
||||||
|
}
|
||||||
|
|
||||||
export function electronMainVitePlugin(options?: ElectronPluginOptions): Plugin[] {
|
export function electronMainVitePlugin(options?: ElectronPluginOptions): Plugin[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -48,6 +61,10 @@ export function electronMainVitePlugin(options?: ElectronPluginOptions): Plugin[
|
||||||
|
|
||||||
const nodeTarget = getElectronNodeTarget()
|
const nodeTarget = getElectronNodeTarget()
|
||||||
|
|
||||||
|
const pkg = loadPackageData() || { type: 'commonjs' }
|
||||||
|
|
||||||
|
const format = pkg.type && pkg.type === 'module' && supportESM() ? 'es' : 'cjs'
|
||||||
|
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
resolve: {
|
resolve: {
|
||||||
browserField: false,
|
browserField: false,
|
||||||
|
@ -60,9 +77,7 @@ export function electronMainVitePlugin(options?: ElectronPluginOptions): Plugin[
|
||||||
assetsDir: 'chunks',
|
assetsDir: 'chunks',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: ['electron', ...builtinModules.flatMap(m => [m, `node:${m}`])],
|
external: ['electron', ...builtinModules.flatMap(m => [m, `node:${m}`])],
|
||||||
output: {
|
output: {}
|
||||||
entryFileNames: '[name].js'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
reportCompressedSize: false,
|
reportCompressedSize: false,
|
||||||
minify: false
|
minify: false
|
||||||
|
@ -72,12 +87,21 @@ export function electronMainVitePlugin(options?: ElectronPluginOptions): Plugin[
|
||||||
const build = config.build || {}
|
const build = config.build || {}
|
||||||
const rollupOptions = build.rollupOptions || {}
|
const rollupOptions = build.rollupOptions || {}
|
||||||
if (!rollupOptions.input) {
|
if (!rollupOptions.input) {
|
||||||
|
const libOptions = build.lib
|
||||||
|
const outputOptions = rollupOptions.output
|
||||||
defaultConfig.build['lib'] = {
|
defaultConfig.build['lib'] = {
|
||||||
entry: findLibEntry(root, 'main'),
|
entry: findLibEntry(root, 'main'),
|
||||||
formats: ['cjs']
|
formats:
|
||||||
|
libOptions && libOptions.formats && libOptions.formats.length > 0
|
||||||
|
? []
|
||||||
|
: [
|
||||||
|
outputOptions && !Array.isArray(outputOptions) && outputOptions.format
|
||||||
|
? outputOptions.format
|
||||||
|
: format
|
||||||
|
]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defaultConfig.build.rollupOptions.output['format'] = 'cjs'
|
defaultConfig.build.rollupOptions.output['format'] = format
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig.build.rollupOptions.output['assetFileNames'] = path.posix.join(
|
defaultConfig.build.rollupOptions.output['assetFileNames'] = path.posix.join(
|
||||||
|
@ -100,6 +124,8 @@ export function electronMainVitePlugin(options?: ElectronPluginOptions): Plugin[
|
||||||
config.build.copyPublicDir = false
|
config.build.copyPublicDir = false
|
||||||
// module preload polyfill does not apply to nodejs (main process)
|
// module preload polyfill does not apply to nodejs (main process)
|
||||||
config.build.modulePreload = false
|
config.build.modulePreload = false
|
||||||
|
// enable ssr build
|
||||||
|
config.build.ssr = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -109,36 +135,44 @@ export function electronMainVitePlugin(options?: ElectronPluginOptions): Plugin[
|
||||||
configResolved(config): void {
|
configResolved(config): void {
|
||||||
const build = config.build
|
const build = config.build
|
||||||
if (!build.target) {
|
if (!build.target) {
|
||||||
throw new Error('build target required for the electron vite main config')
|
throw new Error('build.target option is required in the electron vite main config.')
|
||||||
} else {
|
} else {
|
||||||
const targets = Array.isArray(build.target) ? build.target : [build.target]
|
const targets = Array.isArray(build.target) ? build.target : [build.target]
|
||||||
if (targets.some(t => !t.startsWith('node'))) {
|
if (targets.some(t => !t.startsWith('node'))) {
|
||||||
throw new Error('the electron vite main config build target must be node')
|
throw new Error('The electron vite main config build.target option must be "node?".')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const lib = build.lib
|
const libOptions = build.lib
|
||||||
if (!lib) {
|
|
||||||
const rollupOptions = build.rollupOptions
|
const rollupOptions = build.rollupOptions
|
||||||
if (!rollupOptions?.input) {
|
|
||||||
throw new Error('build lib field required for the electron vite main config')
|
if (!(libOptions && libOptions.entry) && !rollupOptions?.input) {
|
||||||
|
throw new Error(
|
||||||
|
'An entry point is required in the electron vite main config, ' +
|
||||||
|
'which can be specified using "build.lib.entry" or "build.rollupOptions.input".'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvedOutputs = resolveBuildOutputs(rollupOptions.output, libOptions)
|
||||||
|
|
||||||
|
if (resolvedOutputs) {
|
||||||
|
const outputs = Array.isArray(resolvedOutputs) ? resolvedOutputs : [resolvedOutputs]
|
||||||
|
if (outputs.length > 1) {
|
||||||
|
throw new Error('The electron vite main config does not support multiple outputs.')
|
||||||
} else {
|
} else {
|
||||||
const output = rollupOptions?.output
|
const outpout = outputs[0]
|
||||||
if (output) {
|
if (['es', 'cjs'].includes(outpout.format || '')) {
|
||||||
const formats = Array.isArray(output) ? output : [output]
|
if (outpout.format === 'es' && !supportESM()) {
|
||||||
if (formats.some(f => f.format !== 'cjs')) {
|
throw new Error(
|
||||||
throw new Error('the electron vite main config output format must be cjs')
|
'The electron vite main config output format does not support "es", ' +
|
||||||
}
|
'you can upgrade electron to the latest version or switch to "cjs" format.'
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!lib.entry) {
|
throw new Error(
|
||||||
throw new Error('build entry field required for the electron vite main config')
|
`The electron vite main config output format must be "cjs"${supportESM() ? ' or "es"' : ''}.`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (!lib.formats) {
|
|
||||||
throw new Error('build format field required for the electron vite main config')
|
|
||||||
} else if (!lib.formats.includes('cjs')) {
|
|
||||||
throw new Error('the electron vite main config build lib format must be cjs')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,6 +191,10 @@ export function electronPreloadVitePlugin(options?: ElectronPluginOptions): Plug
|
||||||
|
|
||||||
const nodeTarget = getElectronNodeTarget()
|
const nodeTarget = getElectronNodeTarget()
|
||||||
|
|
||||||
|
const pkg = loadPackageData() || { type: 'commonjs' }
|
||||||
|
|
||||||
|
const format = pkg.type && pkg.type === 'module' && supportESM() ? 'es' : 'cjs'
|
||||||
|
|
||||||
const defaultConfig = {
|
const defaultConfig = {
|
||||||
build: {
|
build: {
|
||||||
outDir: path.resolve(root, 'out', 'preload'),
|
outDir: path.resolve(root, 'out', 'preload'),
|
||||||
|
@ -164,9 +202,7 @@ export function electronPreloadVitePlugin(options?: ElectronPluginOptions): Plug
|
||||||
assetsDir: 'chunks',
|
assetsDir: 'chunks',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: ['electron', ...builtinModules.flatMap(m => [m, `node:${m}`])],
|
external: ['electron', ...builtinModules.flatMap(m => [m, `node:${m}`])],
|
||||||
output: {
|
output: {}
|
||||||
entryFileNames: '[name].js'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
reportCompressedSize: false,
|
reportCompressedSize: false,
|
||||||
minify: false
|
minify: false
|
||||||
|
@ -176,12 +212,21 @@ export function electronPreloadVitePlugin(options?: ElectronPluginOptions): Plug
|
||||||
const build = config.build || {}
|
const build = config.build || {}
|
||||||
const rollupOptions = build.rollupOptions || {}
|
const rollupOptions = build.rollupOptions || {}
|
||||||
if (!rollupOptions.input) {
|
if (!rollupOptions.input) {
|
||||||
|
const libOptions = build.lib
|
||||||
|
const outputOptions = rollupOptions.output
|
||||||
defaultConfig.build['lib'] = {
|
defaultConfig.build['lib'] = {
|
||||||
entry: findLibEntry(root, 'preload'),
|
entry: findLibEntry(root, 'preload'),
|
||||||
formats: ['cjs']
|
formats:
|
||||||
|
libOptions && libOptions.formats && libOptions.formats.length > 0
|
||||||
|
? []
|
||||||
|
: [
|
||||||
|
outputOptions && !Array.isArray(outputOptions) && outputOptions.format
|
||||||
|
? outputOptions.format
|
||||||
|
: format
|
||||||
|
]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defaultConfig.build.rollupOptions.output['format'] = 'cjs'
|
defaultConfig.build.rollupOptions.output['format'] = format
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig.build.rollupOptions.output['assetFileNames'] = path.posix.join(
|
defaultConfig.build.rollupOptions.output['assetFileNames'] = path.posix.join(
|
||||||
|
@ -192,6 +237,26 @@ export function electronPreloadVitePlugin(options?: ElectronPluginOptions): Plug
|
||||||
const buildConfig = mergeConfig(defaultConfig.build, build)
|
const buildConfig = mergeConfig(defaultConfig.build, build)
|
||||||
config.build = buildConfig
|
config.build = buildConfig
|
||||||
|
|
||||||
|
const resolvedOutputs = resolveBuildOutputs(config.build.rollupOptions!.output, config.build.lib || false)
|
||||||
|
|
||||||
|
if (resolvedOutputs) {
|
||||||
|
const outputs = Array.isArray(resolvedOutputs) ? resolvedOutputs : [resolvedOutputs]
|
||||||
|
|
||||||
|
if (outputs.find(({ format }) => format === 'es')) {
|
||||||
|
if (Array.isArray(config.build.rollupOptions!.output)) {
|
||||||
|
config.build.rollupOptions!.output.forEach(output => {
|
||||||
|
if (output.format === 'es') {
|
||||||
|
output['entryFileNames'] = '[name].mjs'
|
||||||
|
output['chunkFileNames'] = '[name]-[hash].mjs'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
config.build.rollupOptions!.output!['entryFileNames'] = '[name].mjs'
|
||||||
|
config.build.rollupOptions!.output!['chunkFileNames'] = '[name]-[hash].mjs'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
config.define = config.define || {}
|
config.define = config.define || {}
|
||||||
config.define = { ...processEnvDefine(), ...config.define }
|
config.define = { ...processEnvDefine(), ...config.define }
|
||||||
|
|
||||||
|
@ -202,6 +267,8 @@ export function electronPreloadVitePlugin(options?: ElectronPluginOptions): Plug
|
||||||
config.build.copyPublicDir = false
|
config.build.copyPublicDir = false
|
||||||
// module preload polyfill does not apply to nodejs (preload scripts)
|
// module preload polyfill does not apply to nodejs (preload scripts)
|
||||||
config.build.modulePreload = false
|
config.build.modulePreload = false
|
||||||
|
// enable ssr build
|
||||||
|
config.build.ssr = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -211,36 +278,44 @@ export function electronPreloadVitePlugin(options?: ElectronPluginOptions): Plug
|
||||||
configResolved(config): void {
|
configResolved(config): void {
|
||||||
const build = config.build
|
const build = config.build
|
||||||
if (!build.target) {
|
if (!build.target) {
|
||||||
throw new Error('build target required for the electron vite preload config')
|
throw new Error('build.target option is required in the electron vite preload config.')
|
||||||
} else {
|
} else {
|
||||||
const targets = Array.isArray(build.target) ? build.target : [build.target]
|
const targets = Array.isArray(build.target) ? build.target : [build.target]
|
||||||
if (targets.some(t => !t.startsWith('node'))) {
|
if (targets.some(t => !t.startsWith('node'))) {
|
||||||
throw new Error('the electron vite preload config build target must be node')
|
throw new Error('The electron vite preload config build.target must be "node?".')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const lib = build.lib
|
const libOptions = build.lib
|
||||||
if (!lib) {
|
|
||||||
const rollupOptions = build.rollupOptions
|
const rollupOptions = build.rollupOptions
|
||||||
if (!rollupOptions?.input) {
|
|
||||||
throw new Error('build lib field required for the electron vite preload config')
|
if (!(libOptions && libOptions.entry) && !rollupOptions?.input) {
|
||||||
|
throw new Error(
|
||||||
|
'An entry point is required in the electron vite preload config, ' +
|
||||||
|
'which can be specified using "build.lib.entry" or "build.rollupOptions.input".'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvedOutputs = resolveBuildOutputs(rollupOptions.output, libOptions)
|
||||||
|
|
||||||
|
if (resolvedOutputs) {
|
||||||
|
const outputs = Array.isArray(resolvedOutputs) ? resolvedOutputs : [resolvedOutputs]
|
||||||
|
if (outputs.length > 1) {
|
||||||
|
throw new Error('The electron vite preload config does not support multiple outputs.')
|
||||||
} else {
|
} else {
|
||||||
const output = rollupOptions?.output
|
const outpout = outputs[0]
|
||||||
if (output) {
|
if (['es', 'cjs'].includes(outpout.format || '')) {
|
||||||
const formats = Array.isArray(output) ? output : [output]
|
if (outpout.format === 'es' && !supportESM()) {
|
||||||
if (formats.some(f => f.format !== 'cjs')) {
|
throw new Error(
|
||||||
throw new Error('the electron vite preload config output format must be cjs')
|
'The electron vite preload config output format does not support "es", ' +
|
||||||
}
|
'you can upgrade electron to the latest version or switch to "cjs" format.'
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!lib.entry) {
|
throw new Error(
|
||||||
throw new Error('build entry field required for the electron vite preload config')
|
`The electron vite preload config output format must be "cjs"${supportESM() ? ' or "es"' : ''}.`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (!lib.formats) {
|
|
||||||
throw new Error('build format field required for the electron vite preload config')
|
|
||||||
} else if (!lib.formats.includes('cjs')) {
|
|
||||||
throw new Error('the electron vite preload config lib format must be cjs')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,23 +380,23 @@ export function electronRendererVitePlugin(options?: ElectronPluginOptions): Plu
|
||||||
enforce: 'post',
|
enforce: 'post',
|
||||||
configResolved(config): void {
|
configResolved(config): void {
|
||||||
if (config.base !== './' && config.base !== '/') {
|
if (config.base !== './' && config.base !== '/') {
|
||||||
config.logger.warn(colors.yellow('should not set base field for the electron vite renderer config'))
|
config.logger.warn(colors.yellow('(!) Should not set "base" option for the electron vite renderer config.'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const build = config.build
|
const build = config.build
|
||||||
if (!build.target) {
|
if (!build.target) {
|
||||||
throw new Error('build target required for the electron vite renderer config')
|
throw new Error('build.target option is required in the electron vite renderer config.')
|
||||||
} else {
|
} else {
|
||||||
const targets = Array.isArray(build.target) ? build.target : [build.target]
|
const targets = Array.isArray(build.target) ? build.target : [build.target]
|
||||||
if (targets.some(t => !t.startsWith('chrome') && !/^es((202\d{1})|next)$/.test(t))) {
|
if (targets.some(t => !t.startsWith('chrome') && !/^es((202\d{1})|next)$/.test(t))) {
|
||||||
throw new Error('the electron vite renderer config build target must be chrome? or es?')
|
throw new Error('The electron vite renderer config build.target must be "chrome?" or "es?".')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const rollupOptions = build.rollupOptions
|
const rollupOptions = build.rollupOptions
|
||||||
if (!rollupOptions.input) {
|
if (!rollupOptions.input) {
|
||||||
config.logger.warn(colors.yellow(`index.html file is not found in ${colors.dim('/src/renderer')} directory`))
|
config.logger.warn(colors.yellow(`index.html file is not found in ${colors.dim('/src/renderer')} directory.`))
|
||||||
throw new Error('build rollupOptions input field required for the electron vite renderer config')
|
throw new Error('build.rollupOptions.input option is required in the electron vite renderer config.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
66
src/plugins/esm.ts
Normal file
66
src/plugins/esm.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* The core of this plugin was conceived by pi0 and is taken from the following repository:
|
||||||
|
* https://github.com/unjs/unbuild/blob/main/src/builder/plugins/cjs.ts
|
||||||
|
* license: https://github.com/unjs/unbuild/blob/main/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import MagicString from 'magic-string'
|
||||||
|
import type { SourceMapInput } from 'rollup'
|
||||||
|
import type { Plugin } from 'vite'
|
||||||
|
|
||||||
|
const CJSyntaxRe = /__filename|__dirname|require\(|require\.resolve\(/
|
||||||
|
|
||||||
|
const CJSShim = `
|
||||||
|
// -- CommonJS Shims --
|
||||||
|
import __cjs_url__ from 'node:url';
|
||||||
|
import __cjs_path__ from 'node:path';
|
||||||
|
import __cjs_mod__ from 'node:module';
|
||||||
|
const __filename = __cjs_url__.fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = __cjs_path__.dirname(__filename);
|
||||||
|
const require = __cjs_mod__.createRequire(import.meta.url);
|
||||||
|
`
|
||||||
|
|
||||||
|
const ESMStaticImportRe =
|
||||||
|
/(?<=\s|^|;)import\s*([\s"']*(?<imports>[\p{L}\p{M}\w\t\n\r $*,/{}@.]+)from\s*)?["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][\s;]*/gmu
|
||||||
|
|
||||||
|
interface StaticImport {
|
||||||
|
end: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function findStaticImports(code: string): StaticImport[] {
|
||||||
|
const matches: StaticImport[] = []
|
||||||
|
for (const match of code.matchAll(ESMStaticImportRe)) {
|
||||||
|
matches.push({ end: (match.index || 0) + match[0].length })
|
||||||
|
}
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function esmShimPlugin(): Plugin {
|
||||||
|
let sourcemap: boolean | 'inline' | 'hidden' = false
|
||||||
|
return {
|
||||||
|
name: 'vite:esm-shim',
|
||||||
|
apply: 'build',
|
||||||
|
enforce: 'post',
|
||||||
|
configResolved(config): void {
|
||||||
|
sourcemap = config.build.sourcemap
|
||||||
|
},
|
||||||
|
renderChunk(code, _chunk, options): { code: string; map?: SourceMapInput } | null {
|
||||||
|
if (options.format === 'es') {
|
||||||
|
if (code.includes(CJSShim) || !CJSyntaxRe.test(code)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastESMImport = findStaticImports(code).pop()
|
||||||
|
const indexToAppend = lastESMImport ? lastESMImport.end : 0
|
||||||
|
const s = new MagicString(code)
|
||||||
|
s.appendRight(indexToAppend, CJSShim)
|
||||||
|
return {
|
||||||
|
code: s.toString(),
|
||||||
|
map: sourcemap ? s.generateMap({ hires: true }) : null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue