属性も slot みたいに使えたらいいのに
custom element の子要素は slot を使って shadow dom 内に配置できます
その場合 custom element の子要素を変更すると即時に shadow dom 内の要素に反映されます

これが便利なのですが 自由にタグを書けるのでテキストだけ受け取りたいときには向いていません
そういうときには custom element の属性を使いたいのですが そうなると slot みたいな便利機能はありません

自分で JavaScript の処理で shadow dom 内の要素に属性の文字列を入れる必要があります
さらに変更されたときに shadow dom 内にも反映したいなら 属性の変更を監視して 変更時に自分で shadow dom 内の要素の更新が必要です

Framework なしの WebComponents を使うと この辺りが面倒なのですよね
slot のように自動で反映してくれる仕組みがあるといいのですけど
Node.js で HTML 取得して DOM 操作
ふとローカルのスニペット管理ツール使ってよく使うのは選んでコピペするだけで済むようにしようと思いました
言語指定でちゃんとやるなら VSCode の機能があるけど もっとゆるくグローバルで使うもの
コード対応で軽量のメモツールってあまりないからとりあえず markdown 系メモの適当なやつ

それにこのブログの「コード」カテゴリのも登録しとこうかと思って自動で登録するためのところを作ったのでメモ

const fetch = require("node-fetch")
const { JSDOM } = require("jsdom")
const { add } = require("./add.js")

const main = async (url) => {
const res = await fetch(url)
const html = await res.text()
const dom = new JSDOM(html)
const articles = dom.window.document.querySelectorAll("main article")

for(const article of articles) {
const title = article.querySelector(".article-header .article-title").textContent
const body = Array.from(
article.querySelectorAll(".article-body pre code"),
code => {
for(const br of code.querySelectorAll("br")) {
br.replaceWith("\n")
}
const type = code.dataset.lang || ""
const c = code.textContent.trimEnd()
return "```" + type + "\n" + c + "\n```"
}
).join("\n\n")

add(title, body)
}
}

main("http://let.blog.jp/category/%E3%82%B3%E3%83%BC%E3%83%89")
yarn add node-fetch jsdom
node <script>.js

add.js はパースされた title と body を登録する処理

title は記事のタイトル
body はテキストで本文のコードブロックをマークダウン形式にしたもの
複数あるなら空行挟んで複数個のコードブロック

Node.js でもブラウザと同じように DOM 操作できる jsdom 便利
throw の仕方いろいろ
◯ 詳細なし

単純に Error のインスタンスを作って throw

throw new Error("aa")

◯ assign

エラー処理などに使う補足のデータを含めたいとき
プロパティとして Error オブジェクトに追加する 

throw Object.assign(new Error("aa"), { detail: "xxxx" })

◯ object

Error オブジェクトと補足情報を別々にもつオブジェクトを throw する
throw 対象は Error オブジェクトじゃなくてもいい

throw { error: new Error("aa"), detail: "xxxx" }

◯ custom error type

ちゃんとした作りにするなら Error を継承したそれ用の型を作るのがたぶん適切
異なる型なので特別なプロパティを持ってそうということが伝わるし instanceof で種別判定もできる

class AaError extends Error {
constructor(message, detail) {
super(message)
this.detail = detail
}
}

throw new AaError("aa", "xxxx")

◯ no error object

Error オブジェクトは特に必須じゃない
スタックトレースが要らないなら省いてもいい

throw { error: "aa", detail: "aa-error" }
Node.js でも console.table できる
罫線をうまく使って表が表示される
さすがにブラウザみたいにヘッダクリックでソートは無理

Linux だと問題なくキレイに表示されてるけど Windows だとずれて表示された
フォントの問題みたい
横線が半角でいいのに全角表示されるのが原因
Linux での表示もコピペしてエディタで見るとずれる

console.table([{x: 1, y: 2}, {x: 3, y: 0}, {x: 4, y: 4}])
┌─────────┬───┬───┐
│ (index) │ x │ y │
├─────────┼───┼───┤
│ 0 │ 1 │ 2 │
│ 1 │ 3 │ 0 │
│ 2 │ 4 │ 4 │
└─────────┴───┴───┘

半角ハイフンに置換してみると

┌---------┬---┬---┐
│ (index) │ x │ y │
├---------┼---┼---┤
│ 0 │ 1 │ 2 │
│ 1 │ 3 │ 0 │
│ 2 │ 4 │ 4 │
└---------┴---┴---┘
連番なしに◯回ループ
◯回ループするだけならこれでよかった

for (const k of Array(3)) console.log(1)
// 1
// 1
// 1

Array コンストラクタで作った empty 要素でも for-of ならループ対象
Array.from(Array()) や [...Array()] と一緒でイテレータ使ってるんだからよく考えたらできて当たり前
いったん中身のある配列化しなくてよかった

ちなみに for-in ではキーがないので非対象

for (const i in Array(3)) console.log(1)
// (no output)
IntersectionObserver v2
https://developers.google.com/web/updates/2019/02/intersectionobserver-v2

IntersectionObserver を使っていて VSCode の補完に出てこない isVisible ってプロパティがあるけどずっと false なのが気になって調べてみると上のページが出てきました
v2 の機能みたいです

v2 では実際に見えているかをチェックできるみたいです
ただ 単純な位置計算だけでできなくて重くなるので気軽に使うものではなさそうです

IntersectionObserver コンストラクタのオプションに delay と trackVisibility が追加されて trackVisibility が true だと v2 の機能が使えるようになるようです

isVisible の「見える」というのは「対象の要素が他の要素に完全に遮られておらず スクリーン上で変更や歪めるようなエフェクトを受けてないことを強く保証するもの」だそうです
逆に 「見えない」はその保証ができないということのようです

