Files
zeekayandHanzo Dev 69c6e860d7 transplant onto tamagui v2.6.0, brand as a re-runnable transform
This repo could never sync. There was NO merge-base with tamagui — 372 commits
here against 15,791 there, unrelated histories — because it began as a
copy-paste rebrand with a flattened layout. Every "sync" since was a hand
re-application that drifted, which is why the tree sat on 7.3.1 while upstream
shipped fixes we then rediscovered by hand.

This commit's PARENT IS TAMAGUI. A future sync is `git merge tama/main` then
`node scripts/rebrand.mjs` — a real merge, because the history is now shared.

174 packages: 166 upstream, our 8 restored (chrome, shell, telemetry, recipes,
get, font-geist-{sans,mono}, @hanzo/booker), bento-get gained. 170/170 build.

Our patches to files UPSTREAM ALSO OWNS are carried, which the package-level
delta missed and which was where the value actually was:
  - useMedia's server snapshot (`initState ?? getMedia()`). Upstream still
    returns undefined there, so every Tamagui Dialog kills a prerender — the
    exact crash hanzo.app spent a day on.
  - data-slot on web host nodes, absent upstream entirely.
Both applied ONTO upstream's newer files (it rewrote useMedia +150/-63 and
createComponent +160/-55), marked `PATCH (ours, carried across the transplant)`.

Seven traps are encoded in scripts/rebrand.mjs, each found by a gate:
skip itself and lockfiles; special-case the double-branded names in BOTH scoped
and bare form; map path strings, not just paths; drop a level for the flattened
group; check disk rather than a stale index.

Rust build artifacts are NOT committed. An earlier draft of this commit swept
apps/desktop/src-tauri/target/debug in via `git add -A` — 3,859 files including
a 272MB .a, over GitHub's 100MB cap, so the push could never have landed. They
are gitignored now.

Co-Authored-By: Hanzo Dev <[email protected]>
2026-07-30 18:25:06 -07:00

118 lines
4.2 KiB
TypeScript

import { mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import { esbundleGuiConfig, resolveWebOrNativeSpecificEntry } from '@hanzogui/static'
// regression: vite-plugin doesn't set process.env.GUI_TARGET (vxrn handles
// both web and native through the same plugin), so the static extractor must
// drive platform resolution from the explicit `platform` argument it already
// has plumbed through, not from the env var. previously this fell through to
// `.native.*` whenever GUI_TARGET was unset, producing CSS bundled against
// native code.
let tempDir: string
beforeEach(() => {
// realpath because require.resolve resolves symlinks (e.g. /var -> /private/var on macOS)
tempDir = realpathSync(mkdtempSync(join(tmpdir(), 'hanzogui-resolve-entry-')))
writeFileSync(join(tempDir, 'pkg.js'), '// base\n')
writeFileSync(join(tempDir, 'pkg.web.js'), '// web\n')
writeFileSync(join(tempDir, 'pkg.native.js'), '// native\n')
writeFileSync(join(tempDir, 'only-base.js'), '// base only\n')
})
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true })
vi.unstubAllEnvs()
})
describe('resolveWebOrNativeSpecificEntry', () => {
test('platform=web picks .web variant', () => {
vi.stubEnv('GUI_TARGET', '')
const entry = join(tempDir, 'pkg.js')
expect(resolveWebOrNativeSpecificEntry(entry, 'web')).toBe(
join(tempDir, 'pkg.web.js')
)
})
test('platform=native picks .native variant', () => {
vi.stubEnv('GUI_TARGET', 'web')
const entry = join(tempDir, 'pkg.js')
// explicit arg must win over env, otherwise web extraction in vxrn would
// pollute native config bundling (and vice versa)
expect(resolveWebOrNativeSpecificEntry(entry, 'native')).toBe(
join(tempDir, 'pkg.native.js')
)
})
test('no platform arg + no GUI_TARGET defaults to web', () => {
vi.stubEnv('GUI_TARGET', '')
const entry = join(tempDir, 'pkg.js')
// this is the 3pc / vite-plugin scenario: env unset, no arg passed.
// before the fix it returned the .native variant.
expect(resolveWebOrNativeSpecificEntry(entry)).toBe(join(tempDir, 'pkg.web.js'))
})
test('falls back to base entry when no platform-specific file exists', () => {
const entry = join(tempDir, 'only-base.js')
expect(resolveWebOrNativeSpecificEntry(entry, 'web')).toBe(entry)
expect(resolveWebOrNativeSpecificEntry(entry, 'native')).toBe(entry)
})
})
describe('esbundleGuiConfig platform defines', () => {
// bundle a tiny entry that branches on env vars and inspect the output to
// confirm the static extractor inlines GUI_TARGET + EXPO_OS based on
// the explicit platform argument, not the host process env.
test('platform=web inlines GUI_TARGET and EXPO_OS as "web"', async () => {
vi.stubEnv('GUI_TARGET', '')
vi.stubEnv('EXPO_OS', '')
const entry = join(tempDir, 'entry.js')
writeFileSync(
entry,
`
export const target = process.env.GUI_TARGET
export const expoOS = process.env.EXPO_OS
`
)
const outfile = join(tempDir, 'bundled.cjs')
await esbundleGuiConfig(
{ entryPoints: [entry], outfile, format: 'cjs', external: [] },
'web'
)
const out = readFileSync(outfile, 'utf-8')
expect(out).toContain('"web"')
// make sure the env reads were replaced, not left for runtime
expect(out).not.toContain('process.env.GUI_TARGET')
expect(out).not.toContain('process.env.EXPO_OS')
})
test('platform=native inlines GUI_TARGET as "native" and leaves EXPO_OS alone', async () => {
vi.stubEnv('GUI_TARGET', 'web')
const entry = join(tempDir, 'entry.js')
writeFileSync(
entry,
`
export const target = process.env.GUI_TARGET
export const expoOS = process.env.EXPO_OS
`
)
const outfile = join(tempDir, 'bundled.cjs')
await esbundleGuiConfig(
{ entryPoints: [entry], outfile, format: 'cjs', external: [] },
'native'
)
const out = readFileSync(outfile, 'utf-8')
expect(out).toContain('"native"')
// EXPO_OS shouldn't be inlined for native (ios vs android is ambiguous)
expect(out).toContain('process.env.EXPO_OS')
})
})