mirror of
https://github.com/luxfi/wallet.git
synced 2026-10-30 15:13:19 +00:00
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).
333 lines
11 KiB
TypeScript
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',
|
|
},
|
|
})
|