mizdra's blog

ぽよぐらみんぐ

1Password のカスタムフィールドを autofill に利用する

1Password にはカスタムフィールドという機能があります。これを使うと、ログインのためのちょっとしたメモや、秘密の質問の答えなど、好きな情報を id/pass とともに記録できます。

f:id:mizdra:20211005001726p:plain
秘密の質問の答えを記録している様子

ところでこのカスタムフィールドは、実はログインフォームなどの autofill に活用することもできます。

具体例

例えば以下のような HTML Form があると仮定します *1

See the Pen by mizdra (@mizdra) on CodePen.

こうしたフォームがある時に以下のように 1Password を設定しておくと、所々の入力欄を autofill してくれます。

f:id:mizdra:20211005002513p:plain

f:id:mizdra:20211005003109g:plain

id:mizdra が調べた限りでは、以下の規則で「ラベル」や「新規フィールド」を設定しておくと、autofill してくれるようです。undocumented な機能だったので、正確な仕様は分かりません *2

  • ラベル: 以下のいずれかにマッチするもの
    • autofill したい入力欄のname属性の値に部分一致する文字列
    • autofill したい入力欄のid属性の値に部分一致する文字列
    • autofill したい入力欄に対応するlabel要素のテキストに部分一致する文字列
  • 新規フィールド
    • autofill したい値 (value属性の値)

別解

実はカスタムフィールドとは別に、form の autofill 用の設定を記入する欄が 1Password に用意されています。非常に分かりにくいのですが、Mac 版の 1Password 7 では「保存済みのフォームの詳細を表示」 から、その入力欄を表示できます。

f:id:mizdra:20211005003643p:plain

f:id:mizdra:20211005003850p:plain

専用の入力欄があるならそっちを使えば良さそうと思いつつ、入力欄が下の方にあって使い勝手が悪そうな感じもして難しいですね。皆さんはどうしてますか?

*1:説明のために誕生年を要求するフォームを挙げていますが、勿論こういったログインフォームを作るべきではありません。

*2:1Password のブラウザ拡張機能のソースコードを見ればなにか分かるかも

Sentry で IP アドレスの収集をやめる

@sentry/browser を使うと、ブラウザでエラーが発生した時にそのエラーを Sentry の集計サーバに送信して記録してくれます。送信されたエラーはエラーの種類ごとに Issue という単位にグルーピングされ、Issue ごとに何件発生しているのか、何人のユーザで発生しているのか、過去2週間にどれぐらいのエラー数の増減があったのか、などと簡潔に表示してくれます。便利ですね。セットアップも非常に簡単で、十数行程度のセットアップコードを書くだけで使い始めることができます。

f:id:mizdra:20210929005415p:plain
エラーが Issue ごとにグルーピングされている様子。画像は https://docs.sentry.io/product/issues/ から引用。

IP アドレス の収集をやめる

ところでこのエラーが発生したユーザ数 (画像の USERS のカラムの部分) なのですが、デフォルトではエラーの送信元の IP アドレスを元に割り出しています。ブラウザから Sentry の集計サーバにエラーが送信されると、集計サーバ側で送信元の IP アドレスを取得し、それをキーにユーザを識別しています *1。何もしなくても勝手にユーザ識別してくれて便利ですね。

一方でプロダクトによっては諸事情で IP アドレスの収集をやめたいということもあると思います。実は管理画面から IP アドレスの収集をやめるオプションがちゃんと用意されています。

  • プロジェクトごとに収集停止する場合
    • Settings -> オーガニゼーション -> プロジェクト -> セキュリティとプライバシー > Prevent Storing of IP Addresses を ON に
  • オーガニゼーション全体で収集停止する場合
    • Settings -> オーガニゼーション -> セキュリティとプライバシー > Prevent Storing of IP Addresses を ON に
    • オーガニゼーション全体で収集停止すると、オーガニゼーション全体で強制的に収集停止になりプロジェクトごとに ON/OFF の切り替えさえできなくなってしまうので注意してください

