projenでyarn installが404、ts-nodeも入らずyarn projenできなかった

  • projen
  • Yarn
  • TypeScript

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

projen で管理しているリポジトリで、yarn install も yarn projen も通らない状態になった。どっちかを直そうとするともう片方が必要、という鶏と卵の状態だったので、どう抜けたかを書いておく。

何が起きたか

まず yarn install が 404 で失敗した。

error Error: https://registry.yarnpkg.com/@example/old-package/-/old-package-2.1.22.tgz: Request failed "404 Not Found"

node_modules が作れないので、続けて yarn projen も失敗する。

dax: ts-node: command not found
Synthesis failed: Task "default" failed when executing "ts-node --project tsconfig.dev.json .projenrc.ts"

原因

依存していた @example/old-package がレジストリから消えていた。

.projenrc.ts の deps ではすでに代わりの @example/new-package に差し替えてあった。ただ、projen は .projenrc.ts を実行(合成)して初めて package.json や yarn.lock を書き換える。合成する前の生成済みファイルは古いパッケージを参照したままなので、yarn install はそれを取りに行って 404 で止まる。

ここで詰むのが、合成そのものに ts-node が要ること。yarn projen は ts-node で .projenrc.ts を実行するので、yarn install が通らない限り ts-node が入らず、合成もできない。

flowchart TD
    A[".projenrc.ts は差し替え済み"] --> B["生成済み package.json / yarn.lock は古いまま"]
    B --> C["yarn install が消えたパッケージを取りに行く"]
    C --> D["404 Not Found"]
    D --> E["node_modules が作れない"]
    E --> F["ts-node が入らない"]
    F --> G["yarn projen(.projenrc.ts の実行)が失敗"]
    G -->|"package.json が作り直されない"| B

解決方法

正はあくまで .projenrc.ts。生成済みの package.json は、install を通すためだけに一時的に触る。

  1. .projenrc.ts の deps から消えたパッケージを外し、代わりのパッケージを書く(今回はここまで済んでいた)。
  2. 生成済みの package.json から、消えたパッケージの行だけ消す。yarn.lock はそのままでよい。
  3. yarn install する。これで ts-node と projen が入る。
  4. yarn projen する。.projenrc.ts をもとに package.json、.projen/deps.json、.projen/tasks.json、yarn.lock が作り直され、新しいパッケージも入る。

2 の package.json の差分はこれだけ。

"dependencies": {
"@example/old-package": "^2.1.22",
...
}

yarn.lock に古いエントリが残っていても、package.json から参照されていなければ取りに行かないので install は通った。古いエントリは 4 の再生成で消える。

flowchart LR
    A["package.json から<br/>消えたパッケージの行を削除"] --> B["yarn install<br/>(ts-node / projen が入る)"]
    B --> C["yarn projen<br/>(.projenrc.ts から合成)"]
    C --> D["package.json / deps.json /<br/>tasks.json / yarn.lock を再生成"]

npm の場合の読み替え

今回は Yarn だったけど、projen の packageManager を npm にしているプロジェクトでも、詰み方と抜け方は同じはず。npm 側は実機未確認なので、読み替えとして書いておく。

Yarn npm
yarn.lock package-lock.json
yarn install npm install
yarn projen npx projen(または npm run projen)
registry.yarnpkg.com からの 404 registry.npmjs.org からの 404

手順は次のようになる。

  1. .projenrc.ts の deps から消えたパッケージを外し、代わりのパッケージを書く。
  2. 生成済みの package.json から、消えたパッケージの行だけ消す。package-lock.json はそのままでよい。
  3. npm install する。ts-node と projen が入る。
  4. npx projen する。package.json、.projen/deps.json、.projen/tasks.json、package-lock.json が作り直される。

注意点として、3 は npm ci ではなく npm install を使う。npm ci は package.json と package-lock.json が一致していないとエラーで止まる仕様なので、2 で package.json だけ直した状態だと通らない。npm install なら package.json に合わせて lock 側を更新してくれる。lock に残った古いエントリが install 時にどう扱われるか(そのまま取りに行かずに済むか)は未確認。もし lock 側の古いエントリが原因で止まるなら、package-lock.json から該当パッケージのエントリを消すか、lock ごと消して npm install し直すことになると思う。

手編集の扱い

projen 管理下のファイルを手で直すのは本来やらないことだけど、今回の編集は合成が通るまでの足場でしかない。yarn projen が通った時点で package.json は .projenrc.ts から上書きされるので、最終的に残る依存の指定は .projenrc.ts 側だけになる。

逆に言うと、2 で消したついでに別の依存をいじったりすると、それは合成で上書きされて消える。直すのは install を止めている行だけにしておくのが安全。