Open19

React Native 環境構築

HirotoHiroto
npx create-expo-app app --template

Navigation (TypeScript) を選択

HirotoHiroto

npm ではなく yarn を使用する

rm -rf package-lock.json
yarn
HirotoHiroto

ESLint を設定する

ライブラリインストール

npx install-peerdeps --dev eslint-config-airbnb
# It seems as if you are using Yarn. Would you like to use Yarn for the installation? (y/n) y

# ESLint の設定ファイルを追加でインストールする
npx expo install -- -D @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-airbnb-typescript eslint-plugin-react-native
# Prettier 本体と ESLint と統合するための設定ファイルを追加でインストールする
npx expo install -- -D prettier eslint-config-prettier

touch tsconfig.eslint.json .eslintrc.cjs .prettierrc.cjs

tsconfig.eslint.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "allowJs": true
  },
  "include": ["src", ".*.cjs", "index.ts", "babel.config.js"]
}

.eslintrc.cjs

module.exports = {
  root: true,
  parser: "@typescript-eslint/parser",
  plugins: ["@typescript-eslint", "eslint-plugin-react-native"],
  env: {
    browser: true,
    es2021: true,
  },
  parserOptions: {
    ecmaVersion: "latest",
    sourceType: "module",
    project: "./tsconfig.eslint.json",
    tsconfigRootDir: __dirname,
  },
  ignorePatterns: ["dist"],
  extends: [
    "airbnb",
    "airbnb-typescript",
    "airbnb/hooks",
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "plugin:react-native/all",
    "prettier",
  ],
  rules: {
    "import/prefer-default-export": "off", // named export を使用するので off にする
    "react/react-in-jsx-scope": "off", // React 17 から import の必要がなくなったため off にする
    "react/destructuring-assignment": "off", // props は props としてわかるようにしたいので off にする
    "react/no-unstable-nested-components": ["error", { allowAsProps: true }], // Tabs.Screen の options.tabBarIcon などで使用するので allowAsProps にする
  },
  overrides: [],
};

.prettierrc.cjs

module.exports = {
  printWidth: 120,
};

参考

HirotoHiroto

husky, lint-staged を導入する

husky を導入する

npx husky-init && yarn

lint-staged を導入する

yarn add -D lint-staged
touch .lintstagedrc.cjs

.lintstagedrc.cjs を作成する

module.exports = {
  "*.{js,jsx,cjs,ts,tsx}": ["eslint --fix", "prettier --write"],
  "*.{json,md,yaml}": ["prettier --write"],
};

.husky/pre-commit を編集する

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn run lint-staged
HirotoHiroto

depcheck を導入する

yarn add -D depcheck
touch .depcheckrc

.depcheckrc を作成する

ignores:
  # dependencies
  - "expo-splash-screen"
  - "expo-system-ui"
  - "react-dom"
  - "react-native-web"

  # devDependencies
  - "@babel/core"
  - "depcheck"
  - "jest"
  - "lint-staged"
  - "prettier"
  - "typescript"

depcheck を実行する

yarn run depcheck
No depcheck issue
✨  Done in 1.18s.

pre-commit で depcheck を実行する

echo "\nyarn run depcheck" >> .husky/pre-commit
HirotoHiroto

code-workspace の作成

touch expo-app.code-workspace
{
  "folders": [
    {
      "path": "."
    }
  ],
  "settings": {
    "files.associations": {
      ".depcheckrc": "yaml" // .depcheckrc の language mode の設定
    },
    "cSpell.words": ["depcheck", "depcheckrc"],
  },
  "extensions": {
    "recommendations": [
      "esbenp.prettier-vscode",
      "dbaeumer.vscode-eslint",
      "streetsidesoftware.code-spell-checker"
    ]
  }
}
HirotoHiroto

Makefile を作成する

touch Makefile
deps:
	yarn

start: deps
	yarn expo start

