2025年3月にByteDanceが発表したLynxは、iOS/Android/Web/デスクトップ向けのアプリケーションを開発するための新しいフレームワークです。Lynxは、React NativeやFlutterなどの既存のクロスプラットフォームフレームワークと同じく、開発者が一つのコードベースで複数のプラットフォームに対応したアプリケーションを構築できるように設計されています。

今回は、このLynxの基本情報と、React Nativeとの違いについて解説します。

Lynxとは

Lynxを開発したのはByteDance社で、TikTokの開発元として知られています。そのため、すでにTikTokの中でも使われているとのことです。対応プラットフォームは以下の通りです。

  • iOS
  • Android
  • Web

バージョン3.4で、OpenHarmony(HuaweiのオープンソースOS)に対応予定です。また、3.5にてmacOSとWindowsに対応予定となっています。

Lynxの特徴

Lynxは、前述のクラスプラットフォームサポートに加えて、以下の特徴を持っています。

  • React/CSSによるアプリ開発
  • 高速なパフォーマンス

React/CSSによるアプリ開発

Lynxは、ReactとCSSを使用してアプリケーションを開発します。これにより、開発者は既存のReactの知識を活かして、簡単にアプリケーションを構築できます。CSSもWeb標準のものが利用でき、フロントエンドエンジニアにとって使いやすいはずです。

スタイルの例です。

function App() {
  return (
    <view
      style={{
        flexDirection: "column",
        marginTop: "50%",
        transform: "translate(-50%, -50%)",
        marginLeft: "50%",
        width: "150px",
        height: "150px",
      }}
      class="bg-gradient"
    >
    </view>
  );
}

高速なパフォーマンス

Lynxでは、独自のJavaScriptエンジンのPrimJSを利用しています。PrimJSは、ES2019をサポートしたJavaScriptエンジンで、軽量さと高いパフォーマンスを売りとしています。Chrome DevTools Protocolをサポートしており、デバッグも可能です。

また、デュアルスレッドアーキテクチャを特徴としており、メインスレッドでスクリプトやレイアウトの処理、グラフィックスレンダリングを行います。バックグラウンドスレッドでは、画面表示に影響しないタスクを実行することで、パフォーマンスの向上を図っています。なお、バックグラウンドスレッドは、ES6をサポートしているとのことです。

JavaScript Runtime - Lynx

開発環境

開発する際には、以下の環境が必要です。

  • Node.js 18.x以上

iOS向けに開発する際には、macOSが必要です。iOSアプリとしてのビルドする際にも、やはりmacOSが必要になります。Windowsでの開発については詳しく調べておりませんが、デバッグツールなどもmacOS向けのみ提供されています。

デュアルスレッドについて

Lynxのデュアルスレッドでは、若干の注意が必要なようです。

コードは2回実行される

Reactコンポーネントをレンダリングする際に、コードが2回実行されるとのことです。

const HelloComponent = () =>; { 
 console.log("Hello"); // これは2回表示されます   
 return <text>;こんにちは</テキスト>;。
};

これはメインスレッドとバックグラウンドスレッドの両方で実行されるためです。

1回しか実行されないものもある

Thinking in ReactLynx - Lynxによると、幾つかの処理はバックグラウンドスレッドでのみ実行されます。ReactLynxはLynxの公式なReactライブラリで、ReactのAPIをLynxに最適化したものです。

  • イベントハンドラ
  • useEffectやuseLayoutEffect
  • ref propsとuseImperativeHandle
  • background only を指定したディレクティブ
  • import 'background-only' を使った場合

バックグラウンド専用のコードはバックグラウンドでのみ呼び出せる

バックグラウンド用として定義されたコードを別なモジュールから呼び出す場合、 'background only'; を定義した処理内でのみ呼び出せます。

import { backgroundOnlyFunction } from 'external-module';

backgroundOnlyFunction(); // ❌ Error: ここでは呼び出せない

export function App() {
  function backgroundOnly() {
    'background only';
    fetch();
    NativeModules.call();
    backgroundOnlyFunction(); // ✅ Correct:  background only で定義された中では実行できる
  }

  backgroundOnly(); // ❌ Error: ここでは呼び出せない

  useEffect(() => {
    backgroundOnly(); // ✅ Correct: useEffectはバックグラウンドスレッドで実行される
  }, []);

  return <view />;
}

