Skip to main content
BBPlayer leverages modern, performant technologies across the mobile app, backend service, and shared packages. This page provides a comprehensive overview of the tech stack and the rationale behind key technology choices.

Mobile Application Stack

Core Framework

React

Version: 19.2.0Latest React with the new compiler for automatic optimizations

React Native

Version: 0.83.1Cross-platform mobile framework with native performance

Expo

Version: 55.0.0-preview.7Comprehensive toolkit for React Native development and builds

Expo Router

Version: 55.0.0-canaryFile-based routing built on React Navigation

Why React 19?

BBPlayer uses React 19.2.0 to leverage the React Compiler, which automatically optimizes component rendering without manual memoization. This results in:
  • Fewer useMemo, useCallback, and React.memo calls
  • Improved runtime performance
  • Cleaner, more maintainable code
// babel.config.js includes React Compiler plugin
{
  "plugins": [
    "babel-plugin-react-compiler"
  ]
}
The React Compiler is still in RC stage but provides significant performance benefits for BBPlayer’s complex UI.

State Management

Zustand

Version: 5.0.10Lightweight state management with minimal boilerplate

TanStack Query

Version: 5.90.19Powerful data fetching and caching library

Immer

Version: 10.2.0Immutable state updates with mutable syntax

Why Zustand?

Zustand was chosen for its:
  • Simplicity: No providers, no boilerplate
  • Performance: Minimal re-renders with selector-based subscriptions
  • DevTools: Integration with React DevTools and Rozenite profiler
  • TypeScript: Excellent type inference
import { create } from 'zustand'

const usePlayerStore = create<PlayerState>((set) => ({
  currentTrack: null,
  isPlaying: false,
  play: () => set({ isPlaying: true }),
  pause: () => set({ isPlaying: false }),
}))

Why React Query?

TanStack Query handles:
  • Automatic caching: Reduces redundant API calls to Bilibili
  • Background refetching: Keeps data fresh
  • Optimistic updates: Instant UI feedback
  • Query invalidation: Precise cache management
  • Offline support: Works seamlessly with local-first architecture
const { data, isLoading } = useQuery({
  queryKey: ['playlist', playlistId],
  queryFn: () => fetchPlaylist(playlistId),
  staleTime: 5 * 60 * 1000, // 5 minutes
})

Database & Storage

Drizzle ORM

Version: 0.44.7TypeScript-first ORM with SQLite support

Expo SQLite

Version: 55.0.3Local SQL database for React Native

React Native MMKV

Version: 4.1.1Fast key-value storage for settings and cache

Expo File System

Version: 55.0.3File system access for audio downloads

Why Drizzle ORM?

Drizzle provides:
  • Type safety: End-to-end TypeScript types from schema to queries
  • Zero runtime overhead: No heavy ORM abstractions
  • SQL-like syntax: Familiar to developers who know SQL
  • Excellent DX: Automatic migrations, schema introspection
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'

export const playlists = sqliteTable('playlists', {
  id: text('id').primaryKey(),
  title: text('title').notNull(),
  createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
})

// Type-safe queries
const result = await db.select().from(playlists).where(eq(playlists.id, id))

Why MMKV?

MMKV is 10x faster than AsyncStorage:
  • Synchronous API (no async overhead)
  • Used for app settings, feature flags, and session data
  • Automatic encryption support
  • Memory-mapped I/O for maximum performance

UI Framework & Styling

React Native Paper

Version: 5.14.5Material Design 3 component library

Material Design Icons

Version: 12.4.0Comprehensive icon set

React Native Reanimated

Version: 4.2.1Smooth animations on UI thread

Shopify Skia

Version: 2.4.14High-performance 2D graphics

Material Design 3 Integration

BBPlayer implements full MD3 theming:
  • Dynamic color: Monet color extraction from album artwork
  • Color schemes: Automatic light/dark theme generation
  • Custom themes: Using @bbplayer/image-theme-colors
  • Edge-to-edge: Immersive full-screen layouts
import { MD3DarkTheme, MD3LightTheme } from 'react-native-paper'
import { useMaterial3Theme } from 'react-native-paper'

const theme = useMaterial3Theme({
  sourceColor: albumArtColor,
})

Expo Router

File-based routing with deep linking

React Navigation

Version: 7.1.8Underlying navigation library

Bottom Tabs

Version: 0.10.2Native bottom tab navigation

Gesture Handler

Version: 2.30.0Native gesture recognition

File-Based Routing

Expo Router uses the app/ directory structure:
app/
├── (tabs)/
│   ├── index.tsx        # Home screen
│   ├── library.tsx      # Library screen
│   └── downloads.tsx    # Downloads screen
├── player/
│   └── [id].tsx         # Dynamic player route
└── _layout.tsx          # Root layout
Benefits:
  • Deep linking: Automatic URL handling
  • Type-safe navigation: Generated route types
  • Code splitting: Automatic route-based splitting

Audio Playback

@bbplayer/orpheus

Version: 0.11.3Custom Expo module built on Android Media3 ExoPlayer and iOS AVPlayer

Why Custom Audio Module?

BBPlayer requires advanced audio features:
  • Background playback: Continues playing when app is backgrounded
  • Queue management: Next/previous track handling
  • Media session: Lock screen controls, notification integration
  • Audio focus: Proper handling of phone calls, alarms
  • Loudness normalization: Consistent volume across tracks
  • Gapless playback: Seamless track transitions
import { OrpheusPlayer } from '@bbplayer/orpheus'

const player = OrpheusPlayer.getInstance()

await player.setSource({
  uri: 'https://example.com/audio.m4s',
  title: 'Track Title',
  artist: 'Artist Name',
  artwork: 'https://example.com/cover.jpg',
})

await player.play()

