2022-10-08

ExpoのConfig PluginをTypeScriptで開発する環境を整える

ExpoのConfig Pluginを独自で作成する場合コードはJavaScriptで記述できますが、コード量が増えてきたり複雑な処理を行うPluginを作成したい場合、型のサポートの恩恵を受けられるためTypeScriptを利用するのがおすすめです。

この記事ではConfig PluginをTypeScriptで作成するための設定やテストの設定について説明します。

記載の内容は以下の公式のドキュメントを元にしています。

Config Plugin用のtsconfig.json

Config PluginはNode.js(LTS)で実行されるため、TypeScriptでコードを書いた場合Node.jsで実行可能なJavaScriptにTranspileする必要があります。

React NativeアプリのソースコードもTypeScriptで記述することができますが、トランスパイルするターゲットがConfig Pluginとは異なる(ES6やJSXがサポートされている)ため、同じtsconfig.jsonを共有することはできません。そのためConfig Plugin用に別途tsconfig.jsonを用意する必要があります。

expo-module-scripts

expoがユーティリティとして用意しているexpo-module-scriptsというライブラリが存在します。これはExpoのモジュールやSDKが共通で利用しているスクリプトや設定をまとめたものになります。

Config Plugin用のtsconfig.jsonを用意してくれたり、Pluginのビルドを行うためのコマンドツール等を提供してくれます。利用する場合はインストールしておきます。

yarn add --dev expo-module-scripts

必ずしもこれを利用する必要はなく、もしも使わない場合は独自でtsconfig.jsonの記述やビルド用のスクリプトを用意する形になります。

フォルダ構成

Config Plugin関連のファイルはすべてpluginフォルダに配置します。expo-module-scriptsのトランスパイル用のスクリプトがこの名前のフォルダ名であることを前提としているため、名前をそれに合わせます。別の名前にしても問題ありませんが、その場合はビルド用のスクリプトを自身で用意する必要があります。

tsconfig.jsonはplugin/tsconfig.jsonに配置します。expo-module-scriptsが用意したtsconfigを継承しています。

{
  "extends": "expo-module-scripts/tsconfig.plugin",
  "compilerOptions": {
    "outDir": "build",
    "rootDir": "src"
  },
  "include": ["./src"],
  "exclude": ["**/__mocks__/*", "**/__tests__/*"]
}

ソースコードはplugin/srcに配置し、トランスパイルされたコードはplugin/buildに吐かれます。

Config Pluginを配置

実際にTypeScriptで書かれたConfig Pluginをsrc配下に配置します。

plugin/src/withExample.ts

import { ConfigPlugin } from "@expo/config-plugins"

type Props = { name: string }

export const withExample: ConfigPlugin<Props> = (config, props) => {
  console.log("withExample()")
  config.name = props.name
  return config
}

plugin/src/index.ts

import { ConfigPlugin } from "@expo/config-plugins"
import { withExample } from "./withExample"

const withPlugins: ConfigPlugin = config => {
  config = withExample(config, { name: "hello" })
  return config
}

export default withPlugins

この状態で以下のコマンドを実行するとplugin/build配下にトランスパイルされたjsファイルが生成されます。

EXPO_NONINTERACTIVE=1 npx expo-module build plugin

EXPO_NONINTERACTIVE=1を指定しているのは指定しないとwatchモードになるためです。逆にwatchする場合はこれを外せばOKです。

PluginをPrebuild時に実行するようにするには、app.json(またはapp.config.js)にpluginsの設定を追加します。

{
  "expo": {
    ...
    "plugins": ["./plugin/build"]
  }
}

jestでのテストの設定

jestでテストができるようするにはまずjestをインストールし

yarn add --dev jest

plugin/jest.config.jsを配置します。

module.exports = {
  ...require("expo-module-scripts/jest-preset-plugin"),
  testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$",
}

ここでもexpo-module-scriptsが提供するjestの設定を利用しています。testRegexを指定し直しているのはsample.test.tsのような形式で配置した場合にテスト対象と認識されないためです。このあたりは自身の利用したい形式に合わせて設定を変えればよいと思います。

実際にテストファイルを配置し

plugin/src/withExample.test.ts

import { withExample } from "./withExample"

describe("withExample", () => {
  it("sets name in config", () => {
    const config = {}
    const result = withExample(config as any, { name: "hello" })
    expect(result.name).toBe("hello")
  })
})

以下のコマンドでテストを実行します。

npx expo-module test plugin

スクリプトをpackage.jsonに追加

ビルドやテスト時に利用するコマンドはpackage.jsonに以下のように設定しておくとよいです。

"scripts": {
  ...
  "plugin:build": "EXPO_NONINTERACTIVE=1 expo-module build plugin",
  "plugin:watch": "expo-module build plugin",
  "plugin:test": "expo-module test plugin",
}

Config Pluginの実行を手元で検証する

Config Pluginが実際に問題なく動作するかどうかをローカルで確かめるにはexpo prebuildを実行します。

expo prebuild

実行後、Config Pluginで設定した内容がPrebuild時に実際に反映されているかを確認します。

実際の設定サンプル

今回おこなった設定を反映した実際のプロジェクトサンプルを以下で確認できます。

https://github.com/gaishimo/rn-expo-sandbox/tree/config-plugin-dev

最終更新: 2022-10-08 08:20
筆者: @gaishimo 主にReact Nativeでのアプリ開発を行っています。
© 2021 Omoidasu, Inc. All rights reserved.