Open22
JSConf JP 2023 ノート
興味のあったセッションのノート
Deep dive into Biome
- https://youtu.be/N1lhkH33fwY?t=1407
- Biomeのコアコントリビューターの方
- 現在はリンター・フォーマッターに注力しているが、目標としてはWeb開発全体のツールチェインを目指す
- NodeJSの開発に取り組む議論がある
- 特徴
- 速い TypeScriptソースコードのフォーマットが1秒以下
- ゼロコンフィグ
- エラーレジリエンス
- パースに失敗しても解析が止まらない
- 仕組み
- コードをパースしてGreen TreeとRed Treeに分ける(ASTとは別のもの)
- Green Tree -> Red Tree -> Biome独自AST
- 必要なフィールドがないことを示すmissing field、invalidな部分に対応するノードbogus nodeを持つ
- Red-Green Tree (lossless syntax tree = 構文技から元のコードを復元可能)
- Green Treeはかなり具体的な情報を持つ(スペースやコメント)
- Biomeはrust-analyzerでも使われているライブラリRowanをフォーク
- パーサなどもフルスクラッチに実装しているので大変そう
- Q. 早くするための工夫はありますか?
- Rustでマルチスレッドベースで処理をしている
- 省メモリをに力を入れている
- Q. Biome カスタムルール対応ありますか?
- 元々ない考えだが、導入も検討していてロードマップ作成中
- あるとしたらWASMベース
-
oxcとは協力していきたい
- LintのカスタムルールがGraphQLベースな仕組み
Build and Publish 2023
- https://youtu.be/N1lhkH33fwY?t=6759
- JavaScriptのツールチェインとの向き合い方
- ビルドとは
- Transpile
- Bundle
- Minify
- ES Modules (2015)
- 仕様ではシンボル解決のみきまっていて、インポート先のロード方法は実行環境依存
- ESMの問題:RTT
- Chromeチームの調査(2017)ではモジュール>100or深さ>5ならバンドルしたほうが速いという結論
- 2023時点にある仕様を組み合わせても完全には解決できない(ビルドが必要)
- Browser/Deno/Nodeで同じ書き方ができる土壌はできていきている
- TC39 Proposal Module Dclaration (stage2)
- 現在はファイル単位でしたモジュールを分けられないが、1ファイル内でモジュールを分けられるようにする仕様
- 進んでないので実現可能性は低い
- あるとバンドラーに優しい
- TSにある構文なのでぶつかる
- Toolchains
- まとめ:
- パフォーマンスが向上してきている
- ゼロコンフィグ
- Viteの伸び
- Webpack互換のTurbopack
- Rspack
- Closure Compiler
- Javaレベルで厳密な型アノテーションが必要なため運用が難しかった
- broserify
- commonjs形式でnpmパッケージが導入できるようになったのが革命的だった
- webpack
- バンドル+チャンク分割
- JavaScript以外のファイル
- 設定によって挙動が完全に異なる(世の中にプラクティスがなかったのでデフォルトが作れなかった)
- Roolup
- TreeShake
- Vite
- ゼロコンフィグ
- 開発と運用でビルド結果が違うので際が問題
- その対応のRolldown
- まとめ:
- SSR Frameworks
- SSR/RSC クライアント・サーバーで得意なところに向けてチャンクを分割する技術
- 今後のビルドツールチェイン
- NextJS以外のフレームワークがRSCを導入するときにどのような形になるか
- React以外もServer Component概念を導入しようとしている
フロントエンドリアーキテクチャリングと開発チームのスキルトランスファーにおける9ヶ月間の奮闘記
- https://youtu.be/N1lhkH33fwY?t=8795
- フロントエンドEnabling活動事例
- Rails主軸となっていた古いプロジェクトで大きめの改修が控えているプロジェクトのフロントエンドモダナイズ化をしたときにどのように支援を行っていったかの話し
- 技術支援に徹する
- ツール・ライブラリ選定の助言
- フロントエンドアーキテクチャ提案
- コーディングマニュアル・レビュー・ペアプロ・サンプルコード
- 多くの知見を一度に取り入れると手に負えなくなる。段階的に。
- 基本技術で開発をして、課題が噴出したときにライブラリ導入を考える
- 比喩を使って説明する
- 開発効率を「下げない」
- ドキュメントの充実化
- テンプレートを用意しておくのが良い
- 意思決定をドキュメントに残す
- コンテキストが理解できていない開発者の加入で問題が発生する
- 「好き」とまではなくても「面白い」と思ってもらえるように
- 技術検証を気軽にできる環境(それようのgitレポジトリなど)を作るとよい
- Q. ドキュメントの書き方のばらつき
- コードレビューにドキュメントを書くことを含めるとそれは掟のようなものに
- よいドキュメントはすぐに描けるようになるものではない、長期的には勉強会などを開催する
LLM全盛時代の開発プラクティス
- https://youtu.be/pdgB0Y5ZQGk?t=1680
- GitHub Copilotを使った開発について
- 開いているタブを元にサジェスト
- 実装に「統一感」がないとCopilotもそれに影響される
- 外在性認知負荷
- 統一感を出すためにコードを変えなくてもコメントで補う工夫ができる
- 開発者のコンテキストを理解してサポートしてくれるAIツールはまだなさそう
- AIにコンテキストを伝える
- AIは業務のコンテキストを全く持たない優秀な新人と考える
- AIレビューをする場合は、AIレビューワークフローを言語化する
Micro frontends in Action! 🦏
- https://youtu.be/pdgB0Y5ZQGk?t=7042
- バックエンドはマイクロサービスしたけどフロントエンドはモノリス
- なぜマイクロフロントエンドか?
- 機能ごとのアップグレード・デプロイができる
- 再利用性
- コードベースがシンプルに
- 分割する単位をどう考えるか
- DDD
- ビジネスの領域とそろえることができる
- コンテキストが共有されている
- DDD
- Module Federation
- モジュールをランタイムで読み込む
- 依存モジュールは共有できる
- ランタイム読み込みなので、再デプロイが必要ない
- Native Module Federation
- バンドラーに依存しないModule Federationの仕組み
TypeScriptで型定義を信頼しすぎず「信頼境界線」を設置した話
- https://youtu.be/pdgB0Y5ZQGk?t=9046
- TypeScriptの型はどこまで信頼できるか
- ソフトウェアが壊れるリスクを減らすために値の信頼性が必要
- 型がっていても想定していない値が来る可能性はある
- 値の検証と頻度の場所
- すべてのAPIで値の検証を行っていない場合、値の検証を行っているところでエラーが発生するので誤った値を初めて受け取った場所(バグの発生場所)と原因の場所が違う
- 値のチェックを全ての層で行うのは、ロジックの重複(関数かしても)でコードメンテナビリティが低下する
- バランスが必要
- 明確な境界線を決めないと混乱が生じる
- テストケースは信頼できない部分の値の検証の部分を重点的に
- 信頼できる部分は逆にそのようなテストを増やさない
- 信頼境界は観測・改善を継続する
Building Text Containers in Canvas
- https://youtu.be/pdgB0Y5ZQGk?t=11283
- Excalidrawコアチームの方
- テキストコンテナー
- コンテナーの内側をユーザがクリックしてテキストを入力する
- 外側からドラッグして内側で離しすと内側でクリックイベントが発火した判定になってしまう
- ドラッグ開始地点と終了地点の距離が一定以下の場合だけコンテナ内であると判定している
- A way to link test with its container
- テキストとコンテナーは1対1
- コンテナーIDをテキストの情報に含めている
- コンテナー側にもテキストIDを含めてテキストを持っているか持っていないかを区別している
- The Text should always stay inside Container Bounding Box
- キャンバスは複数行テキストをサポートしていないの自力実装が必要
- DOM measurementsとCanvas measurements
- DOM measurementsはCanvas measurementsより90%近く遅い
- NodeJS環境でも動く(?)
- 長い単語の折り返し情報はJSON上で管理している
- 長い単語の折り返し情報をキャッシュしている
Mastering Cryptography Fundamentals with Node's crypto module
- https://youtu.be/pdgB0Y5ZQGk?t=13489
- getCiphers
- IV
- 平文が同じものを暗号化したとき同じ暗号文になるほを防ぐ
- KDF
- 記憶可能なパスワードから推測不可能な鍵を作成する
- 攻撃者の試行に時間がかかるように、意図的に遅くなるように実装されている
- KDFは決定的な関数。試行を難しくするためにパスワード+Saltを入力とする
- Randomness
- ❌ Math.random
- Key Distribution Problem
- 公開鍵暗号
- パディングの方式は複数ある
Hono v3 and v4
- https://youtu.be/pdgB0Y5ZQGk?t=16019
- Hono
- はじめの方はcdnjsで使われ始めた
- V3
- バリデータが薄く時前から zod/valibot/typebox等
- 型付きクライアント
- ルーターが3種類から5種類に
- どのルータを使うべきか
- 登録が何回も動くものは登録の速いHono/quick
- app.mount()
- Webフレームワークとランタイムの組み合わせごとにアダプターがあったが、Honoを経由するとHonoが各ランタイムで動くためいらなくなる
- Secure Headers Middleware - Hono
- Helpers - Hono
- OpenAPI対応
- バリデータとレスポンスの型を定義して、Honoのアプリケーションを作るだけ
- ストリーム対応
- AI系のサービスのレスポンスはストリームとアイ傷害よい
- Suspence
- Node.jsとWeb standardsの変換最適化
- Node.jsだと遅かった
- V4
- File-based routing
ゲーム「webページ崩し」の仕組み〜あなたの知らないDOMスクリプティングの世界〜
- https://youtu.be/pdgB0Y5ZQGk?t=18022
- DOM処理エッジケースがとても多い
- webページ崩しの処理の流れ
-
- Freeze page
- clearTimeoutでtimout ID候補を片っ端から消す
- Get all elements
- iframe, shadow rootが天敵
- 再帰的にiframe/shadow rootを探索
- playwrightでも同じようにやっている
- クロスドメインiframe
- ブラウザ拡張ではスクリプトを差し込めるのでそれをつかって対応(現状遅い
- 見えない要素とは
- checkVisivility()は一般的な用途目的のものにしか対応してない
- Block erasure
- DOMを削除すると見た目上他の要素がずれてしまう
- visibility: hidden
- DOMを削除すると見た目上他の要素がずれてしまう
- Freeze page
- DOM is CISC-like, not RISC-like
- DOMは複雑すぎる
- DOMは必要か?
- Canvas + AOM
- AOMをいじれ過ぎるとプライバシーの問題がある
Visually experience the beauty of mathematics with p5.js
- https://youtu.be/pdgB0Y5ZQGk?t=20541
- p5jsを使って数学のすばらしさを理解する
- processing -> p5.js
-
フィボナッチ数列
- フィボナッチ数列の比は黄金比に収束
-
フィボナッチ数列
Practical guide to building accessible forms in React
-
A11yがメインのテーマ
-
AOMはDOMのサブセット
-
Chrome DevtoolsでAccessibiliy Treeは確認できる
-
フォーカス
- outline: noneにしてしまうとキーボードユーザにとって使いづらい
- :focus-visible疑似クラス
-
Labeling
- inputのラベルがないと入力内容がわからない
- placeholder
- 薄いグレーで人によっては見づらい
- 多くのaccesibility toolsには無視される
- Labelタグの中にinputを入れる方法は対応していないツールがあるので明示的に結び付けるほうがよい
<label htmlFor="username"> <input type="text" name="username" id="username" /> </label>
- 画面上にラベルを表示したくない場合(検索フォーム、アイコンボタン等)は、CSSで大きさを0にするようにして見えなくする
- HTMLのセマンティクスにないコンポーネントを作りたい場合にARIAを利用する
-
aria-labelledby
で他のタグと同じaccesible名を共有できる - ARIAを間違って利用するならARIAを使わないほうがまし
- 補助的なテキストをinputと関連付けたいとき
-
useId
react側でタグにつけるIDを生成してくれる -
aria-required
-
フォームバリデーション
- サブミットボタンの無効化はツールにやさしくない
- aria-invalid
- aria-describedbyは複数指定可能
- aria-live
- フォームの要素に変更があった場合にツールに通知される
-
実際にa11yツールを使ってみること
- Macはデフォルトのスクリーンリーダーがある
Next.js App Router クライアントキャッシュの仕組み
- https://youtu.be/N1lhkH33fwY?t=10996
- Nextjs Router Cache難しい
- Pages RouterとApp Router
- フレームワークとしても別物レベル
- 4種類のキャッシュ
- キャッシュはOpt out形式
- Request Memomization
- リクエスト中に複数回発生するfetchをキャッシュ
- Data Cache
- ユーザ間で共有できるキャッシュ
- Full Route Cache
- レンダリングの結果をキャッシュ
- Router Cache
- クライアントサイド。RSCをin-memoryでキャッシュ
- App Routeはかなし積極的にキャッシュする
- <Link> prefetchプロパティでopt out
- RSCはHTTPヘッダにRSC=1が付加される
- Navigation
- Static renderingとdynamic renderingがある。基本はstatic rendering
- static rendering部分は遷移前にprefetchしcache
- dynamic rendering or prefetch無効のページは遷移時にfetch
- キャッシュのexpire時間とキャッシュの種類(3種類)でキャッシュの状態が決まる
- キャッシュの振る舞いが変わるのはこの要素に影響されるのでデバッグじにはここに注目する
- キャッシュのパージも複雑
- useReducerを使っていてRedux Devtoolsで発行されたアクションを見ることができる
- まだしばらくはPages Routerはサポートされるが、その後はわからない。
Next.js App Router でのMPAフロントエンド刷新
- https://youtu.be/N1lhkH33fwY?t=12811
- Cache
- Data CacheとFull Route Cacheの複数リクエスト横断でキャッシュが共有されるところが問題
- 要件
- 最新データの表示
- 考えること
- どこはキャッシュしてしないか
- 確実に無効化するには
- cookie()やheadersはdynamic functionsと呼ばれ、これを使っていると基本的にはキャッシュが無効化
- 個々のfetch()オプションで上書きできてしまう
- 徹底するには
- Route Segment Config dynamic="force-dynamic"
- Incremental Cache Handlerでnoopなハンドラ
- 仕組み上暗黙的にはキャッシュのキーにヘッダーも含まれるのでcookie使っていれば他の人には漏れないはず。ただundocumented
- どこで"use client"を使うか
- Storybook
- 現在Server Components未対応
- React Server Component のテストと Container / Presentation Separation | by Yosuke Kurami | Medium
- Testing
- testing-library未対応
- NextJSにExperimentalなPlaywright統合がある
- バックエンド含めた環境を立ち上げたIntegration Testがメイン
- クライアントで済むテストはなるべく逃がす
- 並列化
- Server Actions
- バックエンドで実行されるコードをクライアントから直接呼び出しているようにかける機能
- ほぼReact自体の機能
- 基本はForm
- JavaScriptから明示的に呼び出すことも(Custom Invocations)
- Server Actions使う使わないで実装方法が大きく変わる
- 現状のIssues/PRの様子からこれからメインになっていくと考えた
- Custom Invocationsのエラー
- Result型になっているがネットワークエラーなどは含まれず例外として投げられる
- エラーハンドリングコードがResultとtry/catch両方必要になり複雑化
- 成功以外は全部throwするようなwrapperを作ることでtry/catchに統一
- useFormStatus/useFormStateではProgressive Enhancementな部分を活用することができる
- バックエンドで実行されるコードをクライアントから直接呼び出しているようにかける機能
- MPAからのApp Routerの移行はメンタルモデルが近いので相性が良いと感じている
- create next appを何度も動かして挙動確認をしている
書いたJavaScriptがそのままブラウザで動く未来へ
- https://youtu.be/N1lhkH33fwY?t=15744
- https://zenn.dev/sosukesuzuki/articles/ab5377c8a99cb7
- 現代の開発ではJavaScriptを直接書くことはない
- JSXとTypeScriptなど
- JavaScriptは高級言語のはず
- 何が足りない?
- TypeScript -> JavaScript
- Type Annotation
- Stage 1 進んでいない
- JSX -> JavaScript関数呼び出し
- 提案はないが議論はある
- 進んでいない
- ダウンレベルコンパイル
- エバーグリーンブラウザが以前より使われているはず
- サービスのユーザによってはいけるか
- モジュールのバンドル
- Subresource loading with Web BundlesやBundle preloading
- 望みは薄い
- Minify
- TC39 Binary AST
- 進んでない
- そもそもバイナリ化にビルドが必要では
- 全体的に見て現状厳しい
- 書いたJavaScriptをそのままブラウザで動かす必要はない
- 以前よりビルドツール周りの環境がsustanableになっている
- ただ、Webはそのポテンシャルをもっているのでもったいないと感じている
- TypeScript -> JavaScript
Bunがメジャーリリースされたけど、本当にBunはNode.jsに取って代るほどすごいのか?をAWS Lambdaで検証してみた
- https://youtu.be/N1lhkH33fwY?t=18051
- AWS Lambda環境ではNode.jsのほうが若干はやいケースがある
- AWS LambdaでTypeScriptをそのまま動かせる
- 現状は開発環境で使えるか
On-browser advertisement auctions using PrivacySandboxAPI
- https://youtu.be/N1lhkH33fwY?t=20292
- PrivacySandboxAPI
- いくつかのAPIがまとまったもの
- 3rd party cookies廃止でできなくなることを補う目的のAPIも多い
- Sellerとbuyerの間で広告枠を売り買いする
- 今回扱うのはProtected Audience API
- いままではサーバ上で行っていたオークションをブラウザ上で行う
- buyerはgenerateBid関数で入札額を返り値とし、入札額が最も大きいものの広告が表示される
- Script runnerという実行環境で実行され、利用できるAPIが制限されている
- Chromeのデバッガはソースマップ対応していないので、デバッグに工夫が必要
- buyerとしてはgeneratedBid関数に渡された引数から最適な入札額を計算したい
- 計算方法には機械学習がよく利用される
- mljsではパフォーマンスに問題があったのでwasm(Rustからビルド)したものを利用
Intlの今までとこれから
- https://youtu.be/N1lhkH33fwY?t=22238
- Intlのすべてのコンストラクタは2つの引数を受けとる
- location "en", "ja-JP"
- option コンストラクタごとのオプション
- Intl.RelativeTimeFormat - JavaScript | MDN
- Intl.DisplayNames - JavaScript | MDN
- 基本的にすべてのブラウザの対応状況はよい
- 関連する仕様が多い
- ロケール
- 各地域の違いを抽象化してAPIとして提供しているので、まとめるのも大変そうだなと思った
- TemporalはIntlに準拠したAPIを策定している
パスワードレス認証がもたらすユーザー体験の向上と考慮点
- https://youtu.be/rDfPXDEot_A?t=2327
- にわかいつら
- パスワード認証は課題が多い
- 単純なパスワード -> 複雑なパスワードの要求
- 1人が管理するパスワードは100以上もざら
- 覚えられない/つかいまわし/管理ツールが必要
- MFAの課題
- SNS
- カバーエリア
- 遅延
- コスト
- SIMスワップ
- Authenticator TOTP
- SNS
- パスワードレス認証
- WebAuthn
- 公開鍵暗号方式を利用
- Okta Demo
- デバイス紛失(=鍵紛失)でアカウントにログインできなくなる
- Passkeys
- WebAuthn
- UX
- ユーザ体験はいろいろなサービスが試行錯誤している段階
- パスワードでのログイン後にユーザに選択を促す
- Autofill
- パスワードマネージャを使ったパスワードログインと同じ体験で利用できる
- パスキー利用のボタンを明示
ChatGPTっぽいUIを実現する技術
- https://youtu.be/rDfPXDEot_A?t=5051
- ChatGPTのUIがAIが文章を書き込んでいるように見せるところが画期的だった
- LLMは逐次的に次の単語を選択している
- 文章全体を生成するのには時間がかかるので、単語レベルのようなブロックで結果が返すのを繰り返すAPIになる
- Web Streams API
- Node/Denoでも実装される
- SSE
- ChatGPTが採用したことで今まで以上に注目される
- JavaScript側でSSEのレスポンスをパースは自前で行うことになる
- イベントベースでのAPIならEventSource APIで読める Using server-sent events - Web APIs | MDN
- Content-Typeは
text/event-stream
- メディア以外にもStreamを扱う用途が増えてきた
Storybook駆動開発 UI開発の再現性と効率化
- https://youtu.be/rDfPXDEot_A?t=9532
- テスティングツールとしてのStorybook
- めっちゃ複雑
- AtomicDesignでいうOrganism以上のコンポートネントはドメインの複雑さをかかえるため複雑
- Story: ユーザのユースケース
- 複雑な状態単位でStoryの分割ができる
- 知らない機能に対してどのような状態でどのような動作をすることの理解の助けになる
- めっちゃ重い
- フロントエンド側だけでスコープを小さくしてレンダリングできる
- 再現性
- 簡単に確認できる箇所にテストをいれるだけで、他の箇所のリファクタリングの影響を確認できる
- Jest + Testing Libraryでがっちりかかなくても十分いける
- 利用例
- 料金プランと数多くのサブシステムへの動線生合成
- 権限による操作の整合性
- 顧客自由度の高いUI動作保証
- マトリクスを使うような条件の組み合わせでアプリケーションの動作がかわるようなケースで有用