Angularを久しぶり(もう半年以上ぶり?)に開いてビルド&デプロイを行うと、エラーが発生するようになった。
Error: Error occurred while parsing your function triggers.
TypeError: async_hooks_1.AsyncLocalStorage is not a constructor
色々調べてみるとnodeのバージョンが古いせいで、無理やりアップデートさせられたモジュールとかち合っているらしい (現行v12.10.0)。
それならアップグレードすればいいだろ?という話なのだが、色々スムーズには行かなかったので共有しておく。
環境は Macbook Air の M1 チップ、Angular は 11.2.18。
1. node のアップグレードバージョンを決める
まずあらためて Angular のバージョンを確認しておこう。
ng –version
次にその Angular でサポートされている node のバージョンを把握しておく。
https://github.com/angular/angular
で Angular のプロジェクト開いたら、ブランチから自分の Angular バージョンの系列を選ぼう。

選んだら、そこにリストされている package.json の中身を確認しよう。
下でサポートされる node のバージョンを確認できる。
"engines": {
"node": ">=10.19.0 <16.0.0", ... (snip) ...
},
2. node をアップグレードする
nodebrew というツールを使うと複数の node をインストールしてバージョンの切り替えを行うことが出来る。
インストールの仕方はたぶんぐぐれば出てくるのでここには記載しない。
nodebrew ls-remote というコマンドで、どんなバージョンをインストールするか一覧から探すことが出来る。
インテルチップ使っている人ならばここは問題なく進められるはず。M1チップを使っている人は下の青字の部分も確認してね。
ここで Mac M1 チップユーザーに落とし穴です。M1 チップがサポートする Node.js は 16.0 からだと書かれているね。でももっと古いバージョン入れたいこともあるよね?
nodebrew install-binary <version> でそのバージョンを選ぶと、コマンドが「見つからないよ」とエラーを返してくると思います。で、ちょっと調べると出てくるよね、「nodebrew compile v14.21.2」のようにビルドすれば使えるようになるよ、と。懐かしいなぁ、そういう make コマンドでカーネルビルドみたいなの。
でもちょっと待って。それ、本当に node 本体を M1 チップで動作するようにしたら大丈夫?依存モジュールのデータ型とか処理とか、将来のトラブル呼び込んじゃってない?
俺は結局試行錯誤の上、arch -x86_64 zsh
のように Angular のビルドや firebase のデプロイを行うシェルを Rosetta 使って x86 のエミュレーションと一緒に使ってゆく、というやり方に落ち着きました。
シェルから上のコマンドを叩いて、起動されるプロセス上で nodebrew install-binary <version> を実行すると、今度は何のトラブルもなくインストールされるよ。本当にエミュレーションが走っているのかどうかは、「uname -m」というコマンドを実行することで CPU アーキテクチャを確認することが出来る。
nodebrew でインストールできたら、nodebrew list でリストした利用可能バージョンの中から nodebrew use <version> の様に指定すればいい。指定したものに切り替わっているかどうかを確認するために、あらためて「node -v」を実行してみよう。
お望みのバージョンが表示された人、次に進んで下さい。私はここでも落とし穴にはまり、use で指定したバージョンと node -v で表示されるバージョンが一致しない。
のっけから結論ですが、下の環境変数を設定して nodebrew に PATH を通しておきましょうね。
export PATH=$HOME/.nodebrew/current/bin:$PATH
ここまでやってようやく、nodebrewのcurrentで指定されているnodeのバージョンを見に行くようになる。
3. Angular のコードをアップデート
node のバージョンを 12 -> 14 にアップグレードした際には以下のことを行った。
- アプリ及び functions のディレクトリの node_modules を削除
- dist/… など ng build の出力先の削除
- firebase.json: “functions” の子要素の “runtime” の値を “nodejs14” に設定。
- *.js: require(“firebase-functions/lib/logger/compat”) の参照を require(“firebase-functions/logger/compat”) に変更
- functions/package.json: “engines” の子要素の “node” の値を “14” に設定。
- npm install を functions と アプリそれぞれのルートから実行
- ng build を実行
トラブルシューティング
何が起こってるかわからない、という場合には基本に戻ろう。
- デプロイする時: firebase deploy … –debug とオプションを付けると verbose 表示でどこでどんなエラーが発生しているのかを確認できる。
- 実行する時: ブラウザコンソールの “Console” はもちろん、”Network” でリクエストのレスポンスなども確認しよう。クライアント側に表示されていないエラーを拾うために、Firebase コンソールの Functions ログの確認も行おう。
- とにかくエラーは見過ごさないこと。めんどくさくても一つ一つ調べる。