yn2011's blog

技術メモ

img タグからのリクエストは Origin ヘッダーを持たないのでレスポンスの Access-Control-Allow-Origin を満たしていなくても CORS 違反にならないらしいという話

歴史的経緯により img タグからのリクエストは(crossorigin 属性を付与しない限り)クロスオリジンの場合でも preflight リクエストは飛ばない。これを simple request と呼ぶことは知っていた。

しかし、画像のレスポンスヘッダーに例えばAccess-Control-Allow-Origin: https://hoge.com が含まれる場合に、hoge.com 以外から img タグを利用してリクエストを送ると CORS 違反になるんじゃないかと思っていた。

しかし実際に試してみたら、そのような画像に対して、img タグからリクエストを発行すると正常に画像を取得することができることが分かった。

例えば、localhost で以下のコードを動かすと画像が正常に表示される。 はてブ数を表示する画像 URL はレスポンスに Access-Control-Allow-Origin: https://b.hatena.ne.jp を含むので例として使用している。

コード例1 (画像を取得できる)

<img src="https://b.st-hatena.com/images/users/gif/normal/00001.gif"> // OK

コード例2 (これは駄目)

fetch("https://b.st-hatena.com/images/users/gif/normal/00001.gif"); // CORS エラー

コード例3 (crossorigin 属性を付与すると駄目)

<img src="https://b.st-hatena.com/images/users/gif/normal/00001.gif" crossorigin="anonymous"> // CORS エラー

Chrome の Network タブを見てみると、コード1 の場合はリクエストヘッダーに Origin が含まれていないが、コード2,3 の場合は含まれている。

これは、MDN の Origin に関する記述から引用すると

There are some exceptions to the above rules; for example if a cross-origin GET or HEAD request is made in no-cors mode the Origin header will not be added.

ブラウザは、Origin ヘッダーを基本的には付与するものの、いくつもの例外が存在し、no-cors モードのリクエストには付与しないという。

no-cors モードは、すなわち img タグが(crossorigin 属性を付与しない限り)クロスオリジンでリクエストを行う場合に該当する。 Origin ヘッダーがなければ、たとえレスポンスに Access-Control-Allow-Origin ヘッダーが含まれていても許可されている Origin なのか判定できないから CORS 違反にはならないということだろうか?

ちなみに、fetch を利用して img タグのリクエストを再現すると以下になり、この場合は CORS 違反とはならない。

コード4

fetch("https://b.st-hatena.com/images/users/gif/normal/00001.gif", {
  mode: "no-cors",
});

mode: no-cors の意味がやっと分かった気がする。

ちなみに、img タグを使われると画像配信側はクロスオリジンリクエストでレスポンスを必ず読み取られてしまうのか、というとそんなことはない。

Origin 解体新書の Origin をまたぐその他の仕様 にも記載があるが、サーバー側でリクエストのヘッダーに Origin が含まれているのか判定し、403 エラーを返す実装にすることで実現できる。

こうすると、コード1 のように crossorigin 属性が未付与の場合は Origin ヘッダーが含まれないので 403 エラーになるし、コード3 のように Origin ヘッダーを含めても許可されていない Origin は Access-Control-Allow-Origin に許容すべきオリジンを列挙してレスポンスに含めることでブラウザはレスポンスを読み取れない。

参考

https://stackoverflow.com/questions/47978252/how-img-tag-gets-content-over-cors-headers

flex item は幅を指定せずに margin: auto で縦横中央揃えできる

margin: auto を使用した縦横中央揃えは要素自体に幅((max-)width, (max-height))の指定が必須と思っていた。

例えば、position: absolute と組み合わせた以下の要素は親(absolute の基準)に対して縦横中央揃えされるが

 .test {
  background-color: aqua;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  max-height: 100px;
  max-width: 100px;
}

これは max-widthmax-height の指定がない場合は動作しない。

しかし、flex item (flex box の子要素) の場合はなぜか幅の指定がなくても縦横中央揃え可能になる。