仕様では isVisible は false negatives は許可されてて false positives は許可されてないそうです
見えてるのに false になることはあるけど 見えてないのに true になることはない ということですね
yarn install で install されない
node_modules 内のパッケージのフォルダを直接消した場合は yarn install してもインストールされません

node_modules フォルダ中の .yarn-integrity ファイルにインストール関連の情報が保存されていて lockfileEntries にインストール済みパッケージとバージョンが書かれています
ここを見て更新の必要があるかを判断するので 実際にフォルダがなくても .yarn-integrity の情報と yarn.lock の情報が一致していれば最新状態と判断されます

フォルダを消してしまった場合は .yarn-integrity の中から再インストールしたいパッケージの行を削除すると yarn install でインストールできるようになります
探すのが面倒なら このファイルごと消してしまっても全部インストールされるので大丈夫です


直接ライブラリのソースをいじっていろいろ試して もとに戻したいからフォルダ消して再インストールしたかったのですが そういう場合は注意が必要です
npm のバージョンリストに日付を表示する
npm の Version History のところは相対日付しか表示されていなくて 2 years ago とかが並んでてもあまり嬉しくないです
具体的にいつ頃なのかわからないですし このバージョンとこのバージョンの間はどれくらい空いてたのかを知りたい時とか不便すぎです

一応マウスを乗せるとツールチップで表示されますが ひとつひとつ乗せないとダメなのは面倒です
同時に見れないですし

そこで title 属性(ツールチップのテキスト)を表示するような CSS を用意しました

time:before {
content: attr(title);
color: #d0841e;
font-size: 11px;
margin-right: 20px;
}

このスタイルを npm のページで表示するようにすれば相対日付の左側に完全な日付が表示されます
配列のシャッフル
わりと普通にやると

const values = [...Array(100).keys()]

const shuffle = a => {
const size = a.length
for (let i = 0; i < size; i++) {
const j = ~~(Math.random() * size)
const t = a[i]
a[i] = a[j]
a[j] = t
}
}

shuffle(values)

長いし サッとやりたいときに書くのも面倒

これでいいかも
ランダムに 1 つ取り出して 最後に push を要素数だけ繰り返し

const shuffle = a => {
const size = a.length
for (let i = 0; i < size; i++) a.push(...a.splice(Math.random() * (size - i), 1))
}

速度は上のよりかなり遅いのでその場限りで短く書きたい時向け
よく見ると 言うほど文字数は変わってない気もする
モバイルのマウスイベント
タップで click イベントが起きる

◯ Android
長押しで contextmenu イベントが起きる
ダブルタップしても dblclick イベントは起きない

◯ iOS
長押ししても contextmenu イベントは起きない
ダブルタップで dblclick イベントが起きる
Let's Encrypt 事件のバグ
https://jovi0608.hatenablog.com/entry/2020/03/09/094737
Let's Encrypt の証明書失効の原因は Go を使ったループ時の参照の扱いだったみたいですね

JavaScript でも var 時代にループ内で関数を作るとありがちだった問題です

const fns = []
for(var i = 0; i < 3; i++) {
fns.push(() => console.log(i))
}
fns[0]()
fns[1]()
fns[2]()

// 3
// 3
// 3

ニュースで見かけたときは何があったんだろうと思ってたらこんな基本的なミスが原因だったんですね

Go は詳しくないですが for の中で確保された i ってブロックスコープじゃないのでしょうか
i の参照を保持して out[0] でアクセスするときに解放された場所にアクセスしてそうに見えます
それでコンパイル時にエラー出れば防げそうなのに

この記事に対するコメントをみてみると Rust なら大丈夫だったみたいなのがありますし Rust だとこういうところも安全のようですね

そもそも Let's Encrypt って Go で動いてたんだ
ローカルにデータを残す GitHack は注意したほうがいいかも
GitHackGist に投稿したデータをホスティングしてくれるサービスです
Gist に保存したHTML ファイルをウェブページとして見ることができます
RawGit の後継みたいなもの
サーバ側での処理が不要なツール・アプリを公開する目的で使えます

GitHack に限るものではないですが HTML をホスティングしてくれるサービスではオリジンに注意したほうが良さそうです
こういったサービスは URL が Gist の URL に関連していて単純にファイルを text/html などの content-type で送信してます
その結果オリジンはみんな一緒です
localStorage などはオリジンごとに異なる領域になりますが オリジンが一緒なら共有です
つまり保存した情報は他人のページからでも見れます

GitHack でホスティングされてるローカルメモツールを使っていたとしたらデータは localStorage などに保存されます
その後悪意あるユーザの GitHack を開くと そのメモが全部どこかに送信される……ということもありえます

悪意がなくても保存する名前が被っていたら上書きされてデータが消えます
もちろん他人とだけじゃなく 自分のツール同士でもありえます
全部のツールで保存するキーを data に統一していたら 別のページを開いたらそっちのデータで上書きされます

投稿している Gist サービスではそれぞれが別の git リポジトリなので独立してそうに思ってしまうのですがホスティングするサービス上は全部いっしょなんですよね
Github Pages などのホスティングサービスはユーザごとにサブドメインなのでオリジンは異なります
自分のリポジトリ同士では保存領域が共有ですが 他人のは別なので盗み見られる心配はないです

そう考えると ウェブページとして表示するツール系は Gist よりもリポジトリのほうがいいのかもしれませんね
個人的には git クライアントで push とかはほぼせずに ブラウザ使ってフォームにテキスト貼りつけて更新したいのでフォルダ構造不要で数ファイル程度なら Gist のほうが気楽に使えていいのですけど
≡メニュー
≡メニューをどう実装するかというのを見かけたので
その時の気分でよく変わるけど最近はこういう感じ