start/with-cache-clear: deps
	yarn expo start --clear

android: deps
	yarn expo start --android

ios: deps
	yarn expo start --ios

web: deps
	yarn expo start --web

test/jest: deps
	yarn jest --watchAll

test/tsc: deps
	yarn tsc --noEmit

lint-format: deps
	yarn eslint --fix .
	yarn prettier --write .

package.json の scripts を削除する

jq 'del(.scripts.start, .scripts.android, .scripts.ios, .scripts.web, .scripts.test)' package.json > package.json.tmp
mv -f package.json.tmp package.json
HirotoHiroto

UI ライブラリについて

expo のサイトにいくつか候補が載っている

https://docs.expo.dev/guides/userinterface/

ざっと見た感じやと以下の3つが見た目的には良さそうやった
https://github.com/wix/react-native-ui-lib
https://github.com/akveo/react-native-ui-kitten
https://github.com/tamagui/tamagui

https://npmtrends.com/react-native-ui-kitten-vs-react-native-ui-lib-vs-tamagui

ui-kitten の update が a year ago なのは気になる

tamagui は最近勢いを伸ばしている感じかな

react-native-ui-lib が無難そう

HirotoHiroto

RNUILib の導入

https://wix.github.io/react-native-ui-lib/docs/getting-started/setup
に従う

インストール

npx expo install react-native-ui-lib react-native-reanimated react-native-gesture-handler @babel/plugin-proposal-export-namespace-from

cd ios && pod install は expo を使っている場合は不要?
実行しなくても動作した

https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation/

"@babel/plugin-proposal-export-namespace-from", "react-native-reanimated/plugin", を babel.config.js の plugins の最後に追加する

コンポーネントを作成する

touch app/'(tabs)'/ReNaUiLib.tsx

ReNaUiLib.tsx

import { View, TextField, Text, Button } from "react-native-ui-lib";

export default function ReNaUiLib(): JSX.Element {
  return (
    <View flex paddingH-25 paddingT-120>
      <Text blue50 text20>
        Welcome
      </Text>
      <TextField text50 grey10 placeholder="username" />
      <TextField text50 secureTextEntry grey10 placeholder="password" />
      <View marginT-100 center>
        <Button text70 white background-orange30 label="Login" />
        <Button link text70 orange30 marginT-20 label="Sign Up" />
      </View>
    </View>
  );
}
HirotoHiroto

Jest 周りの調整

npx expo install -- -D @types/react-test-renderer @types/jest

mv components/__tests__/StyledText-test.js components/__tests__/StyledText.test.tsx 
HirotoHiroto

app, components, constants を src 下に配置する

src 下に移動

mv app components constants src

assets の require でエラーが発生するので解消する
Unable to resolve "../assets/fonts/SpaceMono-Regular.ttf" from "src/app/_layout.tsx"

参考

https://github.com/expo/router/issues/41

babel.config.jsprocess.env.EXPO_ROUTER_APP_ROOT = "../../src/app"; を設定する

HirotoHiroto

絶対パスで import ができるようにする

npx expo install -- -D babel-plugin-module-resolver

tsconfig.json の変更

{
  "compilerOptions": {
    ...
    "baseUrl": "./",
    "paths": {
      "@src/*": ["src/*"]
    }
  }
}

babel.config.js の plugins に以下を追加する

[
  "module-resolver",
  {
    alias: {
      "@src": "./src",
    },
  },
],

ファイルを変更する

find src -type f -exec sed -i "" 's#\.\./\.\./constants#@src/constants#g' {} +
find src -type f -exec sed -i "" 's#\.\./constants#@src/constants#g' {} +
find src -type f -exec sed -i "" 's#\.\./\.\./components#@src/components#g' {} +
find src -type f -exec sed -i "" 's#\.\./components#@src/components#g' {} +

参考

https://zenn.dev/pankuz/articles/91f85e1fcfbfc505781b