.parent {
  display: flex;
}
.test {
  background-color: aqua;
  margin: auto;
}
<div class="parent">
  <div class="test">hoge</div>
</div>

これは幅の指定の有無以外は、最初のコード例と同一になるので、親の大きさに合わせて縦横中央揃え可能になる。

こうすれば 500px の正方形の中で縦横中央揃えになる

.parent {
  display: flex;
  width: 500px;
  height: 500px;
}
.test {
  background-color: aqua;
  margin: auto;
}

画面全体に対して縦横中央揃えする場合は、親自体を広げれば OK

.parent {
  display: flex;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

ちなみに、margin: auto を使わずにこの指定でも問題ない

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

どちらがベストなのかは分からない。参考リンク↓

stackoverflow.com

モブプログラミングのモブのときに意識していること

前提

  • モブプログラミング歴 9 ヶ月程度
  • 参加者は全員リモートワークで、最小2人、最大でも4人
  • 自分がモブになるかドライバーになるかは事前に分からない(抽選)
  • 何をモブプログラミングするかは事前にある程度分かっている

モブプログラミングをする前にやっていること

正直毎回予習しているわけではなく、ちょっと今日の開発は難しそうだなと思ったら準備する(場合もある)

  • ドキュメントを軽く読んでおく
    • 使用する言語やライブラリに慣れていない、使う予定の外部サービス(AWS, Google Analytics, Repro etc)に詳しくない場合
  • 開発対象の既存コードを軽く読んでおく
    • 該当箇所の既存コードを触ったことも見たこともない場合
  • 大体の開発の進め方や議論して決めないといけないことをイメージしてみる
    • 想定通りにならないことも多いが、なんとなく考えてみる

モブのときにやっていること

助ける

  • 実装で悩んでいたら助ける

    • 自分もすぐには分からないときは、ググって URL を共有する
    • 例えば、言語、ライブラリのドキュメントや、既存コードで似たような修正を行ったプルリクとか。
  • 先読みして助ける

    • 何となくコードを書いていく流れが見えてきたら事前に障害になりそうな箇所についてググる、既存実装がないか調査するなど
    • 例えば、文字列を数値に変換しないといけないことが明らかだったら、事前にググって型変換の良さげな方法を把握しておくとか。

進行する

  • 悩みすぎて作業が止まってしまっていたら前に進める

    • 命名、現段階では正解が分からない実装方針、個人の趣味の問題でしかないこと、誰かに質問した方が早いこと、議論の堂々巡りなど
    • 大体は「とりあえず今はこれにして、後でまた考えましょう」とか「この人に後で聞きましょう」とか発言すると解消されることが多い
  • 休憩をするように促す

    • ドライバーをしていると、夢中になりすぎていたりするのでモブの人から休憩を提案する
    • 疲労がコミュニケーションの軋轢になったりする
  • 全員でやらなくてもいいことを切り分ける

    • 何となく流れで単純な置換作業とかドキュメントの編集をしてしまうこともあるが、後で1人でできることなら後回しにしてモブプログラミングの効率を高める

質問する

  • ドライバーや他のモブの人と認識がズレている、何をしようとしているのか分からなくなったら質問する

    • 分かったふりで進行してしまうとモブプログラミングをしている価値が下がってしまう
    • 実は全員の考慮漏れで重要なことだったりもする(会話しながら考えていると、パターンの考慮漏れとかはけっこうある印象)
  • 本筋と関係ないが、ショートカットキーや知らないコマンド、機能などがあったら質問する

    • 流れ的に質問しにくい場合もあるが、けっこう学びになることがあるので質問してみると良い
    • 逆にドライバーが自発的に説明するのは「いや、知ってるが...」みたいな空気になると嫌なので勇気がいると思う(相当マニアックなことなら良いが)

丁寧に会話する

  • 口頭で説明できないことを無理に説明しない

    • 図やコードで示したほうが早いことは、自分がドライバーでなくても一旦画面共有させてもらう等してコミュニケーションを効率化する
  • 高圧的にならない

    • 自分の方がよく理解している実装や分野の場合やコミュニケーションが上手くできないときに、もどかしい気持ちを感じたりするかもしれないが HRT を意識してコミュニケーションする。

記録する

  • 考えたこと・学んだこと・やったことを書記として記録する
    • モブプログラミングのログを残し、後から参照可能にする
    • 決定事項だけでなく、思考や議論の過程とか、途中で悩んだこととかも書いておくと良い
    • Scrapbox を使って全員が同時に読み書きできるようにしている

モブのときにやらない方がいいこと

  • 画面を見てはいるが、一緒には考えていない、ついていけてない、同時に別の作業をしている
    • モブプログラミングに参加している意義が薄くなる
  • 音声を聞き取りにくい、画面の文字が見えにくい等環境面の我慢
    • 遠慮せずに伝えたほうが全員のためになる。逆に指摘されたら素直に対応する。(音声の問題は自分でどうにもならないこともあるが)

Storybook を CSS Modules + Next.js プロジェクトに導入する際にハマったこと

環境

  • next 10.0.6
  • @storybook/react 6.1.21
  • @storybook/preset-scss 1.0.3
  • css-loader 3.6.0
  • sass-loader 10.1.1

(多いな)

Storybook を CSS Modules + Next.js プロジェクトに導入したい

ドキュメントに従って、npx sb init するだけでは駄目だったのでハマった点を書く。

.storybook/main.jswebpackFinal で色々しない

ググる.storybook/main.jswebpackFinal で色々して解決する事例が出てくる。これはあんまりやりたくない。 もう少し調べてみたら今は @storybook/preset-scss という addon を使えば自分でコードを書かなくてもいいということが分かった。あぶない。

@storybook/preset-scss がインストールできない

別の記事に書いた。

pokuwagata.hatenablog.com

TypeError: this.getOptions is not a function at Object.loader

v11 系の sass-loader を使うとこのエラーが出てビルドできない。

stackoverflow.com

$ npm i -D sass-loader@10.1.1

すると直る。

cssLoaderOptions を正しく設定する

Install addons に従って .storybook/main.js を設定しておけば良いのかと思いきや css-loader v3 系を使用すると以下のエラーが出てしまう。

ValidationError: Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'localIdentName'. These properties are valid:

正しくは、こういう感じになる。

module.exports = {
  stories: ["../{pages,components}/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    {
      name: "@storybook/preset-scss",
      options: {
        cssLoaderOptions: {
          modules: { localIdentName: "[name]__[local]--[hash:base64:5]" },
        },
      },
    },
  ],
};

