契約しているプランを見直そうとして、手が止まることがあります。「下げたあと、いま作っているアプリは手元に残るのだろうか」という不安です。
Rork の FAQ(2026年10月時点)には、コードの書き出しについて次のように書かれています。有料プランでは生成したコードの所有権があり、GitHub 連携で書き出せること。Rork Pro は React Native / Expo のプロジェクト、Rork Max は SwiftUI の Xcode プロジェクトとして出てくること。連携は双方向の同期であること。ここまでは明記されています。
一方で、プランを下げたあとにプロジェクトがどう扱われるかは、私が読んだ FAQ の範囲では確認できませんでした。 書かれていないことを前提にはできません。個人開発でいくつものアプリと契約を抱えていると、サブスクの見直しは定期的に巡ってきます。私自身、契約を動かす前には必ず「戻れる場所が手元にあるか」を先に確かめるようにしています。ですから「有料のうちに、GitHub から取り直して、組み直せるところまで確かめておく」ことを、プラン変更の前の作業にしています。
書き出しただけでは、まだ半分です。取り出したフォルダが、Rork の外で本当に組み直せる形かどうかは、別の確認が要ります。
「書き出せた」と「組み直せる」は別の話です
GitHub に同期されたことは、画面で確かめられます。けれど、別のパソコンで git clone して動くかどうかは、動かすまで分かりません。起こりやすいのは、次のようなずれです。
- lock ファイルが無い、あるいは複数あって、依存の版が再現できない
app.jsonにストア用の識別子(iOS の bundleIdentifier、Android の package)が入っていない- アイコンやスプラッシュの画像を
app.jsonが指しているのに、ファイルが取り直した側に無い - コードの相対 import が、存在しないファイルを指している
- コードが
EXPO_PUBLIC_で始まる環境変数を読んでいるのに、その名前がどこにも控えられていない
最後の項目は見落としやすい点です。.env は秘密を含むので GitHub に載せない運用が普通ですが、その結果、どんな名前の値を用意し直せばよいのかも一緒に消えてしまいます。 名前だけを書いた .env.example が要るのは、このためです。
取り直したフォルダを調べるスクリプトです
次のスクリプトは、依存のインストールもビルドも行いません。ファイルを読んで、上の5種類のずれを数えるだけです。標準ライブラリだけで動くので、Python 3 があればそのまま実行できます。rebuild_check.py という名前で保存してください。
#!/usr/bin/env python3
"""rebuild_check.py — 取り直したフォルダが、Rork の外で組み直せる形かを静的に確かめます。"""
import json, re, sys
from pathlib import Path
root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
problems, notes = [], []
# 1. package.json と lock ファイル
pkg_path = root / "package.json"
if not pkg_path.exists():
sys.exit("package.json がありません。取り直したフォルダの場所を確かめてください。")
pkg = json.loads(pkg_path.read_text(encoding="utf-8"))
deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
locks = [n for n in ("package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lock", "bun.lockb") if (root / n).exists()]
if not locks:
problems.append("lock ファイルがありません(依存の版が再現できません)")
elif len(locks) > 1:
problems.append(f"lock ファイルが複数あります: {', '.join(locks)}")
for need in ("expo", "react", "react-native"):
if need not in deps:
problems.append(f"dependencies に {need} がありません")
if "start" not in pkg.get("scripts", {}):
notes.append("scripts.start がありません(npx expo start で代用できます)")
# 2. app.json の識別子と、参照している画像
cfg_path = root / "app.json"
if cfg_path.exists():
cfg = json.loads(cfg_path.read_text(encoding="utf-8")).get("expo", {})
if not cfg.get("ios", {}).get("bundleIdentifier"):
problems.append("ios.bundleIdentifier が未設定です")
if not cfg.get("android", {}).get("package"):
problems.append("android.package が未設定です")
refs = [cfg.get("icon"), cfg.get("splash", {}).get("image"),
cfg.get("android", {}).get("adaptiveIcon", {}).get("foregroundImage")]
for ref in filter(None, refs):
if not (root / ref).exists():
problems.append(f"app.json が指す画像がありません: {ref}")
else:
notes.append("app.json がありません(app.config.* の場合は手で確認してください)")
# 3. 相対 import の行き先と、環境変数の名前
src = [p for p in root.rglob("*") if p.suffix in (".ts", ".tsx", ".js", ".jsx")
and not {"node_modules", ".git", "ios", "android"} & set(p.parts)]
imp = re.compile(r"""(?:from\s+|require\(\s*|import\(\s*)['"](\.{1,2}/[^'"]+)['"]""")
exts = ["", ".ts", ".tsx", ".js", ".jsx", ".json", "/index.ts", "/index.tsx", "/index.js"]
used_env = set()
for p in src:
text = p.read_text(encoding="utf-8", errors="ignore")
for m in imp.finditer(text):
base = (p.parent / m.group(1)).resolve()
if not any(Path(str(base) + e).is_file() for e in exts):
problems.append(f"{p.relative_to(root)} の import 先がありません: {m.group(1)}")
used_env |= set(re.findall(r"process\.env\.(EXPO_PUBLIC_[A-Z0-9_]+)", text))
listed = set()
for name in (".env.example", ".env.local.example"):
f = root / name
if f.exists():
listed |= set(re.findall(r"^([A-Z0-9_]+)=", f.read_text(encoding="utf-8"), re.M))
for name in sorted(used_env - listed):
problems.append(f"{name} をコードが読んでいますが、.env.example に名前がありません")
print(f"確認したフォルダ: {root.name} / ソースファイル {len(src)} 本")
for n in notes:
print(" 補足:", n)
for p in problems:
print(" 要対応:", p)
print("結果:", "組み直しに必要なものは揃っています" if not problems else f"{len(problems)} 件の要対応があります")
sys.exit(1 if problems else 0)使い方は3行です。GitHub から新しいフォルダへ取り直し、そこでスクリプトを走らせます。手元で作業中のフォルダではなく、取り直したフォルダで走らせるのが要点です。 作業中のフォルダには、まだ同期されていないファイルが混ざっていて、確認の意味が薄れるためです。
git clone <GitHub のリポジトリ URL> rebuild-test
cd rebuild-test
python3 ../rebuild_check.py .確かめた範囲と、確かめていない範囲です
正直にお伝えします。このスクリプトは、私が用意した2つの小さな見本フォルダで動かしました。実際の Rork の書き出しに対して走らせた結果ではありません。見本は、揃っているものと、わざと欠けさせたものの2種類です。
揃っている見本では、次のように出ました。
確認したフォルダ: good / ソースファイル 2 本
結果: 組み直しに必要なものは揃っています欠けさせた見本(lock が2種類、react と react-native が無い、android.package が無い、画像が無い、import 先が無い、環境変数の名前が控えられていない)では、7件を拾いました。
要対応: lock ファイルが複数あります: package-lock.json, yarn.lock
要対応: dependencies に react がありません
要対応: dependencies に react-native がありません
要対応: android.package が未設定です
要対応: app.json が指す画像がありません: ./assets/icon.png
要対応: app/index.tsx の import 先がありません: ../lib/util
要対応: EXPO_PUBLIC_SUPABASE_KEY をコードが読んでいますが、.env.example に名前がありません
結果: 7 件の要対応がありますつまり、確かめられたのは「このスクリプトが、仕込んだ欠けを取りこぼさず拾う」ところまでです。次のことは確かめていません。
- 実際の書き出しが
app.jsonを使うのか、app.config.tsを使うのか。後者なら識別子と画像の確認はスキップされ、補足が出るだけです @/のような別名 import は、行き先の判定対象に入れていません。別名を使うプロジェクトでは、import の確認が甘くなりますnpm installが通るか、ビルドが成功するか。これは実行しないと分かりません
最後の点は大事です。このスクリプトが「揃っています」と出しても、組み直せる保証にはなりません。 取りこぼしの多い種類のずれを先に拾う、粗い網だと思ってください。
走らせたあとの順番です
要対応が出たら、次の順に直すと手戻りが少なくなります。
- lock ファイルは、使うパッケージマネージャーを1つに決めて、残りを消す
- 識別子(bundleIdentifier / package)は、ストアに出すアプリではあとから変えにくいので、最初に決めた値を控えておく
- 画像と import 先は、Rork 側のプロジェクトに存在するかを見る。無ければ、同期が漏れている可能性があります
- 環境変数の名前は、
.env.exampleに名前だけを書き足す。値は、秘密を含むので書かない
3番で同期漏れが疑われるなら、プラン変更はいったん待ってください。手元の取り直しが不完全なまま契約を変えると、戻る場所を失うおそれがあるためです。
今日の一手
プラン変更を考えた日に、まず一度、GitHub から新しいフォルダへ取り直します。それだけで、連携が動いているかどうかが分かります。
そのうえで、スクリプトの出力を控えておきます。変更の前後で同じ確認をするためです。書き出したコードに鍵が混ざっていないかも合わせて見るなら、Rork が書いたコードに鍵が直書きされていないか、40行ほどのスクリプトで一度だけ確かめますが役に立ちます。取り直す前に除外設定を整えたい場合は、Rork のコードをエクスポートしたら、git init より先に .gitignore を用意しますをご覧ください。再エクスポートで上書きが起きないようにする手順は、Rork が書き換えた箇所だけを読む — 再エクスポートのたびに回している差分確認の手順にまとめています。