Closed14

バージョン違いの@sentry/typesが依存にいると@sentry/browserがランタイムにクラッシュする

kazuma1989kazuma1989

webpackでビルドしているWeb SPAプロジェクト。

package.json
    "@sentry/browser": "6.3.5",
    "@sentry/types": "5.6.1",

こんな感じの依存関係にしたら(Renovateがそうしてきた)、@sentry/browserのinit処理がクラッシュした。

Uncaught TypeError: Cannot read property 'Ok' of undefined
    at new Session (webpack-internal:///cj9L:17)
    at Hub.startSession (webpack-internal:///VKa5:345)
    at startSessionTracking (webpack-internal:///jrvE:201)
    at init (webpack-internal:///jrvE:104)
    at Object.init (webpack-internal:///mAsu:92)
    at eval (webpack-internal:///2YZa:113)
    at Module.2YZa (main.f710ea1176bb2f6626aa.js:313)
    at __webpack_require__ (runtime.f710ea1176bb2f6626aa.js:849)
    at fn (runtime.f710ea1176bb2f6626aa.js:151)
    at Object.0 (main.f710ea1176bb2f6626aa.js:146)
    at __webpack_require__ (runtime.f710ea1176bb2f6626aa.js:849)
    at checkDeferredModules (runtime.f710ea1176bb2f6626aa.js:46)
    at Array.webpackJsonpCallback [as push] (runtime.f710ea1176bb2f6626aa.js:33)
    at main.f710ea1176bb2f6626aa.js:1

TLDR. 対処としては次でOKだった。@sentry/types を直接使っているところはなかったので。

package.json
     "@sentry/browser": "6.3.5",
-    "@sentry/types": "5.6.1",
kazuma1989kazuma1989

ソースマップが有効だったのでブラウザーのdevtoolsで見てみた。

session.js?6b4c
import { SessionStatus } from '@sentry/types';
import { dropUndefinedKeys, uuid4 } from '@sentry/utils';
/**
 * @inheritdoc
 */
var Session = /** @class */ (function () {
    function Session(context) {
        this.errors = 0;
        this.sid = uuid4();
        this.timestamp = Date.now();
        this.started = Date.now();
        this.duration = 0;
        this.status = SessionStatus.Ok; // ❌
        this.init = true;
        if (context) {
            this.update(context);
        }
    }

なるほど SessionStatus がundefinedだと。

kazuma1989kazuma1989

@sentry/types@sentry/browser の依存パッケージ。なのでyarn.lockはこうなっていた。

yarn.lock
"@sentry/browser@6.3.5":
  version "6.3.5"
  resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.3.5.tgz#fc89538cf73752cd5b10060a914c6c5ece2d2893"
  integrity sha512-fjkhPR5gLCGVWhbWjEoN64hnmTvfTLRCgWmYTc9SiGchWFoFEmLqZyF2uJFyt27+qamLQ9fN58nnv4Ly2yyxqg==
  dependencies:
    "@sentry/core" "6.3.5"
    "@sentry/types" "6.3.5"
    "@sentry/utils" "6.3.5"
    tslib "^1.9.3"

"@sentry/types@5.6.1":
  version "5.6.1"
  resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.6.1.tgz#5915e1ee4b7a678da3ac260c356b1cb91139a299"
  integrity sha512-Kub8TETefHpdhvtnDj3kKfhCj0u/xn3Zi2zIC7PB11NJHvvPXENx97tciz4roJGp7cLRCJsFqCg4tHXniqDSnQ==

"@sentry/types@6.3.5":
  version "6.3.5"
  resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.3.5.tgz#d5eca7e76c250882ab78c01a8df894a9a9ca537d"
  integrity sha512-tY/3pkAmGYJ3F0BtwInsdt/uclNvF8aNG7XHsTPQNzk7BkNVWjCXx0sjxi6CILirl5nwNxYxVeTr2ZYAEZ/dSQ==

自分のpackage.jsonで指定した @sentry/types@5.6.1 と、@sentry/browser@6.3.5 の依存の @sentry/types@6.3.5 がそれぞれ存在している。

kazuma1989kazuma1989

それぞれの物理ファイルの居場所はこんな感じ。

% head node_modules/@sentry/browser/node_modules/@sentry/types/package.json 
{
  "name": "@sentry/types",
  "version": "6.3.5",
  "description": "Types for all Sentry JavaScript SDKs",
  "repository": "git://github.com/getsentry/sentry-javascript.git",
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/types",
  "author": "Sentry",
  "license": "BSD-3-Clause",
  "engines": {
    "node": ">=6"

% head node_modules/@sentry/types/package.json 
{
  "name": "@sentry/types",
  "version": "5.6.1",
  "description": "Types for all Sentry JavaScript SDKs",
  "repository": "git://github.com/getsentry/sentry-javascript.git",
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/types",
  "author": "Sentry",
  "license": "BSD-3-Clause",
  "engines": {
    "node": ">=6"
kazuma1989kazuma1989

パッケージのエントリーポイントであるindex.jsはそれぞれこんな感じ。

v5.6.1

node_modules/@sentry/types/dist/index.js
Object.defineProperty(exports, "__esModule", { value: true });
var loglevel_1 = require("./loglevel");
exports.LogLevel = loglevel_1.LogLevel;
var severity_1 = require("./severity");
exports.Severity = severity_1.Severity;
var status_1 = require("./status");
exports.Status = status_1.Status;
//# sourceMappingURL=index.js.map

v.6.3.5

Object.defineProperty(exports, "__esModule", { value: true });
var loglevel_1 = require("./loglevel");
exports.LogLevel = loglevel_1.LogLevel;
var session_1 = require("./session");
exports.SessionStatus = session_1.SessionStatus;
var severity_1 = require("./severity");
exports.Severity = severity_1.Severity;
var status_1 = require("./status");
exports.Status = status_1.Status;
var transaction_1 = require("./transaction");
exports.TransactionSamplingMethod = transaction_1.TransactionSamplingMethod;
//# sourceMappingURL=index.js.map
kazuma1989kazuma1989

違った。package.jsonにmainとmoduleそれぞれのフィールドがあったらmoduleを優先してくれるっぽい。のでこっちが使われてた(node_modules内のファイルを書き換えて確かめた)

node_modules/@sentry/types/esm/index.js
export { LogLevel } from './loglevel';
export { Severity } from './severity';
export { Status } from './status';
//# sourceMappingURL=index.js.map
node_modules/@sentry/browser/node_modules/@sentry/types/esm/index.js
export { LogLevel } from './loglevel';
export { SessionStatus } from './session';
export { Severity } from './severity';
export { Status } from './status';
export { TransactionSamplingMethod, } from './transaction';
//# sourceMappingURL=index.js.map
kazuma1989kazuma1989

@sentry/types v5.6.1 には SessionStatus なんていないことがわかった。@sentry/browser v6.3.5 のバンドルで誤ってv5.6.1がインポートされてしまい、今回のクラッシュになったのだろう。

kazuma1989kazuma1989

対処としては簡単だったからいいが、ちゃんと知っておきたい。
そのインポート(正確にはrequireか)の解決はwebpackがやっているはずだから、webpackくんがどう考えてv5.6.1のほうをチョイスしたか知る必要がある。

kazuma1989kazuma1989

package.jsonの記述はそのままに、node_modules/@sentry/types を丸ごと消したら、ビルド段階で失敗するようになった。優先順があるとかではなく、node_modulesにネストしたnode_modulesは見ていないっぽいな。

kazuma1989kazuma1989

package.jsonから "@sentry/types": "5.6.1", の記述を消した場合、@sentry/browser の依存にある @sentry/typesnode_modules/@sentry/browser/node_modules ではなくルートの node_modules に置かれるようになった。これはYarnによる処理。
webpackは何も変わっていないが、パッケージファイルの置き場が変わったことで @sentry/browser から @sentry/types への参照がうまくいくようになっただけか。

kazuma1989kazuma1989

ミニマルなプロジェクトを作ってみたところ、ネストしたnode_modulesとルートのnode_modulesをちゃんと区別してくれた。なんで・・・

kazuma1989kazuma1989

いやこれ完全に自分がアホなだけだった。webpackのresolve.modules設定に次があった・・・

webpack.config.js
      modules: [
        path.resolve(basePath, './src'),
        path.resolve(basePath, './node_modules'),
        path.resolve(basePath, '../../node_modules'),
      ],

src → ルート(各ワークスペース)のnode_modules → ルート(ワークスペースの親玉の位置)のnode_modules という順でしか解決しない。はい解散。

kazuma1989kazuma1989

引き継いだwebpack.configのことを何もわかってやってなかった。

このスクラップは2021/05/06にクローズされました