build-windows-desktop.mjs 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. import { build } from 'esbuild'
  2. import { execFileSync } from 'node:child_process'
  3. import { cp, mkdir, rm, readdir, readFile, writeFile } from 'node:fs/promises'
  4. import { resolve, join } from 'node:path'
  5. import { createRequire } from 'node:module'
  6. import { bundleDesktopUpdater } from './bundle-desktop-updater.mjs'
  7. if (process.platform !== 'win32' || process.arch !== 'x64') throw new Error('Windows x64 原生助手请通过 Windows CI 或 Windows x64 电脑构建')
  8. const root = resolve(import.meta.dirname, '..'), out = join(root, '.desktop-build'), shell = join(out, 'shell')
  9. await rm(out, { recursive: true, force: true })
  10. await mkdir(shell, { recursive: true })
  11. await mkdir(join(out, 'branding'))
  12. const native = join(out, 'native')
  13. execFileSync('cmake', ['-S', join(root, 'desktop/windows'), '-B', native, '-A', 'x64'], { stdio: 'inherit' })
  14. execFileSync('cmake', ['--build', native, '--config', 'Release'], { stdio: 'inherit' })
  15. for (const name of ['computer-helper.exe', 'computer-helper-dev.exe']) {
  16. await cp(join(native, 'Release', name), join(out, name))
  17. execFileSync(join(out, name), ['--self-test'], { stdio: 'inherit' })
  18. }
  19. const env = { ...process.env }; delete env.ELECTRON_RUN_AS_NODE
  20. execFileSync(createRequire(import.meta.url)('electron'), [join(root, 'scripts/build-windows-icon.cjs'),
  21. join(root, 'public/icons/icon-512.png'), join(out, 'branding/icon.ico')], { stdio: 'inherit', env })
  22. await bundleDesktopUpdater(join(out, 'electron-updater.cjs'), 'win32')
  23. await build({ entryPoints: [join(root, 'src/server/githubReleases.ts')], outfile: join(out, 'github-release.mjs'),
  24. bundle: true, platform: 'node', format: 'esm', target: 'node24' })
  25. await cp(join(root, 'bin/lib/data-home.mjs'), join(shell, 'data-home.mjs'))
  26. await cp(join(root, 'bin/lib/desktop-activation.mjs'), join(shell, 'desktop-activation.mjs'))
  27. for (const file of await readdir(join(root, 'desktop'))) {
  28. if (['data-home.mjs', 'desktop-activation.mjs'].includes(file) || file.endsWith('.test.mjs') || !/\.(js|mjs|cjs|html|css|png|svg)$/.test(file)) continue
  29. if (['file-transfer.mjs', 'host-files.mjs'].includes(file)) {
  30. await build({ entryPoints: [join(root, 'desktop', file)], outfile: join(shell, file), bundle: true, platform: 'node', format: 'esm', target: 'node24' })
  31. } else {
  32. if (/\.(js|mjs|cjs)$/.test(file)) execFileSync(process.execPath, ['--check', join(root, 'desktop', file)])
  33. await cp(join(root, 'desktop', file), join(shell, file))
  34. }
  35. }
  36. await cp(join(root, 'public/icons/icon-512.png'), join(shell, 'icon.png'))
  37. await cp(join(root, 'public/icons/icon-512.png'), join(root, 'desktop/icon.png'))
  38. for (const file of ['release.json', 'build-info.json']) await cp(join(root, file), join(out, file))
  39. for (const file of ['LICENSE', 'NOTICE', 'THIRD_PARTY_NOTICES.md', 'licenses']) await cp(join(root, file), join(shell, file), { recursive: true })
  40. const { webVersion: version } = JSON.parse(await readFile(join(root, 'release.json'), 'utf8'))
  41. await writeFile(join(shell, 'package.json'), JSON.stringify({ name: 'yaoyao-desktop', version, productName: '夭夭',
  42. description: '夭夭 AI:Windows 客户端', author: 'YaoYao contributors', license: 'Apache-2.0', main: 'main.mjs', type: 'module' }, null, 2))
  43. console.log('Windows 客户端与原生助手已构建,不包含本机服务器运行时')