v3 から localIdentName オプションの位置が変更になっている。

github.com

storybookjs/presets にはプルリクも出されているんだがまだ対応されていない。 github.com

参考

npm error: Cannot destructure property `name` of 'undefined' or 'null'

環境

node v15.6.0

npm v7.5.2

npm i -D @storybook/preset-scss

$ npm i -D @storybook/preset-scss したら以下のエラーがでた

npm ERR! code ERESOLVE
npm ERR! Cannot destructure property 'name' of 'node' as it is null.

legacy-peer-deps=true

こちらの Issue によると、npm v7 の不具合らしい。 記載されているとおりに、

$ echo "legacy-peer-deps=true" >> .npmrc

すると直った。($ npm install --legacy-peer-deps でも良いらしい)

npm v6 にダウングレードするよりは良い解決策らしいのでこちらのエラーが出たらこの設定を追加してみよう。

CSS 中央揃えのフローチャート

どういうときにどの中央揃えテクニックを適用するかという整理をしたかったのでフローチャートを作成した。多分まだ間違いや改善の余地はあると思うが、とりあえず今の自分はこういう風に考えているということで公開する。(図が汚い&ブログのモーダルで見にくいのは許して)

f:id:pokuwagata:20210307015307j:plain
フローチャート図(クリックで拡大)