<div class="hover-target">
<div class="face">≡</div>
<ul class="menus">
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
</div>

<style>
.hover-target {
display: inline-block;
}
.hover-target:not(:hover) .menus {
display: none;
}
.face {
display: flex;
width: 1.5em;
height: 1.5em;
justify-content: center;
align-items: center;
cursor: default;
box-shadow: 0 0 2px 1px #0003;
}
.menus {
border: 1px solid #bbb;
margin: 5px 0;
padding: 0;
list-style: none;
}
.menus li {
border-bottom: 1px solid #ddd;
padding: 5px 15px;
margin: 0;
cursor: pointer;
}
</style>
ウェブアプリって思ったほどキーボード操作が考えられてない
◯ 操作できないはずの input 系が操作できる
まとめて disabled が面倒なのか上に透明要素が乗ってるだけや pointer-events: none してるだけ
マウスで操作できなくして CSS で操作できない風に見せてる
マウスじゃ操作できないけどキーボード操作でフォーカス合わせて入力できてしまう

◯ 隠れてるだけ
タブ切り替えなどの見える部分と見えない部分がある UI
アニメーションの都合なのか見えていない要素は削除されずに残ってる
overflow: hidden の外側など見えない場所にはちゃんと存在する
タブキーで見えてない input にフォーカス移すと それが画面内にくるように中途半端なスクロールされる
そのせいで画面壊れる


そんな感じの見た目とマウス操作前提だけで考えてるのが多めな印象

そういう自分も面倒なのでマイナーユーザのためにわざわざ考慮しないけど
動的型付け言語でまで静的型付け言語みたいなことしないでほしい
あるプロパティ mode には "includes" か "equals" を文字列で指定するものとします
こういうのがあると一々 enum だったり定数だったりを作る人がいますよね

enum 等の型がすでにあって mode プロパティを受け取る側がその型を指定するようになっているならそれでいいです
しかし そうでもなく最終的に文字列を入れるのであれば それをわざわざ定数化したりとかムダなことはしたいとは思いません

文字列で 2 種類入れるからそういう事を考えるわけであって プロパティが mode_includes という名前で true か false を指定するのであればどうするのでしょう?
普通に true/false を使いますよね
"includes" の文字列だった部分はプロパティ名として扱うことになりましたがプロパティ名を定数や enum として扱うのでしょうか?
さすがにそんなことはしないと思います

プロパティ名であればそのまま文字列として扱うのであれば mode に入れる "includes" なども文字列としてソースコード上で扱えばいいのです
正規表現の Unicode Property
new RegExp(/\p{sc=Hiragana}/u)

みたいなの
他言語だと 「sc=」 がいらないようでそれを参考にしたらエラーが出る

JavaScript の Unicode Property の指定方法はこれ

// Non-binary values
\p{UnicodePropertyValue}
\p{UnicodePropertyName=UnicodePropertyValue}

// Binary and non-binary values
\p{UnicodeBinaryPropertyName}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes

「For most values, the UnicodePropertyName part and equals sign may be omitted.」(ほとんどの値で UnicodePropertyName とイコール記号は省略できる)って書いてるのに Hiragana はだめらしい

その他指定できるプロパティの一覧
https://www.ecma-international.org/ecma-262/10.0/index.html#sec-runtime-semantics-unicodematchproperty-p

ECMAScript のスペックは whatwg みたいに分割版がなくて ES2019 が全部入りのページなせいでかなり重い
今後更新されないはずだけどそう変わるものでもないので 提案時のスペック見るのもあり

https://tc39.es/proposal-regexp-unicode-property-escapes/#sec-runtime-semantics-unicodematchproperty-p
mac にデフォルトのスクリプト言語なくなるんだ
mac でスクリプト言語がデフォルトで入らなくなるというのを見かけて気になったので調べてみました

https://developer.apple.com/documentation/macos_release_notes/macos_catalina_10_15_release_notes
「Scripting Language Runtimes」 のところ

Python, Ruby, and Perl がデフォルトで含まれなくなるようです
Python や Perl ならともかく Ruby まで入ってたんですね
Ruby あるのに Node.js はないんだ……

デフォルトで使えるスクリプト言語がなくなるって結構つらそうですが 最近は多いのでしょうか
CentOS8 もデフォルトだとなにもないです
正確には Python3 がシステム用に入ってますが ユーザが使うべきじゃないという扱いでパスも通されずわかりづらい場所にあります

読んでてもう一つ気になったのが 「あなたのソフトウェアがスクリプト言語に依存するなら ランタイムをアプリと一緒にバンドルすることをおすすめします」って部分
各ソフトウェアが Python や Ruby のランタイムを独自に持ってたらすごく重くなりそうです
Electron みたいなことになりそう
ただ 言語仕様の追加変更が速くなると想定バージョンも色々あって独自に持ってるのがなんだかんだユーザには一番便利なのかもしれません
Node.js (V8) パフォーマンス比較
普段プログラムを実行してるとき ソフトやブラウザのタブをあれこれ開いてても重くならないくらいのスペックの PC (Windows) で動かしたり VM の最低限度の環境で動かしたりしてもあまり速度差を感じません
感じるときといえばディスク速度が遅い場合に npm ライブラリの初期ロードが遅いくらいです

CPU だけに依存する処理なら意外とどこでも変わらないのかと思って⇩のコードをいくつかの環境で実行してみました

node -e "for(let x=0;x<5;x++){console.time(x); for(let i=0,j=0;i<1000000;i++) j+=i; console.timeEnd(x);}"

