Storybookを入れたときに発生した謎のModule parse failed: Unexpected tokenエラー
npx storybook@latest init
を実行したところ、次のようなエラーが出ました。
全文は長いので一部だけ抜粋
ERROR in ./node_modules/.pnpm/@storybook+components@7.5.1_@types+react-dom@18.2.14_@types+react@18.2.33_react-dom@18.2.0_react@18.2.0/node_modules/@storybook/components/dist/chunk-MUPK3MH6.mjs 3:2128 Module parse failed: Unexpected token (3:2128) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders | import { __commonJS } from './chunk-JRLSWQMA.mjs'; | > var require_markdown=__commonJS({"../../node_modules/refractor/lang/markdown.js"
ぱっと見で何が起きてるか全くわかりませんね。
node_modulesを消したりはしてみたんですが効果はなし。
似たようなプロジェクトを作り直してやってみたんですが、全く再現しませんでした。
ダメ元で `pnpm-lock.yaml` と `node_modules` を削除してlockファイルを作り直したら直りました。
一応何が原因だったかを探りたいので、作り直して再生成された `pnpm-lock.yaml` と作り直す前のものを比較してみます。
大きく分けて3つの違いがありました。
/@storybook/react@7.5.1(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)
の依存であるacornのバージョンが異なる
- /acorn-import-assertions@1.9.0(acorn@8.11.1): + /acorn-import-assertions@1.9.0(acorn@8.11.2): resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} peerDependencies: acorn: ^8 dependencies: - acorn: 8.11.1 + acorn: 8.11.2 dev: true /acorn-jsx@5.3.2(acorn@7.4.1): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: acorn: 7.4.1 dev: true - /acorn-jsx@5.3.2(acorn@8.11.1): + /acorn-jsx@5.3.2(acorn@8.11.2): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.11.1 + acorn: 8.11.2 dev: true /acorn-walk@7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} engines: {node: '>=0.4.0'} dev: true /acorn@7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} hasBin: true dev: true - /acorn@8.11.1: + /acorn@8.11.2: - resolution: {integrity: sha512-IJTNCJMRHfRfb8un89z1QtS0x890C2QUrUxFMK8zy+RizcId6mfnqOf68Bu9YkDgpLYuvCm6aYbwDatXVZPjMQ==} + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} engines: {node: '>=0.4.0'} hasBin: true dev: true
/next@13.5.6(@babel/core@7.23.2)(react-dom@18.2.0)(react@18.2.0)
の依存であるcaniuse-liteのバージョンが異なる
- /caniuse-lite@1.0.30001554: - resolution: {integrity: sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==} + /caniuse-lite@1.0.30001555: + resolution: {integrity: sha512-NzbUFKUnJ3DTcq6YyZB6+qqhfD112uR3uoEnkmfzm2wVzUNsFkU7AwBjKQ654Sp5cau0JxhFyRSn/tQZ+XfygA==}
next-authのバージョンが異なる
- /next-auth@4.24.3(next@13.5.6)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-n1EvmY7MwQMSOkCh6jhI6uBneB6VVtkYELVMEwVaCLD1mBD3IAAucwk+90kgxramW09nSp5drvynwfNCi1JjaQ==} + /next-auth@4.24.4(next@13.5.6)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-5DGffi+OpkbU62vPQIJ1z+hFnmow+ec5Qrn9m6eoglIO51m0DlrmLxBduZEwKAYDEg9k2joi1yelgmq1vqK3aQ==} peerDependencies: - next: ^12.2.5 || ^13 + next: ^12.2.5 || ^13 || ^14 nodemailer: ^6.6.5 react: ^17.0.2 || ^18 react-dom: ^17.0.2 || ^18
最も怪しいのはacronですね。ということでacronの直近のコミット履歴からissueをたどるとこんなものを発見しました。
github.com
github.com
まさに今回発生した現象という感じですね。
というわけでインストールタイミングが悪くて、たまたま依存モジュールの不具合を踏んでしまったというのが事の顛末でした。
工数を理由に管理画面のテストを雑にするのはよくない
という話を同僚としていた。いい話だからブログに書いてと言われたので、無茶苦茶久しぶりに記事を書いた。
通常のユーザーが利用できる面はどういった操作が行われるかわからない以上、テストはしっかり書くべきという意識が強いと思う。実際それは間違っていないし、考えうる限りのケースをテストするべきだと思う。
一方で管理画面は利用できるユーザーが限られているし、悪意のある操作が行われる可能性も限りなく低い。故にリソースが足りていないと「管理画面はまあそこそこのテストでいいでしょ」とか「管理画面は壊れてたら直せばいいから、単純なとこはテストいらないでしょ」みたいな考えに陥りがちだけど、実際は強い権限による操作が行われるのだから相応のテストを書いて然るべきだよね、ということを話していた。
管理画面は通常ユーザーが見れる面と違って権限チェックなども必要だし、これによってテスト書くのめんどくさくなりがちだよねという話題もある。でもテスト手法が確立されていればそれを模倣するだけでいいし、その手法が存在していないってことは実装当初の時点でちゃんとテスト書いてないのでは?という話もできる。まあ後付でどんどんチェック項目増えて肥大化して〜みたいなパターンも考えられるけど、それで追従できないならそれはそれで設計ミスってそうな気はする。
ユーザーからしたら自分の操作起因ではないステータスの変更が行われるわけで、テスト不十分による不具合で誤BANなんてされた日には不快度MAX!!みたいな感じになるので、「この操作が正常に動かなかったときに、対象ユーザーとしてどう思うか」という「操作される側」の意識は常に持っておきたい。
とはいえこれは本当に工数のことを考えていない話で、火の車だった場合には「そんなことしてられっかよ!」という気持ちになるのもまあ分かる。サービスは無料で動かせないからね。でもそれでサービスの信用度下げて「でもあそこ誤BAN多いからな」みたいな風評がついてしまうと新規ユーザー獲得率にも影響するし、自分自身一度信用する気が失せたサービスは可能な限り使いたくないと思っているので、少なくとも自分は自分自身が不具合踏んで(踏まれて)不快になりそうなポイントはちゃんとテストするようにしような、というマインドで開発している。
というかまあこういう脅迫をしてちゃんと工数を確保するのもテックリードの仕事なんだろうな(幸いうちのプロダクトオーナーはその辺の理解度高いので脅迫しなくても大抵やらせてもらえる環境でとてもありがたいのだけど)
ルーターを変えた
実はIPoE接続にしてからずっと違和感があって、ページを訪れた際に画像が表示されなかったり、よくわからない通信切断が行われていた。
タスクマネージャーとかでモニターを眺めてると明らかに通信そのものが行われていないので一発でわかる。
あとTweetDeckを使っているとTL更新で画像だけ取ってこれないみたいなのがしょっちゅう起こるのでわかりやすい。
今まで堪えていたけど、最近マスターデュエルでコイントス時の接続が不安定になって困ること(本当にフィールドに移るタイミングだけで、それ以外は問題ない)がちょいちょいあって、流石に許容できないので色々環境変えて問題の切り分けを行っていった。
結局何が原因だったかというと、タイトルにある通りルーターが原因だった。
sshuttleでNOPASSWDが効かなくなっていた
突然sshuttle --sudoers
で設定してたNOPASSWDが効かなくなったのでなんでだろうねーと思っていたのですが、sshuttleが1.1.0にアップデートされて意図せずコマンドの順序が変わっていたということが原因のようです。
既にmergeされているのでそのうち直りそうですね。
gensim/word2vecにwindow幅を固定する最高オプションが追加されていた
gensim/word2vecではwindow幅を無茶苦茶に大きくしてもランダムにsamplingされるので、実際には単語同士が遠い場合にコンテキストとして扱われない可能性がありました。
そこでこのwindow幅を固定するためのshrink_windows
オプションを追加するp-rがmergeされていました。これをFalse
にすることで固定するという感じです。
このオプションのモチベーションとしては語順が重要でないコーパス(例えば自然言語を分かち書きしたものではなく、特定の単語列をsentenceとして読み込ませた場合など)に対してはsentence内の全単語をコンテキストとしたほうが普通に考えたら正しそうだよね、みたいなことがありうるのでそういうパターンで有効です。
TypeScriptである型の部分型であることを保証する型定義
言い換えると、あるオブジェクトAに存在するプロパティが、あるオブジェクトBに生えているプロパティのいずれかに該当することを保証し、かつどのプロパティが生えてるかは自由、という感じにしたい。
追記:
id:nanto_vi さんに教えていただいたのですが、組み込みで Partial
という型があり、基本的にはこちらを使えば良さそうです。
TypeScript: Documentation - Utility Types
以下中身がどうなっているかなど
keyofとMapped Type使えばなんかできそうだなーと思いつつも
type PartialObjectOf<T> = { [P in keyof T] : T[P] }
こんな風に書くと結局全てのプロパティを持っていないといけないし、どうすればスマートに書けるかなーと思っていた。
実際にはこう書けば良い
type PartialObjectOf<T> = { [P in keyof T]? : T[P] }
要はプロパティがoptionalであることを示せばよいわけですね。
ちなみに一部のプロパティが確実にあることを保証したい場合は以下のように交差型を使用すればよいです。
type PartialObjectOf<T> = { [P in keyof T]? : T[P] } & { prop: string }