Performance Optimization

Shopify FlashList

Version: 2.2.0Faster alternative to FlatList

React Native Worklets

Version: 0.8.0-nightlyRun JavaScript on UI thread

Rozenite Metro

Version: 1.3.0Metro bundler with profiling plugins

React Compiler

Version: 19.1.0-rc.1Automatic React optimizations

Rozenite Integration

Rozenite provides development-time insights:
  • MMKV Plugin: Profile storage operations
  • TanStack Query Plugin: Debug query performance
  • Require Profiler: Analyze module load times
// metro.config.js
const { getDefaultConfig } = require('@rozenite/metro')

module.exports = getDefaultConfig(__dirname, {
  plugins: [
    '@rozenite/mmkv-plugin',
    '@rozenite/tanstack-query-plugin',
    '@rozenite/require-profiler-plugin',
  ],
})

Networking & API

Hono

Version: 4.12.2Fast web framework for API routes

Protobuf.js

Version: 8.0.0Parse Bilibili’s Protocol Buffers

Cookie

Version: 1.0.2Cookie parsing for Bilibili auth

NetInfo

Version: 12.0.1Network connectivity monitoring

Bilibili API Integration

BBPlayer interacts with Bilibili’s API:
  • Authentication: Cookie-based login
  • Video metadata: Fetch video info, thumbnails, uploader
  • Audio streams: Extract audio URLs from video sources
  • Danmaku: Fetch and parse comment streams (protobuf)
  • Playlists: Access user favorites and collections
// Protobuf compilation
"prepare": "pbjs -t static-module -w commonjs -o src/lib/api/bilibili/proto/dm.js src/lib/api/bilibili/proto/dm.proto"

Developer Tools

TypeScript

Version: 5.9.3Static typing across the monorepo

Oxlint

Version: 1.47.0Fast Rust-based linter

Oxfmt

Version: 0.27.0Fast Rust-based formatter

ESLint

Version: 9.39.2Pluggable JavaScript linter

Why Oxlint?

Oxlint is 50-100x faster than ESLint:
  • Written in Rust for maximum performance
  • Runs type-aware rules without TSC overhead
  • Used alongside ESLint for complementary rules
{
  "lint": "oxlint --type-aware && eslint .",
  "lint:fix": "oxlint --type-aware --fix && eslint . --fix"
}

Testing

Jest

Version: 30.2.0JavaScript testing framework

Testing Library

Version: 13.3.3React Native component testing

Jest Expo

Version: 55.0.5Expo preset for Jest

Faker

Version: 9.9.0Generate test data

Monitoring & Analytics

Sentry

Version: 7.10.0Error tracking and performance monitoring

Firebase Analytics

Version: 23.8.6Anonymous usage analytics

Expo Insights

Version: 55.0.4App performance insights
All analytics are anonymous and opt-out. Users can disable data sharing in Settings → General → Share Data.

Backend Stack

Runtime & Framework

Cloudflare Workers

Serverless edge computing platform

Hono

Version: 4.12.2Ultrafast web framework

Wrangler

Version: 4.4.0CLI for Cloudflare Workers

Why Cloudflare Workers?

  • Edge computing: Low latency worldwide
  • Generous free tier: 100,000 requests/day
  • Zero cold starts: Instant response times
  • V8 isolates: Better than containers
  • Native TypeScript: First-class TS support

Database

PostgreSQL

Relational database

Drizzle ORM

Version: 0.44.7TypeScript ORM for PostgreSQL

Drizzle Kit

Version: 0.31.9Schema migrations and studio

Validation

ArkType

Version: 2.1.29TypeScript-first runtime validation

Hono ArkType Validator

Version: 2.0.1ArkType middleware for Hono

Why ArkType?

ArkType is 10x faster than Zod:
  • Type inference with near-zero overhead
  • Composable validation schemas
  • Better error messages
  • Smaller bundle size
import { type } from 'arktype'
import { arktypeValidator } from '@hono/arktype-validator'

const userSchema = type({
  id: 'string',
  email: 'email',
  age: 'number >= 0',
})

app.post('/users', arktypeValidator('json', userSchema), async (c) => {
  const user = c.req.valid('json') // Fully typed!
  // ...
})

Development Tools

Version Control

Lefthook

Version: 1.13.6Fast Git hooks manager

Commitlint

Version: 20.4.1Enforce conventional commits

Gitleaks

Secret scanning and prevention

Package Management

pnpm

Version: 10.26.2Fast, disk-efficient package manager

Syncpack

Version: 13.0.4Consistent dependency versions

Patch Package

Version: 8.0.1Patch node_modules files

Build & CI/CD

Mobile Builds

EAS Build

Expo Application Services for builds

EAS Update

Version: 55.0.5Over-the-air updates

Code Quality

ESLint Plugins

  • React Hooks Extra
  • Drizzle
  • TanStack Query
  • React Compiler

TypeScript ESLint

Version: 8.55.0TypeScript-specific linting

Utility Libraries

Date Handling

Day.js 1.11.19 - Lightweight date library

Color Manipulation

Color 4.2.3 - Color conversion and manipulation

Crypto

CryptoJS 4.2.0 - Encryption utilities

Result Types

Neverthrow 8.2.0 - Functional error handling

Platform-Specific Features

Android

  • Material Design 3: Native Android design system
  • Media3 ExoPlayer: Advanced audio playback
  • Edge-to-Edge: Immersive display mode
  • Gradle Plugin: Custom build configuration

iOS

  • AVPlayer: Native audio playback
  • Share Intent: Deep link handling
  • Haptics: Native haptic feedback

Next Steps

Architecture Overview

Return to the architecture overview

Monorepo Structure

Learn about workspace organization

Build docs developers (and LLMs) love