VM 上の Fedora 31 (Node.js 13.5)

0: 16.607ms
1: 8.044ms
2: 0.962ms
3: 0.949ms
4: 0.99ms

VM 上の Fedora 31 (Node.js 12.16.1)

0: 13.867ms
1: 5.012ms
2: 0.960ms
3: 0.953ms
4: 0.954ms

メインの Windows 10 (Node.js 12.13)

0: 4.398ms
1: 3.273ms
2: 1.232ms
3: 1.186ms
4: 1.192ms

メインの Windows 10 (Chrome 80)

0: 4.19091796875ms
1: 3.22216796875ms
2: 1.18603515625ms
3: 1.219970703125ms
4: 1.222900390625ms

ノート PC Windows 7 (Node.js 12.6)

0: 5.465ms
1: 4.070ms
2: 0.975ms
3: 0.976ms
4: 0.962ms

Fedora と同じホストに置いてる CentOS (Node.js 10.14)

0: 5.388ms
1: 3.839ms
2: 1.214ms
3: 1.200ms
4: 1.201ms

結果は数回実行して結果が特別外れたものじゃないことを確認してから適当に 1 つ取り出してます

同じ Windows だと Node.js も Chrome もほぼ一緒
Windows と Fedora を比べると Fedora は最初 2 回は遅めで以降は少し Windows よりも高速です
いまいちよくわからない結果です
CentOS のものは Windows よりでした

特別スペックが高い(低い)CPU のマシン使ったりしなければあんまり差はでないようです
Node.js のバージョン差のほうが大きいかも
コマンドラインで JSON 表示 (Node.js 編)
これの Node.js 版

node -p "require('./dump.json')"

node コマンドを普通に実行して REPL で require すればいいだけで Node.js インストール済み環境ならそもそも困らないと思う
Python のと違って .foo みたいなプロパティアクセスでほしいとこだけ取れるのが使いやすい
MDN にくまがいた
https://github.com/mdn/kuma

恐竜でもきつねでもなくて くま
MDN のサイトを作ってるものみたい?
KumaScript なるものもあった
こういう MDN のページはこのスクリプトで書かれてるのかな
Wiki みたいな一般的な記法かと思ってた


よく考えたら kuma って日本語じゃん
Sushi Browser
なんか見つけた謎のブラウザ
https://sushib.me/ja/

Chromium 系ブラウザは色々あっても基本は Chromium なのですがこれは Electron ベースのようです
Node.js が使えるということはローカルアクセスなどブラウザではできない機能が豊富そうです
特にターミナルが使えているのが特徴的

コンセプトは 通常のブラウザでは画面がもったいないから最大限効率化したいということみたいです
効率化しすぎた結果なのかサンプル画面を見てもレイアウトがどうなってるのかよくわからないくらいレベルです
renderer プロセスの HTML で Grid 使ってコントロールや webview いっぱい配置した感じなのでしょうか

思いつきで作ったまま放置されてそうな予感はしたのですがそれなりの期間更新されてるようですし 新しいタイプのブラウザとして使ってみるのはありなのかも?
fs/promises は使えなくなってた
以前 fs のメソッドの Promise 版は fs/promises を require してました
いつのまにか fs.promises ができてて fs をインポートしたら一緒に使えるからこっちを使ってましたが fs/promises はどうなってるんだろうと require したら見つかりませんでした

調べてみたら
https://github.com/nodejs/node/pull/20504

どっちも使えるわけではなく fs.promises に変更だったみたいです

ちなみに fs.promises のインポートでたまに見かけるこれですが

import { promises as fs } from "fs"

fs.existsSync など promises にないメソッドが使えないので fs 自体を変数に持ってたほうがいいと思います
Node.js の http parser が変わってた
Node.js 12 から llhttp に変わってたみたい
これまでの http-parser

元のは C 言語で書かれててメンテが辛かったとか
新しいのは一部が C 言語で大部分が TypeScript
書きやすさ重視で速度はそんなでもないのかと思ったけど 156% 速くなってるみたい

llparser という別のプロジェクトも出てきていまいちわかってないけど
llparser は http 関係なく C 言語や LLVM のビットコードでパーサ自体を作るものみたいだし llhttp は llparser を使って C 言語を出力してそれを実行してるということかな
ベンチマークの llhttp に (C) て書いてるし

Node.js ユーザ的には関係ないことでただ速くなったんだー くらいに思ってれば良さそうなのでこれ以上の詳しいことは調べてない
コマンドライン環境で JSON フォーマットしたい
自動生成された圧縮された JSON をみたいのですが インデントもない状態だと読むのが辛いです
短ければコピペして手元の Windows でフォーマットすればいいのですがちょっと長めです
ローカルまでコピーしてくるのも面倒ですし フォーマットするツールをインストールするのもできれば避けたいです

いい方法ないものかと探してみると Python でできました

python3 -m json.tool min.json

これで min.json をフォーマットして表示できます
デフォルトでいろいろな機能が揃ってるのでやっぱり Python は便利ですね
CentOS8 はデフォルトで入ってないのが残念ですが これくらいなら platform-python 使ってしまって良いかも

注意したいのは 複数指定できないところです

python3 -m json.tool a.json b.json

とすると 2 つを見れるのではなく b.json へ出力となって もとの b.json は消えてしまいます

使い方

user@ubuntu ~> python3 -m json.tool --help
usage: python -m json.tool [-h] [--sort-keys] [infile] [outfile]

A simple command line interface for json module to validate and pretty-print
JSON objects.

positional arguments:
infile a JSON file to be validated or pretty-printed
outfile write the output of infile to outfile

