Mobile Development 14 min read

Luna: An In‑App Debugging Tool for React Native in Production Environments

Luna is an in‑app debugging tool for React Native that works in non‑development environments, offering a floating trigger and a half‑screen panel with Log, Network, Redux, and Shopee sections, automatically injected via a simple init call and HOC, enabling real‑time inspection of console output, HTTP traffic, state and app metadata.

Shopee Tech Team
Shopee Tech Team
Shopee Tech Team
Luna: An In‑App Debugging Tool for React Native in Production Environments

React Native (RN) is widely used by Shopee's front‑end team, but its development and debugging workflow is far less friendly than that of Mobile Web, especially when debugging runtime issues in non‑development environments such as Test and UAT.

In development mode RN provides official debugging tools, but they are weaker than browser DevTools and become unusable once the RN code is bundled for production. Existing RN debugging tools either lack features or only work in development mode, leaving developers to rely on manual, time‑consuming methods.

Luna is introduced as a solution that enables in‑app debugging for RN applications running in non‑development environments. It consists of a floating orange trigger button and a half‑screen panel that contains four sections: Log, Network, Redux, and Shopee.

Log intercepts console.log (and other console methods), collects uncaught errors, and displays them in reverse chronological order with type‑based filtering and fuzzy search.

Network captures every HTTP request by overriding XMLHttpRequest, recording request/response headers, bodies, status, duration, and presenting them in a detailed list.

Shopee provides shortcuts for translation, cookie inspection, DataStore viewing/deletion, and displays user ID, device info, and version details.

Redux visualises the entire Redux store tree, allowing developers to inspect the current state.

The project follows a monorepo architecture with three packages: Core, Shopee Plugin, and Redux Plugin. The Core package implements the Log, Network, and Plugin integration modules.

To minimise the integration effort across multiple RN pages, Luna decouples initialization from page registration. The initialization code is executed once at app start:

import Luna from "@shopee/luna";
Luna.init();

Each page is wrapped by a higher‑order component (HOC) provided by the Shopee Plugin, automatically injecting Luna without manual imports. An ErrorBoundary is also added to capture runtime errors and surface them inside Luna.

The Log module overrides the global console and ErrorUtils to collect logs:

export const overrideConsole = (consoleStore) => {
  const mixinType = [
    LOG_TYPE.LOG,
    LOG_TYPE.ERROR,
    LOG_TYPE.WARN,
    LOG_TYPE.DEBUG,
    LOG_TYPE.INFO,
  ];
  mixinType.forEach((type) => {
    // @ts-ignore
    const originConsoleFun = global.console[type];
    // @ts-ignore
    global.console[type] = (...params) => {
      consoleStore.addLog(params, type);
      originConsoleFun(...params);
    };
  });
};

Log rendering uses a custom tree component with lazy loading for large arrays/objects, line‑wrapping for long texts, and a FlatList with generated IDs to ensure smooth scrolling. Logs are displayed in reverse order so the most recent entries appear at the top, reducing the need for users to scroll.

The Network module overrides XMLHttpRequest methods to capture request details:

export const overrideNetwork = (consoleStore) => {
  originOpen = XMLHttpRequest.prototype.open;
  const originSetHeader = XMLHttpRequest.prototype.setRequestHeader;
  XMLHttpRequest.prototype.open = function (...args) {
    this._xmlItem = { openData: args };
    this.addEventListener("load", () => {
      const xmlItem = this._xmlItem;
      const requestHeaders = this._requestHeaders;
      const endTime = new Date().getTime();
      const time = endTime - xmlItem.startTime;
      consoleStore.addNetworkLog({
        url: this.responseURL,
        method: xmlItem.openData[0],
        status: this.status,
        rspHeader: this.getAllResponseHeaders(),
        response: this.response,
        body: xmlItem.sendData,
      });
    });
    originOpen.apply(this, args);
  };
};

Network entries are displayed with URL path highlighting, status‑based background colours, and adaptive time units.

Luna’s plugin mechanism separates optional functionality (e.g., Shopee SDK integration, Redux state inspection) from the core, allowing developers to add custom plugins in a Vue‑like install‑use style without an explicit install step.

Future work includes automated, zero‑code Luna injection during deployment (active only in dev/test environments) and a component‑tree state viewer similar to React DevTools for RN.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

mobile developmentPerformanceplugin architectureReact NativeIn‑App Tools
Shopee Tech Team
Written by

Shopee Tech Team

How to innovate and solve technical challenges in diverse, complex overseas scenarios? The Shopee Tech Team will explore cutting‑edge technology concepts and applications with you.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.