Files
zeekay 78fb1267b6 chore: scrub uniswap — use @luxamm/* (lux fork) only
Replace every @uniswap/* package import with @luxamm/* (lux fork
already canonical for SDK pieces). Replace app.uniswap.org URLs with
lux.exchange, uniswap.org with lux.network. Replace brand strings
(Uniswap Wallet → Lux Wallet, Uniswap Extension → Lux Extension,
Uniswap Labs → Lux Labs Inc.) where they appear in user-facing UI.
Rename handleUniswapAppDeepLink → handleLuxAppDeepLink, also rename
focusOrCreateUniswapInterfaceTab → focusOrCreateLuxInterfaceTab.

Manifest host_permissions updated to lux.exchange and *.lux.network.

Lockfile regeneration: TODO — run pnpm install to refresh after this
commit. Transitive @uniswap/* references in pnpm-lock.yaml are
upstream-package internals.

Protocol-level identifiers (UniswapMethodHandler, UniswapMethods,
UniswapOpenSidebarRequest, handleUniswapX, UniswapXOrderDetails) are
preserved because they reference wire-protocol method names
(uniswap_openSidebar) and external SDK type exports — renaming would
break upstream contracts. iOS Uniswap target directory and
uniswapteam.slack.com / github.com/Uniswap/universe doc refs are
out-of-scope per directive (separate native-build cleanup).

Same hard-banishment rule as tamagui (per feedback memory).
2026-06-10 22:35:41 -07:00

333 lines
11 KiB
TypeScript

import fs from 'fs'
import { createHash } from 'node:crypto'
import path from 'path'
import { loadEnv, transformWithEsbuild } from 'vite'
import commonjs from 'vite-plugin-commonjs'
import { nodePolyfills } from 'vite-plugin-node-polyfills'
import svgr from 'vite-plugin-svgr'
import tsconfigPaths from 'vite-tsconfig-paths'
import { defineConfig } from 'wxt'
import { getTsconfigAliases } from './config/getTsconfigAliases'
const BASE_NAME = process.env.BRAND_EXTENSION_NAME || '▼ Wallet'
const BASE_DESCRIPTION = process.env.BRAND_EXTENSION_DESC || 'Self-custody crypto wallet for swapping, bridging, and managing digital assets.'
const BASE_VERSION = '1.69.0'
const BUILD_NUM = parseInt(process.env.BUILD_NUM || '0')
const EXTENSION_VERSION = `${BASE_VERSION}.${BUILD_NUM}`
// Build variant directory under src/publicAssetsByEnv/. Determines which icons,
// manifest images, and copy bundles ship with the extension.
// prod = production stores (Chrome Web Store + Firefox Add-ons)
// beta = beta channel
// dev = local development
// default = same as prod when env not set
const publicAssetsVariant = process.env.WXT_PUBLIC_ASSETS_VARIANT || 'prod'
/**
* Vite's optimizeDeps cache hash doesn't include `define` values, so changing env vars
* (which are injected via `define` as `process.env.X` replacements) won't invalidate the
* pre-bundled deps cache. This compares a hash of the resolved env defines against a stored
* hash and forces a re-bundle only when env values actually changed.
*/
function shouldInvalidateOptimizeDepsForEnv({
defines,
cacheDir,
}: {
defines: Record<string, unknown>
cacheDir: string
}): boolean {
const hash = createHash('md5').update(JSON.stringify(defines)).digest('hex').slice(0, 16)
const hashFile = path.join(cacheDir, '.env-defines-hash')
try {
if (fs.existsSync(hashFile)) {
const stored = fs.readFileSync(hashFile, 'utf-8').trim()
if (stored === hash) {
return false
}
}
} catch {
return true
}
try {
if (!fs.existsSync(cacheDir)) {
fs.mkdirSync(cacheDir, { recursive: true })
}
fs.writeFileSync(hashFile, hash)
} catch {
return true
}
return true
}
// oxlint-disable-next-line import/no-unused-modules
export default defineConfig({
// WXT Configuration
srcDir: 'src',
entrypointsDir: 'entrypoints',
publicDir: 'src/public',
// Use absolute output directory if specified via environment variable
outDir: process.env.WXT_ABSOLUTE_OUTDIR || undefined,
// Remove browser/version subdirectory when using absolute paths
outDirTemplate: process.env.WXT_ABSOLUTE_OUTDIR ? '' : undefined,
imports: false,
// Enable React support
modules: ['@wxt-dev/module-react'],
hooks: {
// Hook for dynamic asset copying based on build variant.
// All assets in `src/publicAssetsByEnv/<variant>` will be copied to `assets/<name>` at build time.
'build:publicAssets': (_wxt, files) => {
const envDir = path.resolve(import.meta.dirname, 'src/publicAssetsByEnv', publicAssetsVariant)
const entries = fs.readdirSync(envDir)
for (const entry of entries) {
const absoluteSrc = path.resolve(envDir, entry)
if (fs.statSync(absoluteSrc).isFile()) {
files.push({
relativeDest: `assets/${entry}`,
absoluteSrc,
})
}
}
},
// Validate build output after dev builds complete
'build:done': async (wxt) => {
// Only validate in development mode (dev server)
if (wxt.config.mode !== 'development') {
return
}
const { execSync } = await import('node:child_process')
try {
// Run script directly to avoid Nx dependsOn chain that would trigger a full rebuild
execSync('bunx tsx scripts/validateBuildOutput.ts --dev', {
cwd: wxt.config.root,
stdio: 'inherit',
})
} catch {
// oxlint-disable-next-line no-console -- CLI output for build validation
console.error('Build validation failed!')
process.exit(1)
}
},
},
// Vite configuration copied from web project
vite: (env) => {
// Load ALL env variables (including those without VITE_ prefix)
const envVars = loadEnv(env.mode, process.cwd(), '')
const __dirname = path.dirname(new URL(import.meta.url).pathname)
const isProduction = process.env.NODE_ENV === 'production'
const isPreparePhase = process.env.WXT_PREPARE === 'true'
// Create process.env definitions for ALL environment variables
const envDefines = Object.fromEntries(
Object.entries(envVars).map(([key, value]) => [`process.env.${key}`, JSON.stringify(value)]),
)
const defines = {
__DEV__: !isProduction,
global: 'globalThis',
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.DEBUG': JSON.stringify(process.env.DEBUG || '0'),
'process.env.VERSION': JSON.stringify(EXTENSION_VERSION),
'process.env.IS_STATIC': '""',
'process.env.EXPO_OS': '"web"',
...envDefines,
'process.env.REACT_APP_IS_UNISWAP_INTERFACE': '"false"',
'process.env.IS_UNISWAP_EXTENSION': '"true"',
}
const cacheDir = path.resolve(__dirname, 'node_modules/.vite')
const forceOptimize = shouldInvalidateOptimizeDepsForEnv({ defines, cacheDir })
// External package aliases from web config
const overrides = {
buffer: 'buffer',
// External package aliases
'react-native': 'react-native-web',
// Skip expo-crypto alias during prepare phase since it imports react-native-web
crypto: isPreparePhase ? 'crypto' : 'expo-crypto',
'expo-clipboard': path.resolve(__dirname, '../web/src/lib/expo-clipboard.jsx'),
jsbi: path.resolve(__dirname, '../../node_modules/jsbi/dist/jsbi.mjs'), // force consistent ESM build
// Dynamically load all monorepo package aliases from tsconfig.base.json
...getTsconfigAliases(),
}
return {
define: defines,
resolve: {
extensions: ['.web.tsx', '.web.ts', '.web.js', '.tsx', '.ts', '.js'],
preserveSymlinks: true,
modules: [path.resolve(__dirname, 'node_modules')],
dedupe: [
'@luxamm/sdk-core',
'@luxamm/v2-sdk',
'@luxamm/v3-sdk',
'@luxamm/v4-sdk',
'@luxamm/router-sdk',
'@luxamm/universal-router-sdk',
'@luxamm/uniswapx-sdk',
'@luxamm/permit2-sdk',
'jsbi',
'ethers',
'react',
'react-dom',
'react-router',
'cookie',
],
alias: {
...overrides,
},
},
plugins: [
{
name: 'transform-react-native-jsx',
async transform(code, id) {
// Transform JSX in react-native libraries that ship JSX in .js files
const needsJsxTransform = ['node_modules/expo-blur', 'node_modules/react-native-reanimated'].some((path) =>
id.includes(path),
)
if (!needsJsxTransform || !id.endsWith('.js')) {
return null
}
// Use Vite's transformWithEsbuild to handle JSX
return transformWithEsbuild(code, id, {
loader: 'jsx',
jsx: 'automatic',
})
},
},
tsconfigPaths({
// ignores tsconfig files in Nx generator template directories
skip: (dir) => dir.includes('files'),
}),
svgr({
svgrOptions: {
icon: false,
ref: true,
titleProp: true,
exportType: 'named',
svgo: true,
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: { removeViewBox: false },
},
},
'removeDimensions',
],
},
},
include: '**/*.svg',
}),
// SVG import fix from web config
{
name: 'svg-import-fix',
transform(code: string) {
const regex = /import\s+([a-zA-Z0-9_$]+)\s+from\s+['"]([^'"]+\.svg)['"]/g
return code.replace(regex, "import { ReactComponent as $1 } from '$2'")
},
},
],
optimizeDeps: {
include: [
'@hanzo/gui',
'@hanzogui/web',
'ui',
'@luxamm/sdk-core',
'@luxamm/v2-sdk',
'@luxamm/v3-sdk',
'@luxamm/v4-sdk',
'@luxamm/router-sdk',
'@luxamm/universal-router-sdk',
'@luxamm/uniswapx-sdk',
'@luxamm/permit2-sdk',
'jsbi',
'ethers',
'react-router',
'cookie',
'cookie-es',
'void-elements',
'semver',
'eventemitter3',
'html-parse-stringify',
'dayjs',
'js-sha3',
'hash.js',
'elliptic',
'bn.js',
],
exclude: ['expo-clipboard', 'vite-plugin-node-polyfills'],
esbuildOptions: {
// Prefer .web.* extensions so react-native packages resolve to their web variants
// (e.g. react-native-svg/ReactNativeSVG.web.js instead of ReactNativeSVG.js which
// imports Fabric/codegen internals that don't exist on web).
resolveExtensions: ['.web.tsx', '.web.ts', '.web.js', '.tsx', '.ts', '.js'],
loader: {
'.js': 'jsx',
'.ts': 'ts',
'.tsx': 'tsx',
},
},
},
build: {
sourcemap: isProduction ? false : 'hidden',
minify: isProduction ? 'esbuild' : undefined,
rollupOptions: {
output: {
entryFileNames: 'assets/[name]-[hash].js',
chunkFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]',
},
},
chunkSizeWarningLimit: 800,
commonjsOptions: {
include: [/buffer/, /jsbi/, /node_modules/, /cookie/, /void-elements/, /@apollo\/client/],
transformMixedEsModules: true,
},
},
// Support all prefixes (including no prefix)
envPrefix: [],
}
},
// Development server configuration
dev: {
server: {
port: 9998, // Different from webpack (9997) to avoid conflicts
},
},
// Do not edit these defaults. Instead create the file apps/extension/web-ext.config.ts to override them.
// See the README for more information.
// https://wxt.dev/guide/essentials/config/browser-startup.html
webExt: {
startUrls: ['https://lux.exchange'],
chromiumArgs: ['--user-data-dir=./.wxt/chrome-data'],
// Optional: Open devtools in the browser automatically
// openDevtools: true,
// Save profile changes between builds.
keepProfileChanges: true,
// Optional: Firefox profile for Firefox development
firefoxProfile: './.wxt/firefox-data',
},
})