optional arguments:
-h, --help show this help message and exit
--sort-keys sort the output of dictionaries alphabetically by key
Blob に text と arrayBuffer メソッドが増えてた
const b = new Blob([["abcd"]])
console.log(await b.text())
// abcd
console.log(new Uint8Array(await b.arrayBuffer()))
// Uint8Array(4) [97, 98, 99, 100]

FileReader が基本いらなくなる
BinaryString と DataURL 形式は対応してないからこれらが必要なら FileReader を使う
ArrayBuffer から変換もできる

const ab = new ArrayBuffer()
const binary_string = Array.from(new Uint8Array(ab), x => String.fromCharCode(x)).join("")
const data_url = "data:application/octet-stream;base64," + btoa(binary_string)
BigInt 使うときの一時変数に n は使わないほうが良さそう
一行で済む関数くらいなら 引数に変に長い名前を入れるより 1 文字のほうがスッキリ見やすいので 1 文字だけの名前を使うことは多いです
map,filter,forEach などだと e を使うことが多くて reduce や sort だと a, b とか
数値だと num ということで n を使うこともあるのですが BigInt と組み合わせるとかなり見づらい事に気づきました

const fn = n => (n - 1n) * (n / 2n) + (n % 2n) * (n / 2n)

数学では 2 * n を 2n と書くのでそれっぽく見えてしまいます

ちなみにこの関数は引数の数までの自然数を合計したものを返す関数で特に意味はないです
3 なら 0 + 1 + 2 で 4 なら 0 + 1 + 2 + 3 の結果です

console.log(fn(1n))
// 0n
console.log(fn(2n))
// 1n
console.log(fn(3n))
// 3n
console.log(fn(4n))
// 6n
console.log(fn(5n))
// 10n
console.log(fn(6n))
// 15n
console.log(fn(7n))
// 21n
console.log(fn(8n))
// 28n

console.log(fn(1_000_000n))
// 499999500000n
console.log(fn(1_000_000_000n))
// 499999999500000000n
console.log(fn(1_000_000_000_000n))
// 499999999999500000000000n
console.log(fn(1_000_000_000_000_000n))
// 499999999999999500000000000000n
ildasm
dll ファイル調べたら やっぱり C++ で作ったものと .NET でつくったものは全く別ものみたい
同じ拡張子だから 同じように外部から使えるフォーマットかとちょっと期待したけど無理みたい
C++ で作った dll の中身を見るツールに C# で作ったものを入れても何も見れない状態でした

C# で作ったものの中身を見たいと思って調べたら ildasm というツールがあるみたい

コマンドラインツールのようですがダブルクリックで開くとウィンドウが出て GUI で使えました
dll を入れるとクラスやそのメソッドやプロパティなどを表示できます
さらに中間言語での処理を見ることもできました

C++ で作った dll を見るツールとは違いできることが多いです

また JetBrains の dotPeek というツールもあってこっちだと C# のコードまで見れました
本来のソースコードが入ってるわけではないので完全ではないですが 問題なく読める部分が多かったです
IL って思った以上に多くの情報を持ってるのですね

ところで ildasm は .NET Framework 専用で .NET Core にはついてきませんでした
ildasm は .NET Framework の SDK についてくるので VisualStudio を入れてると一緒に入ってるかと思います
場所はこのへん

C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.1 Tools

v10.0A は Windows のバージョンで 7.0A や v8.1A などもあります
NETFX の後の数字は .NET Framework のバージョンです

一応 .NET Core でも非公式なものでパッケージをインストールすることで使えるものはありました
試してないのでクオリティは不明です
esbuild
https://itnews.org/news_contents/oss-esbuild

Go 製で速いらしい
そういえば昔あった Rust 製の JavaScript バンドラーってどうなったんだっけ

比較はキャッシュなしみたいだけど 実際はキャッシュ使うのが当たり前だし スピードが必要な開発中は基本 watch してて更新時に差分だけ置き換えるものだから Webpack や Parcel の速度で困ることはそうそうないと思う

あと Parcel でた頃は設定とか面倒なのしたくないし速いほうがいいしと Parcel 使ってたけど設定できることが少なくて結局 Webpack がメインになったので速度よりも拡張性があるほうがいいな
これは見た感じ速度追求系ぽいけどそのへんどうなんだろう
なんだかんだ短くかけるのは jQuery
ちょっとした事情でコードを短く書きたいときがありました
cdn をロードできるものはその部分は数えません

react や lit-html などは表示したいデータを持ってる場合は便利ですが そうでもない場合は DOM と二重で持って管理することになりますし ライブラリ都合で書かないといけない部分も多々あります
SPA みたいな規模が大きいものでもなく ちょっとしたページなら DOM API だけ使って書いたほうが短く書けます

とは言っても WebComponents にしてしまうとクラス定義とかでてきて書く量が増えます
コンポーネントに分割できて考えやすい部分はありますが 短く書くのには向いてません
昔ながらの querySelector とプロパティの更新が基本になります

そうなると思うのが querySelector とか textContent とか長いのですよね
コードが長めのものだと $ に document.querySelector を割り当てたりしてますが その処理自体を書くことになります

その結果ライブラリの中身を気にせず自分のコードだけを小さくしたいなら jQuery が一番短くかけるのですよね
$ や text や html など DOM API だと長いプロパティ名やメソッド名を短くしていて メソッドチェーン化することで代入や呼び出しの対象を毎回書かなくて済むようにされています

もうほぼ使うこともないと思いましたが 1 つの HTML ファイルに全てまとめた上でファイルサイズをできる限り小さくしたいという状況だと役立ちました
CSS Modules で別モジュールのクラスを使いたい
便利だけど別のモジュールのクラスを使えない
例えばこういう CSS