IP アドレスの収集停止による弊害

IP アドレスの収集をやめると、Sentry からユーザを識別できなくなってしまいます。その結果として当然といえば当然なのですが、Issue ごとのユーザ数を見ることができなくなってしまいます。

f:id:mizdra:20210929113314p:plain
ユーザが識別できなくて、ユーザ数が 0 埋めされてしまっている様子

ユーザ数はその Issue の深刻度を判断する上で非常に重要な情報ですから、これが見れないとなると Issue のトリアージが困難になってしまいます。IP アドレスの収集をやめたいとはいえ、流石にこれだと困りますね。

手動でユーザ情報を設定する

実は @sentry/browser では任意のユーザ情報を設定する Sentry.setUser という API が用意されています。これを使うと IP アドレス以外の任意のデータを、ユーザを区別するための情報として設定できるようになります。

例えば、以下のようにページアクセスの度にランダムで生成した文字列を id として設定しておけば、とりあえずユーザ数は表示されるようになります。もしセッションを跨いでも同じユーザであると判定したければ、localStorageid を保存しておけば良いです。

/** 0 以上 max 未満の整数をランダムで返す */
function getRandomInt(max: number): number {
  return Math.floor(Math.random() * max);
}

// Sentry SDK の初期化
Sentry.init({
  // ...
});

// ユーザ情報をセット
Sentry.setUser({ id: getRandomInt(0xffff_ffff).toString() });

もし IP アドレスを収集していないプロジェクトをやっていて、同様の問題でお困りの方が居ましたら、ぜひお試しください。

巨大なコードベースに対して段階的に新しい ESLint rule を導入する

背景

  • 既存の巨大なコードベースに対して新しい ESLint rule を導入したいことがある
    • ESLint を導入した段階では厳しすぎて OFF にしていたけど、やっぱり便利なので ON にしたい、みたいなケース
    • 例えば @typescript-eslint/no-floating-promises とか
  • しかし既存のコードベースはそのルールに従っていないため、ON にすると大量に lint エラーが出てしまう
    • 例えば数百件とか
  • 手で修正するのは現実的ではない、eslint --fix で修正できる rule でもない、けど便利な rule なので有効化したい
    • さてどうしよう

解決策

以前このブログでも紹介した eslint-interactive というツールに、lint エラーが出ている行に一括で // eslint-disable-next-line xxx を挿入する機能があります。これを使うと、ひとまず既存のコードでは該当 rule は無視して、新規のコードでは rule を有効化する、といったことが簡単に実現できます。

youtu.be

github.com

eslint-interactive とは何か、については以前記事を書いたので是非そちらをお読み下さい。

www.mizdra.net

使ってみてね。

補足: suppress-eslint-errors との違いについて

同等の機能を持ったツールに suppress-eslint-errors というものがあって、これでも全く同じことができます。

github.com

じゃあ何で eslint-interactive 側に rule を無効化する機能を追加したかというと、良いユーザ体験を提供したかったからです。元々 eslint-interactive にはコードベース中の lint エラーを見やすくまとめてくれる機能があったり、rule ごとに eslint --fix できる機能があって、それと一緒になっていたほうが何かとユーザ的には嬉しいだろう、みたいな狙いがあります。1つのツールで完結する嬉しさを実現したかった。

2021/9/8 追記

v2.0.0 をリリースして、 suggestion *1 も機械的に適用できるようになりました。

svh という策定中の CSS Unit について

CSS Values and Units Module Level 4 という提案にて、 svh という新たな CSS Unit の導入が検討されています。簡単に言うと、ブラウザのナビゲーションバーやオムニボックスの高さを除外した vh です。

今までは実際にユーザがブラウザで見ている範囲内に要素を収めるには JS で動的に可視領域の高さを計算する必要がありましたが、これが導入されると CSS だけで実現できます。従来の JS を使ったハックでは CSS が適用されてから JS の実行が行われて高さが変更されるため、Layout Shift が発生していましたが、svh を使うとこの Layout Shift を回避できます。Above the fold に動画や画像を画面いっぱいに表示したい時などに便利そうですね。