横中央揃えについては、基本的には margin: auto で済むと思う。横中央揃えで max-width 指定しない(できない)ケースってあるんだろうか。縦も合わせて揃えたいなら flexbox か position: absolute

flexbox と position: absolute のどちらを優先して使うべきかについて明確な答えは持っていないけど、flexbox で済むならその方が簡単な気はするのでそういう順序でフローチャートを書いている。

縦中央揃えについては、上下の padding や display:table など小技はあるが、悩むぐらいなら flexbox でいいのでは?という気がしているのでそうした。line-height は親の高さが決まっているなら自分自身に指定するだけで済むので、flexbox より簡単かと思う。

縦横中央揃えのケースも考慮すると、もう少しフローチャートが複雑になるのかなと思っていたけどそうでもなかった。結局は flexbox か position: absolute の指定で両方向に対応できるのでそれで済みますねという。

自分がこれから CSS を実装していてもうちょっと直したほうがいいかなと思ったら逐次更新していきます。見栄えが微妙なので図自体描き直すかも。

ツイートで振り返る 2020 年 1~3月

ブログのリハビリということで簡単に書けそうな振り返り系の記事。1年分を1記事にする予定だったが、3月までで力尽きた。そのうち続編を書くかもしれない。

1月

Vim で Go を書こうとしていたらしい。

個人サービス開発について。これ、なんでそう思ったのかあんまり記憶にない。

この頃に競プロに興味持ち始めたらしい。

コロナ影響でリモート勤務が始まった頃かな?

当時の勤務先はかなり早期から原則リモート勤務に切り替わっていて凄かった。正直、当時は新しい風邪が流行り始めただけで原則リモート勤務はやりすぎじゃないか? という気持ちがあったし、そういう空気あったように思う。今から振り返ると素晴らしい意思決定だったと言わざるを得ない。

その他

1 月は転職活動していて、週に何度も色々な会社の面接を受けに行っていた。面接というのはやはり精神力を必要とするもので、「この面接空気悪いな?(#^ω^) ビキビキ」とか「もっとこう話せば良かった」とか色々あった。業務が落ち着いていないとなかなかしんどい生活だな、と思っていた。

2月

なんか疲れてそう

めちゃくちゃ良い言葉

やりたいことなんて常に変化するし、将来からの逆算とかあんまり意味ない。

Go の練習してた。

なんで Vue 書いてるんだろう?

良い本だった。自分が DDD を業務で実践する機会が訪れるのかは謎だが...

分かる。

謎の仮想敵を作っちゃう話。これ、SNS 系(特に twitter とか はてブとか)をほぼ見ないようにすれば大体解決しそう。デジタルミニマリストを読んだ話はそのうち書きたい。

TypeScript の練習?

その他

ぎりぎり採用面接は普通に対面で行われていた時期で、自分が内定獲得したあたりからはリモート面談に切り替わる流れがあった印象。もう数ヶ月転職活動を始める時期が遅れていたら色々と結果は変わっていたかもしれない。

3月

Basecamp 社なんかはコミットメント型になるのかな(あるいは、"だった")

今再読したけど良い話でした

この頃にも脱テレビをしようとしていたらしい。(なお、今年の2月からも再挑戦中)

まだ Vim で遊んでいた模様。今はもう VSCode しか使ってません。

リモート勤務が続いていて、テキストメッセージについて思うところがあったのかもしれない。

この頃、手湿疹がなぜかめちゃくちゃ酷くて鬱になりそうだった。転職活動の影響なのか診察と採用面接の区別がつかなくなっていた(嘘)

コロナ影響が大きくなってきた時期。

その他

入籍、転職、コロナと色々あった月。4月は有休消化で自由に過ごせるはずが、コロナ影響で完全引きこもり生活を余儀なくされることが確定し残念だった。まあ元からインドア派なんですが...