.readonly .edit {
display: none;
}

.edit がこのモジュールのクラスで .readonly はモジュールの外で指定される場合
別クラスの .readonly であることを書くすべがないので実現できない

使用例

<user-list class="readonly">
<user-item>
<div>namae</div>
<div>
<button class="edit"></button>
</div>
</user-item>
<user-item>...</user-item>
<user-item>...</user-item>
<user-item>...</user-item>
</user-list>

user-list に .readonly をつけたら中の user-item 全部で .edit を消したい

stackoverflow とか調べてみると 親のクラスを使わずそのコンポーネントにクラスを指定すべきというのが出てくる
この例で言うと全部の user-item に .readonly つける
ムダが多くて気がすすまないけどコンポーネント的には自分自身にオプションが設定されてるのが正しいのだとか
わかるといえばわかるけどやりたくない
WebComponents 自体 :host-context() でホストより外側のセレクタ使えるし

readonly が user-list より上の page-user みたいな要素についてる場合も許可するのなら いっそ モジュールで一意なクラスに変換しないのもあり
:global を使ってクラスにするか CSS Modules の変換対処外の属性を使ったセレクタにするか ([data-readonly] みたいなの)
readonly みたいなのだと良さそうだけどものによっては別の意味のセレクタが意図せず重複もありそう

親が子を把握してるのなら user-list が user-item の CSS をインポートして親側に子のセレクタをつけるのもあり
ただやりすぎるとすごく複雑になってきそうだし 別コンポーネント用の CSS Modules を使うのは控えめのほうがいいかも
Parcel で CSS Modules だけ設定が違う理由
深く考えてなかったけど Parcel で CSS Modules だけプラグイン設定方法が他と違ってる

{
"modules": true,
"plugins": {
"autoprefixer": {
"grid": true
}
}
}

https://parceljs.org/css.html

ドキュメントだとオブジェクトをエクスポートするので特別な対応が必要と書いてる

モジュールを有効にして以下のコードをバンドルする

