top of page

Velo では import * as ns が静かに空になる

会員向けの注文キャンセル画面で、取り消しボタンを押しても何も起きなかった。正確には、汎用のエラーメッセージが出て終わっていた。どの段階で落ちたのかは分からない。

この処理は「例外を投げない。段階ごとの結果を返す」という方針で書いてあった。書いてあった、というのが正しい。実際には返金の実行など、いくつかの段階が本体を囲む関数の外に置かれていて、そこで投げた例外は方針の外側を素通りしていた。全体を1つの関数へ切り出して囲み、進んだ段階を記録するようにしたところ、ようやく画面に文字が出た。

ecom.idOf is not a function

ecom は存在するのに、中身が無い

該当箇所はこうなっていた。

import * as ecom from 'backend/ecomApi.js';   // ecom.idOf is not a function

プレーンなバックエンドモジュールを名前空間として取り込んでいる。JavaScript としては普通の書き方で、エディタも何も言わない。ビルドも通る。それでも ecom.idOf は関数ではなかった。

名前付きインポートへ変えたら、そのまま動いた。

import { idOf, cancelLineItems } from 'backend/ecomApi.js';

Velo のバンドラは名前空間インポートを解決しない、と読むのが症状に合う。解決に失敗しても例外にはならず、期待した関数を持たないオブジェクトが手元に残る。だから症状は import の行ではなく、最初にその名前を使った行で出る。

1つの症状に2つの修正が要った

この障害で厄介だったのは、原因そのものより、原因が見えるまでの距離だった。

  • 名前空間インポートが解決されないので、ecom.idOf が undefined になる

  • それを呼ぶと TypeError が出るが、その位置は例外を返り値へ変換する範囲の外だった

  • Velo はバックエンドの例外文面をフロントエンドへ渡さないので、画面には汎用のメッセージだけが届く

3つのうち1つでも違えば、最初の1回で原因の名前が読めていた。逆に言えば、「例外を投げない」という方針は、投げうる箇所を全部その内側に入れて初めて成立する。方針をコメントに書いた時点では成立していなかった。

他のファイルも同時に疑う

このとき、同じ画面で別の問題も見つかっている。サイト上のそのバックエンドモジュールの中身が、まったく別のファイルの内容になっていた。719行あり、本来そこにあるはずのない関数を export していた。正しい内容は200行である。貼り付け先を取り違えたまま気付かずにいた期間があったことになる。

行数を突き合わせなければ、これは分からない。名前空間インポートの件と重なっていたので、しばらくは「どちらの影響で落ちているのか」も分からなかった。手で貼り付けて反映する運用では、ローカルのコードが正しいことと、サイト上のコードが正しいことは別々に確かめるしかない。

機械的に見つける

この書き方は、一度でも踏むと分かるが、踏むまでは分からない。ビルドが通り、エディタも黙っているからである。だから規約として名前付きインポートに寄せたうえで、混入していないことを検索で確かめるようにした。

grep -rn "import \* as" backend pages public dashboard

Wix が提供するモジュール(wix-data など)を名前空間で取り込む書き方は普通に動くので、対象はプロジェクト内のファイルを指す import だけである。件数は多くないので、この程度の粗い検索で足りる。

Velo

実装

備忘録

コラム

その他

カテゴリー

bottom of page