概要
Angularで開発しているときに、オブジェクトの中身まで比較して等価かどうかを判定したくなり、調べると以下が出てきた。
これによれば、
このようなチェックを行うには、deep-equal npmパッケージを使用します。
とのことだったので、npm i deep-equal
して利用してみたところ見事に Uncaught ReferenceError: global is not defined
エラーが出たのでその調査と解決の記事。
環境
ライブラリ | バージョン |
---|---|
@angular/core | 9.0.6 |
deep-equal | 2.0.1 |
エラー詳細
ログは以下の通り
index.js:3 Uncaught ReferenceError: global is not defined at Object../node_modules/has-symbols/index.js (index.js:3) at __webpack_require__ (bootstrap:79) at Object../node_modules/es-abstract/GetIntrinsic.js (GetIntrinsic.js:39) at __webpack_require__ (bootstrap:79) at Object../node_modules/es-abstract/helpers/callBind.js (callBind.js:5) at __webpack_require__ (bootstrap:79) at Object../node_modules/regexp.prototype.flags/index.js (index.js:4) at __webpack_require__ (bootstrap:79) at Object../node_modules/deep-equal/index.js (index.js:5) at __webpack_require__ (bootstrap:79)
エラーを吐いている has-symbols/index.js はこちら
var origSymbol = global.Symbol;
たしかに、global
を使おうとしてる。ログからもわかるんですが、deep-equalが依存しているようです。(npm ls has-symbols
した結果👇)
解決策
ググると、「とりあえず polyfills.tsに(window as any).global = window;
って書けばOK😅」みたいなのが出てくるんですが、もう少しだけ、JS初心者向けに説明します。
まず、Uncaught ReferenceError: global is not defined
と出てくるのはブラウザ上のJSエンジンにてglobalが無いということです。Chromeのconsoleでglobalと打てば同じエラーを再現できます。
で、どうしてこういうことが起きるかというと、has-symbols
というライブラリがNode.js環境にはあるglobal
という変数が存在する前提で作られているが、ブラウザのJSエンジンにはglobal
という変数が無いからなんですね。
で、そのglobal
というものの実態はブラウザのグローバルオブジェクトである、window
と同じで良いらしい(ここきちんと調べてない😅)ので、それをglobalとして使えるように、window直下に配置してあげる必要がある、ということですね。
で、polyfills.tsはTypeScriptなので、
window.global = window;
ではglobalなんてフィールド無いぞ!ってエラーが出ますから、一旦anyにキャストしてあげて
(window as any).global = window;
ってのをpolyfills.tsに書けば良いという話ですね。
雑にConsoleで試すとこういうこと👇です。
エラーが出なくなりました。