🌴

LIFF CLIでngrokの代わりにVSCodeのPort Forwardingを使う

に公開

はじめに

結論だけ知りたい方は「好きなプロキシURLを指定するためのserveコマンド」まで飛んでください。

LIFF CLIではローカルサーバーのプロキシが簡単に設定できる

みなさん、LIFF CLIは使っていますか?

私はLIFF CLIが出る前からlocal-ssl-proxyを使って開発しており、ローカル開発に関しては特に不便もしていなかったので、しばらくLIFF CLIには注目していませんでした。

が、先日よくよく調べるとexperimentalでngrokとの自動連携の機能が追加されていることを知り、メチャクチャ便利なので常用するようになりました。

というのも、普段のlocal-ssl-proxyはURL固定なので問題ないのですが、いざ開発中のサーバーの内容を実機で確認しようと思うと、いちいちLINE Developer Consoleを開いてチャネル設定でエンドポイントURLにngrokのURLを設定する必要があり面倒です。

まあ、2年ほど前からngrokは無料版でも固定のドメインが使えるようになったので、ngrok用にLIFFを追加で作成しておけばエンドポイントURLは書き換えずに済みますが、それでも起動時にLIFF IDは指定しなおす必要があります。

それがLIFF CLIを使うと、開発者ごとにLIFFを作成してさえおけば、LIFF IDを変更することなく起動コマンドのみでローカルプロキシとngrokを切り替えることができるのでハイパー便利というわけです。

ngrok無料枠を使い果たしたらどうすればよいか

それはもうサービスに感謝してngrokに課金してください[1]

と言いたいところですが、回避策もほしいですよね。

たとえば、VSCodeのPort Forwarding機能は無料で使えるので、これをngrokの代わりに使えれば便利です。
しかも、同じポートに対するURLは固定的に振られるので取り回しもしやすいです。

ちなみに、Port Forwarding機能の中身はAzureのdev tunnelsで、その利用上限は下記のページに記載されています。

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/management/azure-subscription-service-limits#dev-tunnels-limits

LIFF CLIはserveコマンドで何をしているか

実際、LIFF CLIがserveコマンドで何をしているかといえば、「対象のLIFFのエンドポイントURLにngrokのURLを動的に指定している」だけでしょうから、そのURLを抽出する部分を騙せれば別にngrokでなくても動くはずです。

ドキュメントに、オプションの--proxy-typengrok-v1を指定する場合はnode-ptyが必要だと書いてあるので、コマンドの標準出力結果をパースしているんだろうなと推測できます。

実際のコードを読んでみる

ということで、liff-cliのserveコマンドで何が行われているかコードを読んでみましょう。

結論からいうと、このextractUrl関数ですね。

https://github.com/line/liff-cli/blob/4256081d36f6e1e8fb974f2b27b08ed2c0d83267/src/serve/proxy/ngrok-v1-proxy.ts#L9-L13

node-ptyから受け取った結果をextractUrlを通して抽出していることがわかります。

https://github.com/line/liff-cli/blob/4256081d36f6e1e8fb974f2b27b08ed2c0d83267/src/serve/proxy/ngrok-v1-proxy.ts#L50-L61

ということで、extractUrlの正規表現にしたがって、末尾に ->をつけてURLを出力するコマンドを指定すれば、LIFF CLIはそのURLをプロキシとして使うようになります。

https://exapmle.com ->

好きなプロキシURLを指定するためのserveコマンド

以下のように、--ngrok-commandオプションに好きなURLをechoでもしておけばOKです。
Port Forwarding機能のURLはほぼ固定なので環境変数に入れておけば使い回せると思います。

liff-cli serve \
  --liff-id $NEXT_PUBLIC_LIFF_ID \
  --url http://localhost:3000/ \
  --proxy-type ngrok-v1 \
  --ngrok-command "echo \"$PROXY_URL ->\""

VSCodeの「ポート」タブでポートの転送を開始するのは手動でやる必要がありますが、エディタ上で簡単にできるので、まあそこは頑張ってください。

