📱

Expoの各種設定ファイルの使い分け

2024/12/07に公開

この記事はReact Native 全部俺 Advent Calendar 7日目の記事です。

https://adventar.org/calendars/10741

このアドベントカレンダーについて

このアドベントカレンダーは @itome が全て書いています。

基本的にReact NativeおよびExpoの公式ドキュメントとソースコードを参照しながら書いていきます。誤植や編集依頼はXにお願いします。

Expoの設定ファイル

Expoでアプリ開発をしていると、多くの設定ファイルがプロジェクトの一番上の階層に並びます。中には似たような設定を扱うためのファイルもあって初めのうちは混乱しがちなので、それらをまとめて解説します。

package.json

{
  "name": "test-react-native",
  "main": "expo-router/entry",
  "version": "1.0.0",
  "scripts": {
    "start": "expo start",
    "reset-project": "node ./scripts/reset-project.js",
    "android": "expo run:android",
    "ios": "expo run:ios",
    "web": "expo start --web",
    "test": "jest --watchAll",
    "lint": "expo lint"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/vector-icons": "^14.0.2",
    "@react-navigation/bottom-tabs": "^7.0.0",
    "@react-navigation/native": "^7.0.0",
    "expo": "~52.0.11",
    "expo-blur": "~14.0.1",
    "expo-constants": "~17.0.3",
    "expo-font": "~13.0.1",
    "expo-haptics": "~14.0.0",
    "expo-linking": "~7.0.3",
    "expo-router": "~4.0.9",
    "expo-splash-screen": "~0.29.13",
    "expo-status-bar": "~2.0.0",
    "expo-symbols": "~0.2.0",
    "expo-system-ui": "~4.0.4",
    "expo-web-browser": "~14.0.1",
    "react": "18.3.1",
    "react-dom": "18.3.1",
    "react-native": "0.76.3",
    "react-native-gesture-handler": "~2.20.2",
    "react-native-reanimated": "~3.16.1",
    "react-native-safe-area-context": "4.12.0",
    "react-native-screens": "~4.1.0",
    "react-native-web": "~0.19.13",
    "react-native-webview": "13.12.2"
  },
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@types/jest": "^29.5.12",
    "@types/react": "~18.3.12",
    "@types/react-test-renderer": "^18.3.0",
    "eslint": "^8.57.0",
    "eslint-config-expo": "~8.0.1",
    "jest": "^29.2.1",
    "jest-expo": "~52.0.2",
    "react-test-renderer": "18.3.1",
    "typescript": "^5.3.3"
  },
  "private": true
}

Node.jsプロジェクトの依存パッケージやバージョン管理、スクリプトの管理をするためのファイルです。使いたい外部パッケージがある場合はこのファイルのdependenciesにパッケージ名とバージョンを入れることでインストールすることができます。npm install <パッケージ名>をすることで自動でpackage.jsonを更新することができるので、基本的にはコマンドを使ってインストールをして、dependenciesを直接書くのは避けましょう。

tsconfig.json

{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    "paths": {
      "@/*": [
        "./*"
      ]
    }
  },
  "include": [
    "**/*.ts",
    "**/*.tsx",
    ".expo/types/**/*.ts",
    "expo-env.d.ts"
  ]
}

Typescriptの各種設定をするためのファイルです。多くのオプションがありますが、"extends": "expo/tsconfig.base",の部分でExpoの推奨オプションがすでに設定されているので基本的には何も触らなくて大丈夫です。
Expoのテンプレートで生成されるtsconfig.jsonの特徴を一点挙げるとすればcompilerOptions > pathsが最初から設定されていることです。これにより以下のようにファイルのインポートを絶対パスでできるようになります。

import { A } from "../../utils/some_file"

import { A } from "@/utils/some_file"

実は本来、絶対パスの設定を正しく動かすためにはtsconfig.jsonだけでなくバンドラ(React Nativeではのちに説明するmetro)の設定も同様に行う必要があるのですが、Expoを使っていればtsconfig.jsonの設定をもとにバンドラの設定もよしなにやってくれるので、絶対パスの設定を変更したい場合はここを書き換えるだけで済みます。

metro.config.js

const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");

module.exports = withNativeWind(getDefaultConfig(__dirname), {
  input: "./src/global.css",
});

React Nativeで使われているMetroというバンドラの設定ファイルです。
バンドラとは複数のJavaScriptを一つにまとめるために使われるツールのことです。同様のツールとしてwebpackなどが有名ですね。
このファイルはプロジェクトのテンプレートには含まれていないため、デフォルトの設定をカスタマイズしたい場合は自分でこのファイルを作る必要があります。
使っているライブラリなどでmetro.config.jsの書き換えが求められていない限りカスタマイズする必要はないです。

babel.config.js

module.exports = (api) => {
  api.cache(true);
  return {
    presets: [
      ["babel-preset-expo", { jsxImportSource: "nativewind" }],
      "nativewind/babel",
    ],
  };
};

JavaScript開発で使われるBabelというトランスパイラに関する設定ファイルです。これもmetro.config.jsと同様にプロジェクトに最初からあるわけではないので、必要に応じて自分で作成する必要があります。
使っているライブラリなどでbabel.config.jsの書き換えが求められていない限りカスタマイズする必要はないです。

app.json(app.config.json)

{
  "expo": {
    "name": "test-react-native",
    "slug": "test-react-native",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/images/icon.png",
    "scheme": "myapp",
    "userInterfaceStyle": "automatic",
    "newArchEnabled": true,
    "ios": {
      "supportsTablet": true,
      "bundleIdentifier": "com.itometeam.test-react-native"
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/images/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      }
    },
    "web": {
      "bundler": "metro",
      "output": "static",
      "favicon": "./assets/images/favicon.png"
    },
    "plugins": [
      "expo-router",
      [
        "expo-splash-screen",
        {
          "image": "./assets/images/splash-icon.png",
          "imageWidth": 200,
          "resizeMode": "contain",
          "backgroundColor": "#ffffff"
        }
      ]
    ],
    "experiments": {
      "typedRoutes": true
    }
  }
}

Expoはネイティブコードの管理をしなくていいことが大きな特徴ですが、アプリ名の変更や通知の設定など、どうしてもネイティブ側の設定にアクセスしなければならないケースがあります。
それらは通常であればxcodeprojファイルやbuild.gradleファイルに書くべき設定ですが、Expoでは代わりにapp.jsonをカスタマイズすることで、それらの値を変更することができます。

eas.json

{
  "cli": {
    "version": ">= 13.2.1",
    "appVersionSource": "remote"
  },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal"
    },
    "production": {
      "autoIncrement": true
    }
  },
  "submit": {
    "production": {}
  }
}

EAS(Expo App Services)の設定を書くためのファイルです。app.jsonと混同しがちですが、app.jsonはアプリの静的な設定を変更するためのファイルで、eas.jsonはアプリのビルド環境やビルド方法に関する設定を書くためのファイルというふうに理解しておきましょう。

まとめ

これらの設定ファイルは互いに補完し合う関係にあり、Expoアプリの異なる側面をカバーしています。初期段階ではapp.jsonの基本設定だけで十分ですが、アプリが成長するにつれて他の設定ファイルも活用していきましょう。

Discussion