sentry-electron 0.5.5が`TypeError: module.require is not a function`で起動できない問題を調査しました(未解決)
@sentry/electron - npmのバグ調査をしました.
前に0.5.4が壊れているのをissueで報告しました.
I update to 0.5.4, error on MODULE_NOT_FOUND · Issue #81 · getsentry/sentry-electron
issueがcloseされたから問題は解決したと思ってv0.5.5にアップグレードしました.
他の問題が発生しました.
% y
yarn run v1.7.0
$ cross-env NODE_ENV=development electron .
App threw an error during load
TypeError: module.require is not a function
at new ElectronFrontend (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/dispatch.js:38:1)
at Object.initAndBind (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/core/dist/sdk.js:24:1)
at init (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/sdk.js:51:1)
at Object../src/sentry.js (/home/ncaq/Desktop/foo/app/webpack:/src/sentry.js:3:1)
at __webpack_require__ (/home/ncaq/Desktop/foo/app/webpack:/webpack/bootstrap:19:1)
at Object.<anonymous> (/home/ncaq/Desktop/foo/app/webpack:/src/main.js:18:1)
at Object../src/main.js (/home/ncaq/Desktop/foo/app/main.js:64808:30)
at __webpack_require__ (/home/ncaq/Desktop/foo/app/webpack:/webpack/bootstrap:19:1)
at /home/ncaq/Desktop/foo/app/webpack:/webpack/bootstrap:83:1
at Object.<anonymous> (/home/ncaq/Desktop/foo/app/main.js:87:10)
A JavaScript error occurred in the main process
module.require
は存在しないということ.
とりあえず/node_modules/@sentry/electron/dist/dispatch.js
に行って,
module.require
をrequire
に書き換えてみます.
起動はしました.
webpack環境だとmodule.require
は無効化されているのでしょう.
そもそも何故require
じゃなくてmodule.require
が使われているのかわからない.
両者の違いはなんだ…?
その場所のコメントを読みます.
We dynamically load the frontend implementation for the current process type. In frontend bundlers such as webpack or rollup, those requires are resolved statically. For this reason, we use
module.require
for the main implementation here, which is only defined in the main process. The renderer implementation must use the defaultrequire
.In case
process.type
is not defined, dispatch defaults to the renderer implementation, which should be fine for most cases. False positives of this would be running@sentry/electron
in a bare node process, which is acceptable.sentry-electron/dispatch.ts at 326c7a0625f3ae650d390ddd0d667b0da7ea3f99 · getsentry/sentry-electron
現在のプロセスの種類向けのフロントエンド実装を動的にロードします. webpackやrollupなどのフロントエンド·バンドラーではrequireたちは静的に解決されます. このため, main実装ではmainプロセスのみに定義されている
module.require
を使います. renderer実装ではデフォルトのrequire
を使用します.
process.type
が実装されていない場合, dispatchのデフォルトはrendere実装になります. これはだいたいの場合において大丈夫です. この偽陽性で生のnodeで@sentry/electron
が動くようになります.
動的ローディングしたいのは伝わってきました.
module.require
とは何だ?
module.require(id) Added in: v0.5.1
- id
<string>
- Returns:
<Object>
module.exports from the resolved moduleThe module.require method provides a way to load a module as if require() was called from the original module.
In order to do this, it is necessary to get a reference to the module object. Since require() returns the module.exports, and the module is typically only available within a specific module's code, it must be explicitly exported in order to be used.
module.require
メソッドは, 元のモジュールからrequire()
が呼び出されたかのように, モジュールをロードする方法を提供します。これを行うには, モジュールオブジェクトへの参照を取得する必要があります。
require()
はmodule.exports
を返すので, 通常は特定のモジュールのコード内でのみ使用可能です。これは明示的にエクスポートして使う必要があります。
???require
とmodule.require
の違いが全くわからない.
調べても出てこないので諦めました.
module.require
で生のrequire
を呼び出そうとしていることは伝わってきますが.
NodeのREPLではmodule.require
は存在します.
> module.require
[Function]
そしてwebpackでビルドするとmodule.require
は消滅します.
試しにmain部分にmodule.require('path');
を書いてみると,
同じくTypeError: module.require is not a function
になります.
webpackにmodule.require
を提供する意志があるのか検索しました.
module.require
i cannot provide it, because it is not possible to resolve via static dependency resolution. It will stay undefined. Align module-object to node's module-object · Issue #20 · webpack/webpack
私はそれを提供できません, なぜならこれは静的な依存関係の解決によっては解決できないからです。これは未定義のままです.
そりゃ動的ロードだから解決できないですね.
この変更が加わったのは fix: Dispatch correctly for bundlers like webpack by jan-auer · Pull Request #84 · getsentry/sentry-electron です.
前のissueである
I update to 0.5.4, error on MODULE_NOT_FOUND · Issue #81 · getsentry/sentry-electron
でもmodule.require
が動かないと警告していたのですがスルーされてしまいました.
とりあえずここを元に戻してしまおうとmodule.require
をrequire
に戻しましたが,
すると元のエラーが発生するんですね.
% y
yarn run v1.7.0
$ cross-env NODE_ENV=development electron .
Installing Devtron from /home/ncaq/Desktop/foo/app
info: Added Extension: React Developer Tools
info: Added Extension: Redux DevTools
{ Error: Cannot find module '/home/ncaq/Desktop/foo/package.json'
at webpackEmptyContext (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/main sync:2:1)
at getPackageJson (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/main/context.js:80:1)
at /home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/main/context.js:240:25
at Generator.next (<anonymous>)
at fulfilled (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/main/context.js:4:42)
at <anonymous> code: 'MODULE_NOT_FOUND' }
{ Error: Cannot find module '/home/ncaq/Desktop/foo/package.json'
at webpackEmptyContext (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/main sync:2:1)
at getPackageJson (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/main/context.js:80:1)
at /home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/main/context.js:240:25
at Generator.next (<anonymous>)
at fulfilled (/home/ncaq/Desktop/foo/app/webpack:/node_modules/@sentry/electron/dist/main/context.js:4:42)
at <anonymous> code: 'MODULE_NOT_FOUND' }
Done in 7.34s.
なるほど動的ロードする意味はあったというわけですね.
しかしmodule.require
を使ってしまうとエラーになるのは変わらないので,
何か別のもので置き換えることを試みました.
動的ロードと言えばdynamic importだろうということで書き換えようとしたのですが,
init
もElectronFrontend.constructor
もasync
関数ではなく,
dynamic importはPromise
を返してくるからロードを待つ方法がわからないです.
await
とかじゃなくて素直にロードをwait
する方法は無いのかな?
ロードを待てないとElectronFrontend#inner
がnullableになってしまい,
他のメソッドが正常に動かなくなる危険性も生まれます.
そもそもinit
が完了するまで実行を待たないとおかしなことになります.
というかなんでJavaScriptのPromise
は素直にコンテキストを選ばずに終了を待てないんでしょう.
他の言語のThread系の機能は普通にそれ出来ますよね.
単純に待つAPIを実装できない理由はあるんでしょうか.
起動を並列化したい理由も無いですし,
単にPromise
の終了をwait出来れば全て解決するのですが.
本当に待てないのでしょうか?
私が知らないだけ?
EcmaScriptの提案にはトップレベルにimport
が書けるものがあるようですが.
tc39/proposal-top-level-await: top-level await
proposal for ECMAScript (stage 2)
これのつらさは実行環境を見て,
mainとrendererを大規模に分岐させようとしているから発生していると思うんですよね.
素直にmainInit
とrendererInit
関数を用意すれば静的に依存パスが定まって楽になるのでは.
いくつか設計を修正する案は思いつきましたが時間切れなのでissue建てて報告だけしておきましょう.