2024年6月17日月曜日

shadow-cljsでnodeのライブラリ呼び出し時にundefinedエラーが出る場合はdefaultの読み込み必要な場合がある


要点

ライブラリ名に$defaultを付けてrequireすると解決する場合があります。
(ns your.some.file
(:require ["react-native-ble-manager$default" :as rn-ble-manager]))

背景

react-native + expo + shadow-cljs環境で作っているandroidアプリでreact-native-ble-managerのstart関数を呼んだところ下記のエラーが発生しました。
(ns your.some.file
(:require ["react-native-ble-manager" :as rn-ble-manager]))

(.start rn-ble-manager)
Possible Unhandled Promise Rejection (id: 0):
TypeError: undefined is not a function

上記エラーの調査試行内容と解決方法を共有します。

requireはできているが、何かおかしい

requireしたreact-natibe-ble-managerをjsのconsole.logで表示したところ、start関数は下記の位置にありました。
(ns your.some.file
(:require ["react-native-ble-manager" :as rn-ble-manager]))

(.log js/console rn-ble-manager)
// start以外の要素は省略しています
Object {
"default": BleManager {
"_nativeModule": Object {
"start": [Function nonPromiseMethodWrapper]
}    
}
}
object内のdefaultキーの中にstartがあるので、start関数が見つけられずにundefinedになっていました。
この問題はcljs環境だけでなく、nodejsの環境でも書き方によって発生する問題でした。

unhandled promise rejection #192

defaultを読み込めば解決

ライブラリのdefaultを読み込む設定を調べたところ、shadow-cljsの説明書で解決方法を見つけました。

13.1.1. Using npm packages

ライブラリの末尾に$defaultを付けることでdefaultをimportできます。
(ns your.some.file
(:require ["react-native-ble-manager$default" :as rn-ble-manager]))

これにより、start関数が期待する位置で読み込まれ、start関数がundefinedにならず呼び出し可能になりました。
(なお、関数が期待通りに動くかはandroidの権限付与など別の問題が関係します。)
(ns your.some.file
(:require ["react-native-ble-manager$default" :as rn-ble-manager]))

(.log js/console rn-ble-manager)
(.start rn-ble-manager) ; undefinedエラーを回避
// start以外の要素は省略しています
BleManager {
"_nativeModule": Object {
"start": [Function nonPromiseMethodWrapper]
}    
}

おわり

関数呼び出しでundefinedエラーが発生して戸惑いましたが、shadow-cljsの記述方法を把握してライブラリのdefault部分を呼び出したことで、期待通りに実行できました。

参考

13.1.1. Using npm packages
unhandled promise rejection #192

0 件のコメント :