mmag

ハマったことメモなど

dev.toコードリーディング会に参加した

smarthr.connpass.com

行ってきました。十数人で各々が好きなところから読み始めて、最後に見所や気づきを喋る流れでした。initializersを読んでいく人やモデル中心に見ていく人など様々。近日中に全員のメモが公開されるとのことですので、そのときはリンク追記します。会場を提供してくださったSmartHRさんありがとうございました。


追記

追記ここまで


以下は自分のメモ。やはりdev.toと言えば爆速なので、CSSをheadタグに埋め込んでいたり、キャッシュってどうやってんだろうなーといったところを中心に読みました。最後の所感にも書きましたが、爆速サイトをつくるためのイケてる最強プラクティスが詰まったコードを期待していた割に、泥臭さ100%のコードやら結構ひどいメソッドたちやらが溢れていて、歴史に勝てるものはおらんのじゃ...という気持ちになりました。usersテーブル辺りを見ると共感が得られると思います。やはり銀の弾丸は無く、歯を食いしばってひとつずつ問題をなぎ倒していくしか道は無いのです...。

なお、ハイライトは http://sushi.to というサイトが発見された瞬間でした。

### headタグへのCSS埋め込み

- [`render "layouts/styles"`](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/views/layouts/application.html.erb#L20)
  - ページに必要なCSSをひたすら`.to_s.safe_html`
  - [キャッシュ条件が結構ながい](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/views/layouts/_styles.html.erb#L1)
  - [ここで`<% Rails.application.config.assets.compile = true %>`](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/views/layouts/_styles.html.erb#L4)
  - 思っていたより泥臭いし、メンテできる気がしないけどどうなのか
    - [大多数のページは`stylesheet_link_tag application`](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/views/layouts/_styles.html.erb#L75)なので意外と大丈夫なのかも
  - [`core_page?`で](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/views/layouts/_styles.html.erb#L73)最小限のcssを読むか判定している
    - このcssはService Workerがはじめにキャッシュしている
### Service Worker

- [serviceworker-rails](https://github.com/rossta/serviceworker-rails)使ってる
- [service-worker.js.erb](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/assets/javascripts/serviceworker.js.erb)
  - インストール時に最小限必要なjs, css, 画像類, offline.htmlを取得してキャッシュに入れてる
  - GET以外、通知の取得はスルーしてネットワークへ
  - 割とキャッシュに入れてない
    - [この条件](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/assets/javascripts/serviceworker.js.erb#L70)にマッチしたやつだけ
- [serviceworker-companion.js](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/assets/javascripts/serviceworker-companion.js)
  - 割と普通
  - Homeにインストールの結果をGAに送っていた

### どうやってCDNキャッシュしてるか

- bodyのdata属性にユーザ情報を埋め込んでいるが、これを非同期にやっているのでCDNにキャッシュできる

[initializePage.js.erb](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/assets/javascripts/initializePage.js.erb)

`javascript=
function initializePage(){
  initializeLocalStorageRender();
  initializeStylesheetAppend();
  initializeFetchFollowedArticles();
  callInitalizers();
}

function callInitalizers(){
  initializeLocalStorageRender();
  initializeBodyData();
`

[`initializeBodyData`](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/assets/javascripts/initializers/initializeBodyData.js)で`/async_info/base_data`を叩いてbodyのdataに入れてる。入れたらlocalStorageにも入れてる。次回からはlocalStoreageから読み出してbodyのdataに入れてる。[`getUserData()`](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/javascript/src/utils/getUserData.js)は15秒間待ってる。

[base.js.erb](https://github.com/thepracticaldev/dev.to/blob/a82bcd9dd9ae9be98c3f08548bcb41d5f7b70c96/app/assets/javascripts/base.js.erb#L229)

`javascript=
function mouseoverListener(e) {
  if ($lastTouchTimestamp > (+new Date - 500)) {
    return // Otherwise, click doesn't fire
  }

  var a = getLinkTarget(e.target)

  if (!a || !isPreloadable(a)) {
    return
  }

  a.addEventListener('mouseout', mouseoutListener)

  if (!$delayBeforePreload) {
    preload(a.href)
  }
  else {
    $urlToPreload = a.href
    $preloadTimer = setTimeout(preload, $delayBeforePreload)
  }
  getImageForLink(a);
}
`

マウスホバーでの先読みしてる。スマホは`touchstartListener`。

### 所感

CSS埋め込みとか、CDNエッジキャッシュするための工夫とか、もうちょっと高度な謎テクノロジーであのパフォーマンスを実現していると思っていたけど、読んでみたら想像を絶する泥臭さだった。総じて、この量のjsをテストほとんど無しで本当に書いたの...という気持ち。