それすらも面倒な人向け

その手動作業すらも面倒な人はVSCode機能ではなく、本家のdev tunnelsを使います。
この工程にはMicrosoftアカウントが必要です。

まず、devtunnelをインストールします。

brew install --cask devtunnel

次に、Microsoftアカウントでログインします。

devtunnel user login

devtunnel host -p 3000でPort Forwardingと同様にホストできます。詳しくは公式ドキュメントを参考にしてください。

コマンド出力結果をパースしてURL ->の形式に直します。

liff-cli serve \
  --liff-id $NEXT_PUBLIC_LIFF_ID \
  --url http://localhost:3000/ \
  --proxy-type ngrok-v1 \
  --ngrok-command "sh -c 'devtunnel host -p 3000 | awk \"/https:\/\/[^ ]*-3000\\.asse\\.devtunnels\\.ms/ { print \\\$0 \\\" ->\\\" }\"'"

エスケープだらけで複雑なコマンドですが、やっていることは単純で以下のとおりです。

  1. 正規表現https://[^ ]*-3000\.asse\.devtunnels\.msでURLを抽出
  2. awkで末尾に ->を付与
  3. 全体をsh -cで囲うことでCLI内でコマンド引数に付与されるポート番号がawkの引数化されることを防ぐ

とはいえ、コマンドが複雑なことに変わりはないので別でスクリプトファイルとして書き出して利用してしまうほうが健全かもしれません。

start-devtunnel.sh
#!/bin/bash
devtunnel host -p 3000 | awk '/https:\/\/[^ ]*-3000\.asse\.devtunnels\.ms/ { print $0 " ->" }'

実行コマンドはかなりスッキリします。

liff-cli serve \
  --liff-id $NEXT_PUBLIC_LIFF_ID \
  --url http://localhost:3000/ \
  --proxy-type ngrok-v1 \
  --ngrok-command "$(pwd)/start-devtunnel.sh"

ドキュメントには書かれていない選択肢

ついでに上記で調べたngrok-v1-proxy.tsの隣にngrok-proxy.tsというファイルを見つけて気付いたのですが、ngrok-v1じゃなくてngrokというオプション指定も存在するようですね。

https://github.com/line/liff-cli/blob/4256081d36f6e1e8fb974f2b27b08ed2c0d83267/src/serve/resolveProxy.ts#L48-L53

node-ptyを経由せずにngrokのライブラリを直接利用してつなぐオプションのようです。

https://github.com/line/liff-cli/blob/4256081d36f6e1e8fb974f2b27b08ed2c0d83267/src/serve/proxy/ngrok-proxy.ts

NGROK_AUTHTOKENという環境変数に認証トークンを入れておけば使えそうな雰囲気があったので試してみましたが、どうにも使えませんでした。

NGROK_AUTHTOKEN="" liff-cli serve \
  --liff-id $NEXT_PUBLIC_LIFF_ID \
  --url http://localhost:3000/ \
  --proxy-type ngrok

おかしいなと思ってPRを探っていたら、https://github.com/line/liff-cli/pull/18 にて修正されているようでした。
これは先週にマージされたばかりなので、npmはApr 22にリリースされたバージョンのままで、まだ反映されていないようですね(2025/6/6現在)。

試しにPRの修正内容にしたがって手元のnode_modules/@line/liff-cli/dist/serve/proxy/ngrok-proxy.jsを直接書き換えてawaitを削除したら動くようになりました、めでたしめでたし。

おわりに

せっかく記事を書いたと思ったら最後にngrok-v1のオプションがdeprecatedになりそうなことを知ったのでちょっとショックです。

悔しいので一生v0.4.0を使うことにします。みなさんは未来に生きてください。私は過去にすがって生きていきます。

脚注
  1. ちなみに私はサービスへの感謝は支払いで示すべきという信条がわずかばかりあるので課金しています。 ↩︎

キリフダ株式会社

Discussion