RORK LABEN
DEADLINE — 8月31日から、Google Play の新規アプリとアプリ更新はすべて Android 16(API レベル36)を対象にする必要があります。残り8日ですEXTENSION — 条件を満たす開発者は Play Console のフォームから11月1日までの延長を申請できます。申請そのものは締切前に済ませておく必要がありますEXISTING — 更新を出さない既存アプリも、新しい Android を載せた端末で新規ユーザーに見つけてもらうには最低 API レベル35 が必要です。静かに新規流入だけが止まる構造ですEXPO — Expo SDK 57 は React Native 0.85 から 0.86 への更新で、破壊的変更なしの1コマンド移行を狙った小さなリリースです。React は SDK 56 と同じ 19.2 のままですMEMORY — expo@57.0.9 が React Native 0.86.2 へ更新し、reanimated や worklets を読み込むアプリでメモリが大きく増える Hermes V1 の回帰を解消しましたPREBUILD — expo prebuild が既定でネイティブディレクトリを破棄して再生成するようになりました。API 36 対応で手を入れた設定と衝突しやすい部分ですDEADLINE — 8月31日から、Google Play の新規アプリとアプリ更新はすべて Android 16(API レベル36)を対象にする必要があります。残り8日ですEXTENSION — 条件を満たす開発者は Play Console のフォームから11月1日までの延長を申請できます。申請そのものは締切前に済ませておく必要がありますEXISTING — 更新を出さない既存アプリも、新しい Android を載せた端末で新規ユーザーに見つけてもらうには最低 API レベル35 が必要です。静かに新規流入だけが止まる構造ですEXPO — Expo SDK 57 は React Native 0.85 から 0.86 への更新で、破壊的変更なしの1コマンド移行を狙った小さなリリースです。React は SDK 56 と同じ 19.2 のままですMEMORY — expo@57.0.9 が React Native 0.86.2 へ更新し、reanimated や worklets を読み込むアプリでメモリが大きく増える Hermes V1 の回帰を解消しましたPREBUILD — expo prebuild が既定でネイティブディレクトリを破棄して再生成するようになりました。API 36 対応で手を入れた設定と衝突しやすい部分です
記事一覧/開発ツール
開発ツール/2026-07-09上級

生成のたびに崩れるレイヤ境界を、CIで守る — Rork製Expoアプリの依存ルール機械化

Rorkが生成したExpoアプリを長く運用すると、画面から直接APIクライアントを叩くimportが静かに増えていきます。ESLintのゾーン制約とdependency-cruiserで依存の向きを機械化し、CIで落とすまでの実装を残します。

Rork543Expo180アーキテクチャ21ESLintCI5

プレミアム記事

半年ぶりに触った画面コンポーネントの先頭で、import { supabase } from "../../lib/supabaseClient" という行を見つけました。

その画面は本来、フックを経由してデータを受け取るはずのものでした。けれど生成と手直しを重ねるうちに、いつの間にか最短距離が選ばれていました。責める相手はいません。私自身が「今日はここだけ」と通した一行が、次の生成で参照され、さらに次の画面へ複製されていきます。

個人開発でアプリを複数本抱えていると、この種の劣化は静かに進みます。レビューする人がいないのですから、当然といえば当然です。ならば、レビュアーの役割を機械に肩代わりしてもらうより他にありません。

扱わないことを先に書いておきます。理想的なレイヤ構成の議論はしません。すでに App Store で配信中のアプリを、今の構成のまま「これ以上は崩さない」状態へ持っていく話に絞ります。

「境界」を守る前に、境界を宣言する

依存ルールを機械化するとき、最初につまずくのは「どこが境界なのか誰も書いていない」点でした。頭の中にはあるのに、ファイルには存在しません。

私は既存のディレクトリ構成をそのまま採用し、依存の向きだけを一枚の表に落としました。新しい構成を発明せず、いま在るものに名前を付ける。これだけで作業量が大きく変わります。

レイヤ実際のパスimportしてよい先
app(画面)app/**features, ui, shared
features(機能)src/features/**同一feature内, data, ui, shared
data(取得・永続化)src/data/**shared のみ
ui(見た目のみ)src/ui/**shared のみ
shared(型・定数・純関数)src/shared/**なし(葉)

ここで大事なのは、features 同士の横断を禁じている点です。Rork に「お気に入り画面にも通知バッジを出して」と頼むと、features/favorites から features/notifications を直に呼ぶコードが出てきます。動きます。動きますが、片方を作り直したい日に、もう片方が人質になります。

横断が必要なら shared に型を、data にクエリを置く。判断が要る場面を、判断が要らない場面へ寄せていく作業です。

ESLint で「書けないようにする」

まず効いたのは ESLint の no-restricted-imports でした。エディタ上で赤線が出るため、生成直後の私がその場で気づけます。CI で落ちるより一日早い。

Flat Config でゾーンごとに設定します。

// eslint.config.js
import tseslint from "typescript-eslint";
 
/** レイヤごとの禁止 import パターン */
const layerRules = {
  "src/data/**": ["@/features/*", "@/ui/*", "@/app/*"],
  "src/ui/**": ["@/features/*", "@/data/*", "@/app/*"],
  "src/shared/**": ["@/features/*", "@/data/*", "@/ui/*", "@/app/*"],
  "app/**": ["@/data/*"], // 画面から直接データ層を触らせない
};
 
export default tseslint.config(
  ...Object.entries(layerRules).map(([files, patterns]) => ({
    files: [files],
    rules: {
      "no-restricted-imports": [
        "error",
        {
          patterns: patterns.map((group) => ({
            group: [group],
            message: `${files} からこの層への import は許可されていません。shared 経由に置き換えてください。`,
          })),
        },
      ],
    },
  })),
);

message を丁寧に書く理由があります。半年後の私は、なぜ禁止されているかを覚えていません。エラーメッセージが唯一の設計ドキュメントとして残ります。実際、この一行があるかないかで、迂回の質が変わりました。メッセージがないと // eslint-disable-next-line が生えます。

ただし ESLint だけでは足りません。app/screens/Home.tsx../../data/client のような相対パスで抜けてくると、パターンによっては素通りします。そして循環依存は原理的に見えません。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
レイヤ違反214件・循環依存17件を、baseline方式で新規ゼロに固定した手順
ESLint no-restricted-imports のゾーン設定と dependency-cruiser ルールの実コード
CI実行時間を38秒だけ増やして、差分のみ厳格化する段階導入の設計
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

関連記事

開発ツール2026-07-30
Renovate が触ってよい依存と、触ってはいけない依存 — Expo SDK 57 の123パッケージを機械的に切り分ける
Rork 生成アプリに依存の自動更新を入れると、Expo が版を管理している123パッケージまで巻き込まれます。2026年7月30日時点の実測では、うち6件が npm の最新版へメジャー更新される差でした。除外リストを手で書かず SDK から機械生成する手順をまとめます。
開発ツール2026-06-15
Rork Max の Swift 生成と Expo 版の責務分界 — どこまでをノーコードに任せ、どこから手で書くか
Rork Max が Swift ネイティブ生成に対応し、通常の Rork は引き続き Expo(React Native)を生成します。2つの生成エンジンを1つのアプリ事業の中でどう使い分けるか、責務の線引きを実アプリの運用視点で設計します。
開発ツール2026-03-10
RorkのReact Native + Expoアーキテクチャを深掘り解説
RorkがReact NativeとExpoをどう組み合わせてクロスプラットフォーム開発を実現しているかを掘り下げます。マネージドワークフローとベアワークフローの違い、Expo Goでのテスト、EAS、状態管理、Expo Routerによるナビゲーションまでを解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →