6 ポイント 投稿者 GN⁺ 2023-11-07 | 1件のコメント | WhatsAppで共有
  • 本文では、バニラJavaScriptを使った Document Object Model(DOM)操作の習得について論じています。
  • Angular、VueJS、React、Solid、Svelte といった現代的なツールを使う場合でも、Web開発のためにブラウザの DOM API を理解する重要性を強調しています。
  • 著者は、基本的なブラウザ API、わかりやすい例、リアルタイムデモ、ヒントとベストプラクティス、実際のユースケース、そして最新ブラウザおよび Internet Explorer との互換性を含む資料集を提供しています。
  • これらの資料は、初級・中級・上級の3つのレベルに分かれています。
  • 初級レベルには、ユーザーのカラースキーム設定に応じてファビコンを動的に変更すること、Webページの読了時間を計算すること、CSS のルート変数を動的に更新することなどが含まれます。
  • 中級レベルには、Shift+Tab キー操作でテキストエリアのインデントを解除すること、全画面モードに入ること、スピン入力を構築することなどが含まれます。
  • 上級レベルには、カスタムカーソルを作成すること、HTML 文字列をサニタイズすること、カスタムスクロールバーを作成することなどが含まれます。
  • 著者は、モーダルを開くときにレイアウトがずれるのを防ぐことや、テキストノードの境界矩形を取得することなどのヒントも提供しています。
  • 本文は、フロントエンド技術コンテンツに関する著者のニュースレター購読への案内で締めくくられています。

1件のコメント

 
GN⁺ 2023-11-07
Hacker Newsのコメント
  • 例の一覧が素晴らしく、いくつか目を通しただけでも細やかさとディテールに驚かされる
    Reactのようなプラットフォームから、より小さくミニマルな実装へ移ろうとすると、標準JSで複雑なパターンをどう扱うかでしばしば行き詰まるが、実際にコードを見ると「巨大なライブラリに大量のプロパティを渡すよりずっと簡単だな」と思うことがある

    • RiotJSのメジャーアップデートを3〜4回経験したあと、似たような悟りに至った
      ミニマルなJSフレームワークでも、一見素朴な機能要望が積み重なると、結局はフック、イベント、副作用の継ぎはぎの怪物になりがちだ
      最近はjQueryも使わず、ESモジュールのようなものはコード整理に使うが、わざわざnpmコマンドを実行する必要はない。これはベンダーから取り込む類いのものではなく、グローバルなブラウザ標準だ
      今ではMDNを聖書のように読んでいる。信じて従えばほぼ最後まで導いてくれるし、フレームワークはある地点からむしろ足かせになる。5年前はここまでではなかったが、ブラウザAPIはモジュール、flexbox、gridのような強力で一貫した基本要素へ急速に収束した
    • 元記事の例は、Webクライアントフレームワークと競合する性格のものではない。フレームワークが解決する一般的な問題は状態管理と、状態変化時のUI更新だ
      たとえば元記事の例の大半は、Reactを使っていても結局自分で書くことになるコードに近い
  • サイドプロジェクトとして、まだ名前のない「Webデザイナーのためのvim」のようなものを作っている。Webflowのようにブラウザ上でWebサイトやコンポーネントを作るが、すべてコマンド言語で動く仕組みだ
    最初はフレームワークなしでやると決めていた。2009年からこの仕事をしていて、フレームワークに触る前から長くJSを使ってきたので、ネイティブDOM APIで十分だと思っていた
    ところがDOMの内外でデータをやり取りする作業があまりに退屈でミスも多く、精神衛生のために結局ミニフレームワークを自作して使い始めた。そこでようやく、そもそもフレームワークを使い始めた理由を思い出した。結局は何らかの形でフレームワークを使うことになり、違いはそれが自作の特注品か、コミュニティ製の業界標準かだけだ
    インタラクションの少ないサイトならネイティブDOMでもよく、Reactを使っているサイトの大半は実際には不要かもしれない。だが製品に少しでもニュアンスや複雑さがあるなら、フレームワークを使って面倒を避けたい。最終的にSvelteへ移行し、ずっと満足している

    • 超ミニマルなプロジェクトは、結局jqueryやlodashの半分を再実装することになる。ツリーシェイキングがよく効くramdaのような良いライブラリを見つけて節度を持って使うほうが、ずっと楽だ
    • 「フレームワークを選ばなければ、自分で作ることになる」という言葉はまさにその通りだ
    • これはアプリケーションを作るケースなので、説明だけでもDOMインタラクションをラップしたほうがよいと推測できる
      インタラクションが必要なWebサイトなら、DOM操作のほうがより根本的で汎用的な技術を使え、ビルド工程が軽いか不要で、実行も速く、明示的だという点でより良い選択になりうる
      もちろんグレーゾーンは多いが、この事例はフレームワークの利点が出る範疇にきれいに収まっている
    • 最近のSvelteKitはSSR中心で、Svelte自体には標準のクライアントサイドルーターがない。CSRのシングルページアプリにSvelteを使おうとして断念した
  • value.startsWith('javascript:')だけでは脆弱性が生じる。URLの前に任意の空白が入る可能性があるので、少なくともvalue.trim().startsWith('javascript:')が必要だ
    それでもブロックリストより許可リストのほうがよいと思う。http:, https:、必要ならmailto:, ftp:, sftp:程度だけを許可し、/で始まる相対URLは場合によって許可できるかもしれない
    ただし実際にURLになりうるすべての属性を正確に扱う必要があるため、結局はいくつかのタグとその属性だけを許可する方式のほうがよさそうだ

    • 非常に古いブラウザをサポートする必要がないなら [1]、URLの解析はブラウザに任せる簡単な方法がよい。たとえば ['http:', 'https:', 'mailto:', 'tel:'].includes(new URL(value, location.origin).protocol) のように処理できる
      [1] https://caniuse.com/url
    • ここで言っているのは、この記事の「Sanitize HTML strings」のことだと思う: https://phuoc.ng/collection/html-dom/sanitize-html-strings/
      この記事はHTMLサニタイズがそんなに簡単だという印象を与えるべきではない。末尾で https://github.com/cure53/DOMPurify に触れてはいるが、こういうものを自分で書こうとすべきではないともっと強く言い、DOMPurifyだけを勧めるほうが適切だと思う
      この件でissueを立てた: https://github.com/phuocng/html-dom/issues/281
  • 知っておくと便利な一覧のようで、全部は見ていないが今のところはよさそうだ
    最初の例を開いてみると、window.matchMedia('(prefers-color-scheme: dark)')を不要に2回実行している
    setFaviconをイベントリスナーのコールバックに使うなら、コールバックに渡されるevent引数のevent.matchesを使えばよい
    個人的にはHTMLで処理するほうがよい。JSを無効にしているユーザーにも対応できるからだ
    https://phuoc.ng/collection/html-dom/change-the-favicon-dyna...

    • HTMLで処理すれば、別テーマのコンテンツが一瞬ちらつく現象も防げる。theme-colorメタにも同じ方法を適用でき、ディテールにこだわるPWA開発者にはあまり使われていないが優れた機能だ
  • 「textareaの自動拡張」手法は、新しいCSSプロパティ form-sizing の登場によって古くなりつつある。
    https://chriscoyier.net/2023/09/29/css-solves-auto-expanding...
    この新しいCSSプロパティを使わないとしても、要素の height を調整する方式は理想的ではなく、ぎこちなくなることがある。
    より良いアプローチは、隠しミラー要素を使うこと。
    https://css-tricks.com/the-cleanest-trick-for-autogrowing-te...

  • ここにあるもののかなり多くは、より良いネイティブAPIがあるのに、古くてぎこちないAPIを使っている。
    たとえば「要素の置き換え」は ele.parentNode.replaceChild(newEle, ele); になっているが、Chrome 54未満、Firefox 49未満、Safari 10未満を対象にしないなら、単に ele.replaceWith(newEle) を使えばよい。
    replaceWith は、1つのノードを複数のノードやテキストに置き換えることもできる。
    同様に「NodeListの走査」も、配列に展開してから forEach を使えと言っているが、単に for (let ele of nodelist) ... でよい。

    • NodeList が live なオブジェクトである場合がある点は覚えておくべき。走査中にそのリストを操作すると、予想外の結果になることがある
  • いいね。ブックマークした。似た方向性の良い資料として https://youmightnotneedjquery.com/ もある。
    Web作業を頻繁にするわけではないが、やるたびにあちらの フレームワーク過剰症 には完全にやる気を削がれる。新しいReactプロジェクトが依存関係数百個で始まるのは制御不能だし、その複雑さの重さには驚かされる。
    一方で、標準搭載のクロスプラットフォームなブラウザ技術はこれまでになく強力で、よくある作業をこなすコード量もそれほど多くない。
    フロントエンド開発者たち、大丈夫か?

    • Reactやnpmはまったく好きではないが、一部のフレームワークには純粋なDOM APIが提供しない有用なものがあるので、今でも居場所はあると思う。
      たとえば アプリケーション状態管理 やルーティングは、純粋なDOM APIだけを使うなら自前で実装しなければならない大きな部分だ。
      アプリの複雑さ次第では大したことではないかもしれないが、基本的なアプリを超えた瞬間に、こうした追加機能の価値は急速に高まる。ただしnpmが必要なものを使っているなら面倒になる。
    • 同じ系統のもう1つの素晴らしい資料として、すばらしい https://javascript.info/ がある。
      基本プラットフォームとその機能を愛するフロントエンド開発者として、ネストされたCSS、コンテナクエリ、ES6以降の全体的に改善されたJS体験のような良いものが来ているのはうれしい。
      同時に、ボタンや太字のような些細なものにまでコンポーネントを使う人が多すぎるのには驚きもする。
      フレームワーク自体は好きだが、多くのフレームワークやライブラリのマーケティングは、CSSや素のDOM操作が狂ったように難しく、NPMから適当なパッケージを引っ張ってくることが速くて簡単なだけでなく、プロフェッショナルなやり方だという信念に依存している。
    • 制御不能になっているという点には同意する。ただ、この1年でプラットフォームチームに移って初めてDevOps系のツールを扱い始めたのだが、その複雑さもフロントエンドに劣らない。
      Kubernetes, Helm, Terraform, CircleCI のようなものを見るだけでも、何層にも積み重なった用語の量がばかげている。
    • 「強力なクロスプラットフォーム技術」で、些細ではないことを実際にやったことがあるのか気になる。あと、選択肢はReactだけではない
  • 複数のDOM関数が、自動的に更新される live HTMLCollection を返すと知ったときは本当に驚いた。
    フレームワーク流行以前、あるいは再びフレームワークなしで開発する流れが少し人気を得る前後で、この機能が実運用コードでどれほど積極的に使われていたのか気になる。

  • 古いものが再び新しくなる。最初のフロントエンドの仕事は、1999年にWebアプリケーションを作ることだった。
    ツリービューのドラッグ&ドロップ、クリックして編集、事実上のシングルページアプリのような凝った機能まで、全部「Vanilla」JSで作った。
    最も難しかったのは、NetscapeとInternet Explorer の違いをすり合わせることだった。

    • 状態とその変更はどう管理していたのか気になる。
      なぜ今ではそういうことのやり方を知らないように見えるのだろう ;]
  • 最近いちばん気に入っている素のJavaScript機能は、Chrome 1.0やIEの時代からあった Element.insertAdjacentHTML だ。
    とくにバックティックを使う複数行文字列と組み合わせると、有用というだけでは足りない。こんなに昔からあったのに、1年ほど前まで知らなかったのが信じられない。
    insertAdjacentHTML(position, text) は、指定されたテキストをHTMLまたはXMLとしてパースし、結果のノードをDOMツリーの指定位置に挿入する。
    もともとのDOMだけでやるなら、li 要素を作り、a 要素を作り、子として追加し、href 属性を設定し、テキスト値を入れてから ul に挿入しなければならなかった。あるいは大きな文字列にまとめて innerHTML で入れるしかなく、既存のリストを変更するのはさらに面倒で冗長だった。

    1. https://developer.mozilla.org/en-US/docs/Web/API/Element/ins...