React Nativeとの違い

Lynxを使う上で、一番気になるのはReact Nativeとの違いでしょう。以下に、LynxとReact Nativeの違いをまとめました。

特徴 Lynx React Native
開発元 ByteDance Meta
プラットフォーム iOS/Android/Web/デスクトップ iOS/Android/Web ※1
アーキテクチャ デュアルスレッドアーキテクチャ シングルスレッドアーキテクチャ
スタイル設定 CSS 独自のスタイルシート
エコシステム まだ小さい 大きなコミュニティ

※1 MicrosoftがReact Native for Windows + macOS · Build native Windows & macOS apps with Javascript and Reactを提供していますが公式ではありません

パフォーマンスについては計測した訳ではありませんが、Lynxの方が優れているという意見が多いようです。現状では、Lynxはまだ新しいフレームワークであり、エコシステムが小さいため、React Nativeの方が情報は多いです。特に、React Nativeは大規模なコミュニティと豊富なライブラリが存在します。こうした点においては、Lynxを選択した際には、自分で調べながら実装していく必要があると言えるでしょう。

ネイティブAPIの利用

iOSやAndroidのネイティブ機能を利用する際には、自分でモジュールを開発します。現状、コミュニティなどで提供されているモジュールは見当たりませんでした。

Native Modules - Lynx

Lynxの始め方

Lynxの始め方は、以下のようになります。以下のコマンドでベースを生成します。

npm create rspeedy@latest

実行すると、プロジェクト名とJavaScript/TypeScriptの選択を求められます。プロジェクト名は、任意の名前を指定してください。完了したら、プロジェクトのディレクトリに移動し、必要なライブラリをインストールします。

cd プロジェクト名
npm install

そして、プレビルドサーバーを開始します。

npm run dev

これで、サーバーが立ち上がります。macOSの場合はLynx Explorerアプリをダウンロードし、iOSシミュレータにドラッグ&ドロップしてインストールします。このLynx Explorerを立ち上げて、プレビルドサーバーが指定するURLにアクセスすれば、アプリが表示されます。

実際の開発時はホットリロードが有効になっているので、さくさくと開発が進められます。

Androidの場合も同じくLynx ExplorerをダウンロードしてAndroidエミュレータで実行するか、実機で実行します。

初期に生成される src/App.tsx は以下のようになっています。 onTap はUI生成側ではないので、バックグラウンドスレッドを指定しています。メインスレッドとバックグラウンドスレッドの使い分けがLynx使いこなしのポイントになりそうです。

import { useCallback, useEffect, useState } from "@lynx-js/react"

import "./App.css"
import arrow from "./assets/arrow.png"
import lynxLogo from "./assets/lynx-logo.png"
import reactLynxLogo from "./assets/react-logo.png"

export function App() {
  const [alterLogo, setAlterLogo] = useState(false)

  useEffect(() => {
    console.info("Hello, ReactLynx")
  }, [])

  const onTap = useCallback(() => {
    "background only"
    setAlterLogo(!alterLogo)
  }, [alterLogo])

  return (
    <view>
      <view className="Background" />
      <view className="App">
        <view className="Banner">
          <view className="Logo" bindtap={onTap}>
            {alterLogo
              ? <image src={reactLynxLogo} className="Logo--react" />
              : <image src={lynxLogo} className="Logo--lynx" />}
          </view>
          <text className="Title">React</text>
          <text className="Subtitle">on Lynx</text>
        </view>
        <view className="Content">
          <image src={arrow} className="Arrow" />
          <text className="Description">Tap the logo and have fun!</text>
          <text className="Hint">
            Edit<text style={{ fontStyle: "italic" }}>{" src/App.tsx "}</text>
            to see updates!
          </text>
        </view>
        <view style={{ flex: 1 }}></view>
      </view>
    </view>
  )
}

まとめ

今回は新しく登場したマルチプラットフォーム対応のアプリフレームワークであるLynxを紹介しました。まだリリースして間もないですが、開発に必要な機能は揃っており、今後に期待ができそうです。CordovaやReact Native、Flutterなどのフレームワークと比較して、どのような差別化ができるのか、今後の動向に注目です。

Lynx