ブラウザベンダの実装状況

そもそもまだ仕様がドラフトの段階で、実装は全く進んでいません。一応 Issue は出ているので、興味があればトラッキングしてみましょう。早く使えるようになると良いですね *1


以前 Twitter を見ていたら目に入ったので、調べて書いてみました。

*1:もちろんまだドラフト段階なのでどうなるか分かりませんが

nodebrew と homebrew の Node.js が重複しないようにする

普段 yarn を homebrew で管理していているのだけど、yarn が node への依存を持っているせいで、インストールしたり、更新したりする時に Node.js が homebrew で追加でインストールされることがある。けど Node.js は nodebrew で管理しているので、2重でバイナリが存在してむず痒い。何とかしたい、という話。*1 *2

作戦

  1. homebrew でインストールした Node.js バイナリをアンインストールする
  2. nodebrew でインストールした Node.js バイナリを homebrew の管理化に置く
  3. homebrew 側で node fomula のバージョンを固定して、brew upgrade でアップグレードされないようにする

1. homebrew でインストールした Node.js バイナリをアンインストールする

brew uninstall node でアンインストールできる。ただし yarn などから依存されている関係で、そのまま実行してもアンインストールできない。--ignore-dependencies を付けて実行する必要がある。

$ # まず homebrew でインストールしたバイナリがあることを確認して...
$ brew list node
/usr/local/Cellar/node/15.12.0/bin/node
/usr/local/Cellar/node/15.12.0/bin/nodebrew
/usr/local/Cellar/node/15.12.0/bin/npm
/usr/local/Cellar/node/15.12.0/bin/npx
/usr/local/Cellar/node/15.12.0/include/node/ (482 files)
/usr/local/Cellar/node/15.12.0/lib/dtrace/node.d
/usr/local/Cellar/node/15.12.0/lib/node_modules/ (2550 files)
/usr/local/Cellar/node/15.12.0/share/doc/ (2 files)
/usr/local/Cellar/node/15.12.0/share/man/man1/node.1
/usr/local/Cellar/node/15.12.0/share/systemtap/tapset/node.stp

$ # アンインストール
$ brew uninstall node --ignore-dependencies
Uninstalling /usr/local/Cellar/node/15.12.0... (3,283 files, 56MB)

$ # アンインストールされたことを確認
$ brew list node
Error: No such keg: /usr/local/Cellar/node

2. nodebrew でインストールした Node.js バイナリを homebrew の管理化に置く

homebrew には brew link という、自前ビルドしたバイナリなどを homebrew の管理化に置くためのコマンドが用意されている。

github.com

これを使うと、nodebrew でインストールした Node.js バイナリを homebrew の管理化に置くことができる。

$ # まず brew doctor して node が足りないぞと言われていることを確認
$ brew doctor
...
Warning: Some installed formulae are missing dependencies.
You should `brew install` the missing dependencies:
  brew install node

Run `brew missing` for more details.

$ # /usr/local/Cellar/node に nodebrew でインストールした Node.js へのシンボリックリンクを貼る
$ mkdir /usr/local/Cellar/node
$ ln -s ~/.nodebrew/current/ /usr/local/Cellar/node
$ brew link --overwrite node

$ # 再度 brew doctor して警告が出なくなったことを確認
$ brew doctor

$ # homebrew から見えるバイナリの位置も確認しておく
$ brew list node
/usr/local/Cellar/node/current/bin/node
/usr/local/Cellar/node/current/bin/nodebrew
/usr/local/Cellar/node/current/bin/npm
/usr/local/Cellar/node/current/bin/npx
/usr/local/Cellar/node/current/include/node/ (482 files)
/usr/local/Cellar/node/current/lib/dtrace/node.d
/usr/local/Cellar/node/current/lib/node_modules/ (2550 files)
/usr/local/Cellar/node/current/share/doc/ (2 files)
/usr/local/Cellar/node/current/share/man/man1/node.1
/usr/local/Cellar/node/current/share/systemtap/tapset/node.stp