.foo{}
.bar{}
import styles from "./test.css"
console.log(styles)
parcel build --no-minify index.js
結果は
/*略*/
})({"qP9o":[function(require,module,exports) {
module.exports = {
"foo": "_foo_05711",
"bar": "_bar_05711"
};
},{}],"Focm":[function(require,module,exports) {
"use strict";

var _test = _interopRequireDefault(require("./test.css"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

console.log(_test.default);
},{"./test.css":"qP9o"}]},{},["Focm"], null)
//# sourceMappingURL=/index.js.map

クラス名のオブジェクトがエクスポートされてる

モジュールが無効だとこう
/* 略 */
})({"qP9o":[function(require,module,exports) {

},{}],"Focm":[function(require,module,exports) {
/* 略 */

処理は何もなし
エクスポート内容が無いときも空オブジェクトで常にエクスポートがあるなら共通でも良さそうだけど モジュールがあるときだけ追加の処理でエクスポートしてそう
Parcel 内部でその判断するためにフラグ形式でモジュールを使うかどうか判断必要みたい

エクスポートの必要性
モジュール使わないときは出力される CSS はそのままのクラス名
JavaScript 側での処理はいらずに HTML や JavaScript では CSS ファイルに書いたままのクラス名を書くだけ
モジュール使うときは一意な名前に変換されてる
その変換後の名前を知るために JavaScript では CSS をインポートして元のクラス名から変換後のクラス名を取得して DOM に設定する
systemctl status が less で開かれる
久々に systemctl status でデーモンの状態を見たら less で開かれるようになってました
これまでは普通に status のテキストが出力されていましたが less で status のテキスト部分だけが開かれた挙動になってました

less なので検索できたり 画面右端ではみ出た部分も右にスクロールさせて読めます
これまでは詳細みるなら -l (?) みたいなオプションを追加してとか言われて面倒だったのが不要になったようです
ただ一々画面が切り替わったり 上の方にスクロールしてログとしてあとから確認できないなどのデメリットもあります

変わったのは fedora を 31 にアップデートしてからの気がします
less で見たいならパイプすればよくて 基本はこれまでのように単純に出力でいいかなと思って戻す方法がないか調べたらこんなページがありました

https://unix.stackexchange.com/questions/343168/can-i-prevent-service-foo-status-from-paging-its-output-through-less

--no-pager オプションを使えばいいようです
未使用 CSS を削除するツール
たまにネットで見かけますが 個人的にはあまり信用してません
必要なところまで消されそうな気がして仕方ないです

CSS はクラスや属性名で指定できますが それらは静的なものとは限らないです
JavaScript から作られるものも多くあるわけですが 文字列結合など色々処理した結果できあがる文字列の場合もあります
不要部分を削除してしまうわけですから 多分使われてなさそう 程度で消すと動かなくなって重大な問題です

静的な解析だと限界がありますし 実際に動かして使われたかを判別する機能は Chrome の devtools についてます
ただそれも 実際にそのスタイルが使用される状態になる必要があります
一通りの操作はしてみても 特別な状態の組み合わせでしか起きないスタイルの指定があるかもしれません
すべての状態の組み合わせで試すなんて規模が大きいと無理がありますし CSS や HTML の書き方や JavaScript でクラスの指定など何らかのルールに従って書いてる前提でもないと確実にないって言い切るのはかなり難しいと思います

ただ 実際に使う操作を試して使っていないスタイルなら 特別な組み合わせでのみ使用されるケースがあってもとりあえず削除してもいいのかもしれません

作った側は使うと確実にバグが発生するのを認識していて 修正依頼が来たら修正する準備はできているのに 誰も使わない機能なせいで数年前からその状態のままという話を聞いたことがあります
業務で使うようなシステムになるとユーザ数も限られて割とあるのだとか
それに似た話で テストをするのが作った側ではなく 使う側がやることで 機能上できはするものの実際には使われないような使い方はバグがあっても気づかれず放置で 逆によく使う使い方は丁寧にチェックされるというやり方をしてるところもあるようです
誰も使わない機能や使い方でのバグを直しても時間の無駄ですし 使う側としては使う機能だけちゃんと動いてくれればいいですからね
バグが絶対許されない環境でもないならそれくらいのゆるさのほうが効率も良くていいのかもしれません
HTTPS は強要するものじゃなくて住み分けるものです
こんな記事が
https://www.itmedia.co.jp/news/articles/2002/20/news059.html

必要以上に HTTPS を強要してくる最近の風潮はホント迷惑ですよね
まぁこの場合は Teams はログイン必要なサービスでプライベートな情報を保存するので HTTPS が必須なサービスなわけで Google が HTTPS HTTPS 言ってなくても起きた問題ですけど

Microsoft くらいでもミスがあるようなものですし めんどくさく大変なものです
セキュリティはめんどくさくなるようするものだとかいう話もあるくらいですし

本当に HTTPS が必要なサービスは HTTPS を使うべきですけど必要ないところまで HTTPS 化させようという仕組みが多いです
Google のランキングに影響だとか JavaScript で使える機能が制限だとか HTTPS を必要以上に優遇して HTTP の使いづらくしてます
HTTP で十分なものまで HTTPS にしようとしてるのが気に入らないです
余計なものがなくてシンプルなテキストの HTTP だからこそいい部分も多いはずです

HTTPS だと証明書も必要ですし ウェブサーバを立てる難易度が上がって個人レベルで立てづらくなります
静的ファイルをホストするだけなら無料サービスも多いですが サーバサイドもとなると無料はほとんどないですし
SNS みたいなところにまとまるよりは 自由な個人サイトみたいなのが多いほうが好きなので 気軽にサーバを立てづらくなるようなものはやめてほしいものです
async 対応なコレクションメソッドがほしい
map は普通に map に渡す関数を async にしたら Promise の配列になるので Promise.all するだけ

const items = [10, 20, 30]
const asyncDiv5 = num => new Promise(resolve => setTimeout(resolve, 100, num / 5))

await Promise.all(items.map(asyncDiv5))
// [2, 4, 6]

reduce も返り値が Promise でも次の関数に渡されるのが Promise なだけだから次の関数が前回の値を await して使えばいい

const values = [1, 2, 3, 4]
const getValue = x => Promise.resolve(x * 10)

await values.reduce(async (a, b) => (await a) + (await getValue(b)), 0)
// 100

問題は渡した関数の返り値の値をコレクションメソッド内部で扱う場合
これらは Promise に対応してないので Promise を解決せずそのまま Promise 自体を結果として扱う
なので filter の場合だと Promise オブジェクトはオブジェクトなので true になって全部が残るし find でも最初のが絶対マッチする

console.log([1, 2].filter(async x => false))
// [1, 2]

console.log([1, 2].find(async x => false))
// 1

filter に対応するならこういう一度 Promise の中身を取り出す処理が必要になる

const filter = async (arr, fn) => {
const filter_flags = await Promise.all(items.map(fn))
return arr.filter((_, i) => filter_flags[i])
}

この処理を毎回直接書くのは避けたいくらいので filter 関数を自作することになる
標準で用意してくれればいいのに

const items = [0, 1, 2, 3, 4]
const fn = x => {
if(x === 0) return false
if(x === 1) return true
if(x === 2) return new Promise(r => setTimeout(r, 1000, true))
if(x === 3) return Promise.resolve(false)
if(x === 4) return Promise.resolve(true)
}

await filter(items, fn)
// [1, 2, 4]
Twitter のツイート数取得
ニュース系サイトで Twitter でのツイート数が表示されてるのを見かけました
ツイート数ってどうやってとれるんだろう?と思ったのでソースを見てみたら JavaScript で取得していました
Twitter の API かなと思ったら https://jsoon.digitiminimi.com/ のサイトでした

見てみたらツイート数を取得するサービスをやってるようです
わざわざこういうのを使ってるあたり Twitter 自体にはツイート数取得の機能はなさそうですね
Safari は回転制御できない
こんな機能見つけました
https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation/lock

モバイル端末の回転を制御できるようです
ゲームなど一部のアプリだと縦長か横長どっちかの表示のみだったりします
でも Web だとそれができなくて不便です
viewport 固定で横長専用とかしたいのですけど

それがこれをつかえばできる!と思ってました
でも Safari (iOS) は非対応でした
モバイル端末考えると iOS シェアは多いですし Android だけできてもなぁという気分です

これに限らず Safari って独自の使用があったり変な動きしたりと扱いづらいです
新機能の実装も Firefox のほうが早いことが多くて全部で動くものとなると Safari がネックになってることも多いです

Win7 のサポートが終わって IE 対応がほぼなくなると Safari が第二の IE になるようにしか思えません……
一番の問題は iOS で Chrome など別のブラウザ入れてもエンジンは Safari の Webkit 固定なんですよね
Go → Rust てよくみるよね
Discord も Go → Rust に切り替えたらしいです

https://blog.discordapp.com/why-discord-is-switching-from-go-to-rust-a190bbca2b1f

けっこうこの移行よくみかけますね
最近だとネイティブにビルドできるメジャーなものといえばだいたいこの 2 つだからかな

C/C++ は複雑で避けられがちですし D はまだ生きてたのって感じですし
.NET 系は Core は Linux などで動くとはいってもネイティブとはちょっと違いますし
同じく Java 系も

個人的には Go は興味なくて Rust は興味あるので Rust に移行するプロダクトが多いのは嬉しいことです

そういえば deno も当初は Go で実装していて どうして Rust にしないの? みたいなこと言われて Rust にしたんでしたっけ
そんな deno も予定では 2 月末に 1.0 でるらしいです
完全 Web 互換らしいのでリリースしたら使ってみようかと期待してます
ツリー構造の要素をひとつずつ返してくれるジェネレータ
function* treeIter(root) {
yield root
for(const child of root.children || []) {
yield* treeIter(child)
}
}
const tree = {
name: "root",
children: [
{
name: "item1",
children: [
{
name: "11",
children: [
{
name: "111",
children: [],
}
],
},
{
name: "12",
children: [],
},
{
name: "13",
children: [],
}
],
},
{
name: "item2",
children: [
{
name: "21",
children: [],
}
],
},
],
}

Array.from(treeIter(tree), x => x.name)
// ["root", "item1", "11", "111", "12", "13", "item2", "21"]

JavaScript でタプル
必要性はともかく変更不可版 Array ということでこれでよさそう
中身同じでも等しいものにならないのが不便かも

class Tuple extends Array {
constructor(...a) {
super()
this.push(...a)
Object.freeze(this)
}
}

作ったタプルをすべて保存しておいて同じ中身なら既存のを返せばできそうだけどメモリ的につらそう
WeakSet を forEach できたらいいのに
JSON 比較
JSON を比較したいとき文字列比較だと オブジェクトの順番の違いでも違うもの扱いされる
オブジェクトや配列を再帰的にチェックしていくのは面倒
片方のプロパティ全部をもう片方と全部比較しても もう片方のほうにしか無いプロパティもあったり 考慮することが意外とあってコードも長くなる

短く書きたかったので オブジェクトは Object.entries の形式化してソートするだけ
比較は JSON.stringify した文字列比較に任せる方針なもの作ってみた

const rec = v =>
(v instanceof Object && !Array.isArray(v)) ?
Object.entries(v).map(x => [x[0], rec(x[1])]).sort((a, b) => a[0].localeCompare(b[0]))
:
v

const jsonDiff = (a, b) =>
JSON.stringify(rec(a)) === JSON.stringify(rec(b))

jsonDiff({a: 1, b: 2}, {b: 2, a: 1})
// true

JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1})
// false

JSON を比較するくらい標準機能にあってもいいと思うのに
SQL で列名が被って困る
SQL の列名は同じ種類の ID なら同じ名前にしておけば USING(xx_id) で JOIN できたり便利なので 列名を一意にしようなんて思ったことはありませんでした

しかし 「SELECT * FROM ~」 のように全取得してると LEFT JOIN で JOIN 先にマッチする行がないと id が null になってしまう問題に困りました
同じ列名なのでオブジェクトや連想配列やディクショナリとして取得するとあとの方の null で上書きされてしまうのですよね
「*」 を使わず全部書けば解決ですが 長いです
ワイルドカードで除外が選べれば助かるケースはかなりあるのですが SQL では対応してません
それに SQL って全然更新されないので JavaScript などのように待てば便利なる期待もありません
せめて 「select a.* as a__*」 で a__ プレフィックスつけてくれるみたいなのができたらよかったのですけど

それで思ったのが最初から列名を 「tablename__columnname」 みたいなのにしておくことです
見た目はいまいちですが JOIN が入ってくると列名が被る可能性があって 結局 WHERE や SELECT で 「tablename.columnname」 のようにテーブル名も含めて書くならあんまり変わりません
とはいえやっぱり長いし 実際に 「tablename.columnname」 と書くときはエイリアス使って 1, 2 文字のテーブル名です
なのでエイリアスを含めた 「tablealias__columnname」 にしておくのはありな気がしました
列名指定のためのエイリアスが不要になりますし

CREATE TABLE foo (
f__id integer,
f__name text,
PRIMARY KEY (f__id)
);
CREATE TABLE bar (
b__id integer,
b__name text,
b__f_id integer,
PRIMARY KEY (b__id)
);

SELECT * FROM foo LEFT JOIN bar ON f__id = b__f_id WHERE f__id < 10;
JavaScript int max
// signed int32 max
-1 >>> 1
// 2147483647

// unsigned int32 max
-1 >>> 0
// 4294967295

// number max
Number.MAX_SAFE_INTEGER
// 9007199254740991
サーバ使えない環境で proxy
長いクエリがある URL に短縮 URL を作って リダイレクトせず短縮 URL のまま表示する
サーバサイドも使えれば長い URL のページへ proxy するだけで済むので単純
静的ファイルのみしか使えない場合はどうしようかと考えたら全画面 iframe 使うだけだった

<!doctype html>

<style>
body { margin: 0; }
iframe {
display: block;
width: 100vw;
height: 100vh;
border: 0;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
<iframe src="page.html"></iframe>

src の page.html のところに長い URL を設定する
iframe だけのページを iframe の URL 変えながらたくさん作るのも面倒なのでマッピングのデータの json をロードして今のページに対する長い URL を動的に作るほうがいいかも
ページ数分の大きめな json を毎回ロードすることになるけど キャッシュされればそこまで困るほどでもなさそう

JSONP ふうに iframe への設定も含めとくとか

!function(values) {
document.querySelector("iframe").src = values[location.pathname]
}({
"/azj4": "/foo/bar.html?longlonglong=query",
"/bj9c": "/long-url.html",
// ...
// ....
})