サンダーボルト

相手モンスターを全て破壊する。

deep-equalを使うとエラー:Uncaught ReferenceError: global is not defined

概要

Angularで開発しているときに、オブジェクトの中身まで比較して等価かどうかを判定したくなり、調べると以下が出てきた。

typescript-jp.gitbook.io

これによれば、

このようなチェックを行うには、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 はこちら

github.com

var origSymbol = global.Symbol;

たしかに、globalを使おうとしてる。ログからもわかるんですが、deep-equalが依存しているようです。(npm ls has-symbols した結果👇)

f:id:nao_666:20200403120544p:plain
npm ls has-symbols

解決策

ググると、「とりあえず polyfills.tsに(window as any).global = window;って書けばOK😅」みたいなのが出てくるんですが、もう少しだけ、JS初心者向けに説明します。

まず、Uncaught ReferenceError: global is not defined と出てくるのはブラウザ上のJSエンジンにてglobalが無いということです。Chromeのconsoleでglobalと打てば同じエラーを再現できます。

f:id:nao_666:20200403120913p:plain
`global` をConsoleで実行した結果

で、どうしてこういうことが起きるかというと、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で試すとこういうこと👇です。

f:id:nao_666:20200403122339p:plain

エラーが出なくなりました。