3. homebrew 側で node fomula のバージョンを固定して、brew upgrade でアップグレードされないようにする

最後に brew upgrade で homebrew でインストールした Node.js がアップグレードされてめちゃめちゃにならないよう、バージョンを固定するようにしておく。これは brew pin を使うとできる。

$ brew pin node

おわり。

おまけ

実は今回紹介した手法は、以下の nvm + homebrew 向けの記事を homebrew 向けにアレンジしたものになっている。nvm の人はこの記事を見れば全く同じことが達成できるはず。

github.com

*1:正直 yarn を homebrew でインストールしなければ良いのだけど、yarn 以外でも依存関係でインストールされることがある。最近だと https://github.com/antonmedv/fx とか…

*2:ちなみに homebrew でインストールした Node.js がどの fomula から依存されているかは brew uses node と打つと分かります。

icon-suggestion v2 をリリースしました

あの大人気 Scrapbox UserScript の v2 をリリースしました。既に icon-suggestion をお使いの方は、自動で v1 からアップデートされているはずです。

「icon-suggestion って何?」という方はこちら:

www.mizdra.net

前バージョンからの変更点

  • ポップアップを開く度に最新のアイコンを suggest するように
    • 以前のバージョンでは suggest されたアイコンはキャッシュされ、Ctrl+R を押すか、リロードするまでアイコンリストが更新されませんでした
    • 本バージョンから、ポップアップを開く度に最新のアイコンリストが表示されるようになります
  • isSuggestionReloadKeyDownオプションが廃止されました
    • アイコンリストの手動更新が不要になったため
    • キーワードにマッチするアイコンが無い場合に Enter を押すと、[入力したキーワード.icon]が入力されるようになりました
  • presetIconsオプションでプリセットアイコンを登録できるようになりました
    • 好きなアイコンをプリセットとして登録しておくと、suggest box表示中にCtrl+Lを押した際に suggest されます
  • Firefox でアイコンの挿入ができない問題を修正

1 番目と 3 番目の変更については、以前からユーザから欲しいとご意見を頂いていたものです。お待たせしました!是非使ってみて下さい。プリセットアイコンの登録方法は、以下の Scrapbox にて解説しています。

scrapbox.io

開発者向け情報

本バージョンから、ソースコードが GitHub で管理されるようになりました。もし不具合を発見したり、欲しい機能があれば、Issue を出したり PR を送って頂けるようになっています。テストも Unit テストから E2E テストまで用意していて、安心して contribution して頂けるような環境になっていると思います。あと Preact 使ってます。皆さんからの contribution をお待ちしています。

github.com

Special Thanks

JavaScript で print デバッグ時に変数名を出力する

数列の和を求めるプログラムを作成することになり、意気揚々と以下のようなプログラムを書いたという状況を想像して下さい。

function sum(nums, acc = 0) {
  if (nums.length === 0) return 0;
  if (nums.length === 1) return nums[0];
  return sum(nums.slice(1), acc + nums[0]);
}

const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(sum(nums)); // expected: 55

一見すると何も問題なさそうに見えるプログラムですが、実はバグがあります (皆さん分かりますか?) *1。実際に上記プログラムを実行すると 55 ではなく 10 が出力されます。

こうした場面に遭遇すると、自然と sum 関数が呼び出される度に numsacc がどう変化していくかを知りたくなってきます。この時取りうるデバッグ方法には様々なものがありますが、最も簡単なのは print デバッグでしょう。

function sum(nums, acc = 0) {
  console.log(nums);
  console.log(acc);
  if (nums.length === 0) return 0;
  if (nums.length === 1) return nums[0];
  return sum(nums.slice(1), acc + nums[0]);
}

これを Chrome devtools の Console パネルで実行すると以下のように出力されます。出力がどう整形 (色が付いたり、クリックで折りたたみを展開できたり) されるかは、その JavaScript 実行環境 (Chrome や Firefox、Node.js など) によりますが、大体どの実行環境でも似たような見た目で出力されるはずです。

