fix(desktop): ship entry.ts as the Electron main bundle entry
The bundler rewrite predates #113247, and merging it back kept main.ts as the esbuild entry. entry.ts, which picks the ozone platform and relaunches before main loads, was no longer bundled: the WSLg Wayland relaunch never ran. Bundle entry.ts again and run the built electron-main.mjs in a test to prove the relaunch ships.
This commit is contained in:
committed by
brooklyn!
parent
9e7239acfd
commit
c0a0f097a8
@@ -56,7 +56,9 @@ export async function bundleElectronMain({ source, out, stamp, dev = false }) {
|
||||
}
|
||||
await build({
|
||||
...common,
|
||||
entryPoints: [join(source, 'apps/desktop/electron/main.ts')],
|
||||
// entry.ts picks the Linux ozone platform (native Wayland/WSLg) and
|
||||
// relaunches before main.ts loads; Electron reads it only from argv.
|
||||
entryPoints: [join(source, 'apps/desktop/electron/entry.ts')],
|
||||
format: 'esm',
|
||||
outfile: join(out, 'electron-main.mjs'),
|
||||
banner: { js: "import { createRequire } from 'module'; const require = createRequire(import.meta.url);" + envBanner },
|
||||
|
||||
101
apps/desktop/scripts/bundle-electron-main.test.mjs
Normal file
101
apps/desktop/scripts/bundle-electron-main.test.mjs
Normal file
@@ -0,0 +1,101 @@
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
|
||||
import { afterAll, beforeAll, expect, test } from 'vitest'
|
||||
|
||||
import { bundleElectronMain } from './bundle-electron-main.mjs'
|
||||
|
||||
const repo = resolve(import.meta.dirname, '../../..')
|
||||
let root
|
||||
let bundle
|
||||
let preload
|
||||
|
||||
// Run the shipped electron-main.mjs under plain Node as if on Linux. The entry
|
||||
// relaunches through process.execPath; the preload (inherited through
|
||||
// NODE_OPTIONS) makes that child print its argv instead of starting the app.
|
||||
beforeAll(async () => {
|
||||
root = mkdtempSync(join(tmpdir(), 'hermes-electron-entry-'))
|
||||
await bundleElectronMain({ source: repo, out: join(root, 'dist'), dev: true })
|
||||
bundle = join(root, 'dist/electron-main.mjs')
|
||||
preload = join(root, 'preload.mjs')
|
||||
writeFileSync(
|
||||
preload,
|
||||
`
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { registerHooks } from 'node:module'
|
||||
Object.defineProperty(process, 'platform', { value: 'linux' })
|
||||
if (process.argv.some(arg => arg.startsWith('--ozone-platform='))) {
|
||||
console.log(JSON.stringify({ relaunched: process.argv.slice(2) }))
|
||||
process.exit(0)
|
||||
}
|
||||
// Externals the bundle leaves to Electron's node_modules. Stub each with
|
||||
// every name the bundle imports from it; only app.exit is ever called.
|
||||
const bundled = readFileSync(${JSON.stringify(bundle)}, 'utf8')
|
||||
const stub = specifier => {
|
||||
const names = new Set(specifier === 'electron' ? ['app'] : [])
|
||||
for (const [, list, from] of bundled.matchAll(/import\\s*\\{([^}]*)\\}\\s*from\\s*"([^"]+)"/g)) {
|
||||
if (from !== specifier) continue
|
||||
for (const name of list.split(',')) names.add(name.trim().split(/\\s+as\\s+/)[0])
|
||||
}
|
||||
names.delete('')
|
||||
return [...names].map(name => name === 'app'
|
||||
? 'export const app = { exit: code => process.exit(code) }'
|
||||
: 'export const ' + name + ' = {}').join('\\n') + '\\nexport default {}'
|
||||
}
|
||||
const externals = new Set(['electron', 'node-pty', 'get-windows'])
|
||||
registerHooks({
|
||||
resolve: (specifier, context, next) => externals.has(specifier)
|
||||
? { url: 'hermes-stub:' + specifier, shortCircuit: true } : next(specifier, context),
|
||||
load: (url, context, next) => url.startsWith('hermes-stub:')
|
||||
? { format: 'module', source: stub(url.slice('hermes-stub:'.length)), shortCircuit: true } : next(url, context),
|
||||
})
|
||||
`
|
||||
)
|
||||
}, 120_000)
|
||||
|
||||
afterAll(() => rmSync(root, { recursive: true, force: true }))
|
||||
|
||||
function launch(env, config) {
|
||||
const home = mkdtempSync(join(root, 'home-'))
|
||||
|
||||
if (config) {
|
||||
mkdirSync(home, { recursive: true })
|
||||
writeFileSync(join(home, 'config.yaml'), config)
|
||||
}
|
||||
|
||||
const out = execFileSync(process.execPath, [bundle, '.'], {
|
||||
cwd: root,
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
PATH: process.env.PATH,
|
||||
HERMES_HOME: home,
|
||||
NODE_OPTIONS: `--import=${pathToFileURL(preload).href}`,
|
||||
...env
|
||||
}
|
||||
})
|
||||
|
||||
return JSON.parse(out.trim().split('\n').at(-1))
|
||||
}
|
||||
|
||||
test('the bundled entry relaunches native Wayland sessions with the wayland ozone platform', () => {
|
||||
expect(launch({ XDG_SESSION_TYPE: 'wayland', WAYLAND_DISPLAY: 'wayland-0', DISPLAY: ':0' })).toEqual({
|
||||
relaunched: ['.', '--ozone-platform=wayland']
|
||||
})
|
||||
})
|
||||
|
||||
test('the bundled entry keeps the WSLg Wayland relaunch', () => {
|
||||
expect(launch({ WSL_DISTRO_NAME: 'Ubuntu', WAYLAND_DISPLAY: 'wayland-0', DISPLAY: ':0' })).toEqual({
|
||||
relaunched: ['.', '--ozone-platform=wayland']
|
||||
})
|
||||
})
|
||||
|
||||
test('the bundled entry lets desktop.electron_flags choose the ozone platform', () => {
|
||||
const config = 'desktop:\n electron_flags:\n - --ozone-platform=x11\n'
|
||||
|
||||
expect(launch({ XDG_SESSION_TYPE: 'wayland', WAYLAND_DISPLAY: 'wayland-0', DISPLAY: ':0' }, config)).toEqual({
|
||||
relaunched: ['.', '--ozone-platform=x11']
|
||||
})
|
||||
})
|
||||
@@ -32,6 +32,7 @@ function fixture() {
|
||||
put(join(app, 'vite.config.mjs'), 'export default { base: "./", build: { minify: false } }')
|
||||
put(join(app, 'index.html'), '<html><div id="app"></div><script type="module" src="/src/index.js"></script></html>')
|
||||
put(join(app, 'src/index.js'), 'document.getElementById("app").textContent = "built renderer"')
|
||||
put(join(app, 'electron/entry.ts'), "await import('./main')")
|
||||
put(join(app, 'electron/main.ts'), 'console.log(JSON.stringify({ stamp: __HERMES_INSTALL_STAMP__, identity: __HERMES_PRODUCT_IDENTITY__ }))')
|
||||
put(join(app, 'electron/preload.ts'), 'globalThis.fixturePreload = "compiled preload"')
|
||||
put(join(app, 'electron/preview-guest-preload-entry.ts'), 'globalThis.fixtureGuestPreload = "compiled guest preload"')
|
||||
|
||||
Reference in New Issue
Block a user