f:id:mizdra:20210502225505p:plain

複数行に渡る出力を1行にまとめたい

実は console.log は複数の引数を渡せるようになっていて、以下のように書くこともできます。一度に複数の値を渡すと、それらの値は一緒の行にまとめられて出力されるので、1回の呼び出しで複数行出力されて見にくいという不満を解消できます。便利ですね。

function sum(nums, acc = 0) {
  console.log(nums, acc);
  if (nums.length === 0) return 0;
  if (nums.length === 1) return nums[0];
  return sum(nums.slice(1), acc + nums[0]);
}

f:id:mizdra:20210502230145p:plain

ここまではよくある tips ですね。

変数名も出力したい

出力する変数がだんだん増えてくると、出力の何番目がどの変数だったのか判断が難しくなります。当然変数名も一緒に出力して、どの値がどの変数のものかがひと目で分かるようにしたくなってくると思います。

そうした状況でオススメなのが、次のテクニックです。

function sum(nums, acc = 0) {
  console.log({ nums, acc });
  if (nums.length === 0) return 0;
  if (nums.length === 1) return nums[0];
  return sum(nums.slice(1), acc + nums[0]);
}

f:id:mizdra:20210502230518p:plain

console.log の引数リストを { ... } で囲うだけです。これだけで変数名も一緒に出力されるようになります。簡単ですね。

変数名が出力される仕組み

「何でこれで変数名が出力されるの?」という疑問を持った方も居るともうので、軽く解説します。先程のコードは Shorthand property names という、オブジェクトを初期化するためのシュガーシンタックスです。ES2015 で導入された比較的新しい *2 記法です。以下の2つのコードは等価になります。

console.log({ nums, acc });
console.log({
  nums: nums,
  acc: acc,
});

つまり先程のコードは、変数 nums の値を nums という名のプロパティに、変数 acc の値を acc という名のプロパティに持つオブジェクトを console.log で出力していた訳ですね。変数名を出力していたというよりは、たまたま変数名と同じ名前のプロパティ名が出力されていて、変数名が出力されているように見えていた、という感じです。

別解: degugger; を仕込む

結構忘れられがちなのですが、専用のデバッガを使うという手もあります。変数名の表示はもちろん、スタックトレースの表示やステップ実行ができたりと、print デバッグよりもずっと高級なデバッグ体験が得られます。もし高級なデバッグ体験が欲しければこちらを使うのが良いでしょう。

デバッガを利用する最も手軽な方法は、 debugger 文です。変数の値を覗き見したい行に debugger; と書いて Chrome などで実行すると、その行に到達した瞬間にデバッガが自動で起動して、実行が一時停止します *3。後はデバッガのメニューから変数の状態を見たり、ステップ実行してみたりと好き放題できます。

f:id:mizdra:20210502234958p:plain

デバッガは利用するための環境構築が大変なイメージがあり、敬遠されがちですが、便利なのでスキを見て使っていけると良いと思っています。最近の VSCode でもエディタ組み込みのデバッガの開発に力を入れていたりと、どんどんデバッガの利用が容易になっているように感じています。debugger; くらいなら簡単に始められるので、是非使ってみてはいかがでしょうか。

おまけ1

実行環境がChrome devtools、かつ関数呼び出しの入力を監視したい時限定で、変数名を出力出来るわけではないけど、monitor 関数も便利だよと教えて頂いた。便利!!!

blog.pastak.net

おまけ2

サムネオチって言葉久々に聞いた気がする。

*1:解: 3行目で acc を足し忘れている

*2:といっても標準化されてから約6年経過してますが。

*3:何となく分かると思いますが、debugger; のある行に breakpoint を仕掛けたかのような挙動になります。

ポケットモンスター・ポケモン・Pokémon・は任天堂・クリーチャーズ・ゲームフリークの登録商標です.

当ブログは @mizdra 個人により運営されており, 株式会社ポケモン及びその関連会社とは一切関係ありません.