<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tomoyuki Kashiro</title>
    <description>The latest articles on Forem by Tomoyuki Kashiro (@t-jindai).</description>
    <link>https://forem.com/t-jindai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F42039%2F631cd491-ee70-48b5-8b37-2016da6e9ee9.jpeg</url>
      <title>Forem: Tomoyuki Kashiro</title>
      <link>https://forem.com/t-jindai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/t-jindai"/>
    <language>en</language>
    <item>
      <title>Use Page Object Pattern in React Component Tests</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Sat, 13 Aug 2022 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/use-page-object-pattern-in-react-component-tests-1f43</link>
      <guid>https://forem.com/t-jindai/use-page-object-pattern-in-react-component-tests-1f43</guid>
      <description>&lt;p&gt;My understanding is that readability and maintainability are domains which should be put high priority in software tests. To achieve this, using &lt;code&gt;Page Object Pattern&lt;/code&gt; might be a good help not only in E2E tests but also React Component tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Page Object Pattern
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://webdriver.io/docs/pageobjects/" rel="noopener noreferrer"&gt;https://webdriver.io/docs/pageobjects/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Page Object Pattern is one of the software programming principle which encapsulate page manipulation logic that tend to harm readability and maintainability in software tests.&lt;/p&gt;

&lt;p&gt;Software test involves two kinds of cods below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;test code : e.g. Shows error messages when invalid email is typed in form.&lt;/li&gt;
&lt;li&gt;manipulation code to reproduce test situation : e.g. Shows page then type email&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Page Object Pattern aims to move the latter codes to page class, which is called Page Object, to help software engineers read and write the former codes easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  The example of Page Object Pattern
&lt;/h2&gt;

&lt;p&gt;Let’s see &lt;a href="https://webdriver.io/docs/pageobjects/" rel="noopener noreferrer"&gt;https://webdriver.io/docs/pageobjects/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Page class has E2E test instance which comes from test library such as selenium.
import Page from './page'

class LoginPage extends Page {

    // Defines some functions to manipulate page to reproduce test situation.
    get username () { return $('#username') }
    get password () { return $('#password') }
    get submitBtn () { return $('form button[type="submit"]') }
    get flash () { return $('#flash') }
    get headerLinks () { return $$('#header a') }

    async open () {
        await super.open('login')
    }

    async submit () {
        await this.submitBtn.click()
    }

}

export default new LoginPage()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using this page instance to prepare test cases, we can make test codes simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('should deny access with wrong creds', async () =&amp;gt; {
    await LoginPage.open()
    await LoginPage.username.setValue('foo')
    await LoginPage.password.setValue('bar')
    await LoginPage.submit()

    await expect(LoginPage.flash).toHaveText('Your username is invalid!')
})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to use Page Object Pattern in React Component tests
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import type { ComponentProps } from "react";
import { render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import LoginForm from "./LoginForm";

type Props = ComponentProps&amp;lt;typeof LoginForm&amp;gt;

const setup = (props): Props =&amp;gt; {
  const { getByRole, getByLabelText, getByText } = render(&amp;lt;LoginForm {...props} /&amp;gt;);
  return {
    typeEmail: (email: string) =&amp;gt; userEvent.type(getByLabelText("email"), email),
    getByText,
    submit: () =&amp;gt; userEvent.click(getByRole("button"))
  };
};

it("When email typed is invalid, shows error message.", () =&amp;gt; {
  const utils = setup();
  utils.typeEmail("invalidemail");
  utils.submit();

  expect(utils.getByText("Email is not correct.")). toBeInTheDocument();
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>CSS MdiaQueryのmin-widthとmax-widthどちらを使う？</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Sun, 08 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/css-mdiaquery-min-width-max-width-2i2</link>
      <guid>https://forem.com/t-jindai/css-mdiaquery-min-width-max-width-2i2</guid>
      <description>&lt;h2&gt;
  
  
  はじめに
&lt;/h2&gt;

&lt;p&gt;レスポンシブデザインでサイトを作る際に、CSS MediaQueryの min-width / max-width を使いますが、どっちを使っていくべきか悩んでる人も多いのかと思います。&lt;/p&gt;

&lt;p&gt;この記事では、どっちを使っていくべきか解説していきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media (max-width: ◯◯px) {
  // 画面サイズが◯◯px以下に適用
}

@media (min-width: ◯◯px) {
  // 画面サイズが◯◯px以上に適用
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  結論
&lt;/h2&gt;

&lt;p&gt;基本的に、&lt;code&gt;min-width&lt;/code&gt; で書いた方が良いです。&lt;br&gt;&lt;br&gt;
そのように書くことで、CSSをシンプルに保つことができます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// sample.scss
.awesome-container {
  xxx: xxxx;
  xxx: xxxx;

  @media (min-width: 100px) {
    // 画面サイズが100px以上に適用
  }

  @media (min-width: 300px) {
    // 画面サイズが300px以上に適用
  }

  @media (min-width: 500px) {
    // 画面サイズが500px以上に適用
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  理由1：CSSは画面サイズが大きくなるに連れて、記述量が増える
&lt;/h2&gt;

&lt;p&gt;一般的に、画面サイズの小さいモバイル画面では、要素は上から下へ積み重なっていくようにデザインされて、画面サイズが大きくなるにつれて要素を横並びにしてデザインされることが多いです。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;mobile&lt;/th&gt;
&lt;th&gt;tablet&lt;/th&gt;
&lt;th&gt;desktop&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqepuk3y1y8hkqio1k1jl.png" alt="image.png" width="217" height="383"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdeyvlg830lqdahulvqy.png" alt="image.png" width="335" height="383"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvah1txkrnw14rhrmlol.png" alt="image.png" width="473" height="377"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;そして、HTMLで記述された要素は、デフォルトで、&lt;code&gt;左上から下&lt;/code&gt; に積み重なっていきます。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64frsxc6gsrsjg787nu9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64frsxc6gsrsjg787nu9.png" alt="image.png" width="401" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;この並びを &lt;code&gt;横&lt;/code&gt; にしようとするときCSSの &lt;code&gt;position, float ,display&lt;/code&gt; などでスタイルを調整していきます。&lt;br&gt;&lt;br&gt;
CSSのプロパティを、装飾目的、レイアウト目的の2つに分類したとすると、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;装飾目的：color / font-size / font-familly / border&lt;/li&gt;
&lt;li&gt;レイアウト目的：position / width / height / display&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;レイアウト目的のスタイルは、画面サイズの小さいモバイルだと、不要なケースが多く（縦に並べるだけならCSS不要）、画面サイズが大きくなるにつれて、横並びにするため、必要になってくきます。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;よって、画面サイズに応じて記述するCSSが増えていくのです。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  理由2：CSSはスタイルのキャンセルが手間
&lt;/h2&gt;

&lt;p&gt;CSSにはスタイルをキャンセルさせる方法がなく、キャンセルしたければ、初期値で上書きする必要があります。&lt;/p&gt;

&lt;p&gt;前述したように、画面サイズに応じてレイアウト目的のスタイルが増えていくので、先に画面サイズが大きいスタイルを記述すると、レイアウト目的スタイルが不要な小さい画面サイズのスタイルを記述するときに、都度キャンセルする必要がでてきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.awesome-panel {
  // 画面サイズが401px以上はabsolute
  position: absolute:

  @media (max-width: 400px) {
    // 画面サイズが400px以下ならpositionの初期値（static）でpositionをキャンセルする
    position: static;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;これを、画面サイズが小さいスタイルから記述すると、キャンセルが不要になります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.awesome-panel {
  // 画面サイズが400px未満
  // position: static: ←初期値なので記述不要

  @media (min-width: 400px) {
    // 画面サイズが400px以上ならabsolute
    position: absolute;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSSは画面サイズが大きくなるに連れて記述量が増える&lt;/li&gt;
&lt;li&gt;CSSはスタイルのキャンセルが手間である&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;という条件から、&lt;code&gt;min-width&lt;/code&gt; を利用して小さい → 大きい順にCSSを書くことで、 &lt;strong&gt;CSSをシンプルにでき、結果CSSのファイルサイズが小さくなり、メンテナンスしやすいスタイルを書くことができるようになります。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;また、Webサイトのデザイン・開発は &lt;code&gt;モバイルファースト（モバイル優先）&lt;/code&gt; で考えることが当たり前になってきましたが、この書き方はそのポリシーを反映した形になってて、マークアップもモバイルから作ることになるので良いという側面もあります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// sample.scss
.awesome-container {
  xxx: xxxx;
  xxx: xxxx;

  @media (min-width: 100px) {
    // 画面サイズが100px以上に適用
  }

  @media (min-width: 300px) {
    // 画面サイズが300px以上に適用
  }

  @media (min-width: 500px) {
    // 画面サイズが500px以上に適用
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  さいごに
&lt;/h2&gt;

&lt;p&gt;もしこれを読んでもまだ、 &lt;code&gt;max-widthベースの方がいい&lt;/code&gt; と感じる人はぜひ、1つのページを &lt;code&gt;min-widthベース&lt;/code&gt;と&lt;code&gt;max-width&lt;/code&gt; ベースの2通りで書いてみてください！&lt;br&gt;&lt;br&gt;
私も &lt;code&gt;どっちでもいいじゃん&lt;/code&gt; と思う派だったが、やってみるとmin-widthベースの方が圧倒的に書きやすく驚きました！&lt;/p&gt;

</description>
    </item>
    <item>
      <title>CookieのSameSite Attributeとは？</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Wed, 15 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/cookie-samesite-attribute-4cke</link>
      <guid>https://forem.com/t-jindai/cookie-samesite-attribute-4cke</guid>
      <description>&lt;p&gt;Cookie に SameSiteという新しい属性が追加されて、いくつかのブラウザではその初期値が変わる予定です。&lt;/p&gt;

&lt;p&gt;Google Chrome ではその変更が2020年2月を予定しています。&lt;br&gt;&lt;br&gt;
複数のドメインの間で通信をし、Cookieを利用するサービスは影響あるかもしれません。&lt;/p&gt;

&lt;p&gt;ここでは、 SameSite の概要と影響をさくっと確認していきます。&lt;/p&gt;
&lt;h2&gt;
  
  
  SameSite Cookies とは？
&lt;/h2&gt;

&lt;p&gt;SameSite とは、 Cookie に追加される新しい属性です。&lt;br&gt;&lt;br&gt;
Cookie を発行する際は、 key=value と合わせて、属性として Cookie の振る舞いを制御するオプションを設定できます。&lt;br&gt;&lt;br&gt;
例えば、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expires : Cookieの有効期限&lt;/li&gt;
&lt;li&gt;Secure : https の場合のみ利用を制限するかどうかのフラグ&lt;/li&gt;
&lt;li&gt;HttpOnly : サーバサイドでの利用に制限するかどうかのフラグ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;などです。&lt;/p&gt;

&lt;p&gt;SameSite は Cookie がドメインをまたいで利用されるときの挙動を制御する新しいオプションになります。&lt;br&gt;&lt;br&gt;
SameSite=Strict, SameSite=Lax, SameSite=None の3つの値から選択できます。&lt;br&gt;&lt;br&gt;
詳しい内容は後述します。&lt;/p&gt;
&lt;h2&gt;
  
  
  SameSite Cookie が必要とされる理由
&lt;/h2&gt;

&lt;p&gt;主な理由は、 CSRF（クロスサイトリクエストフォージェリー）という攻撃を防ぐことにあります。&lt;/p&gt;

&lt;p&gt;例えば、SNSなどでコメントを投稿する機能を例に考えます。&lt;br&gt;&lt;br&gt;
コメントを投稿するのに必要な仕様は以下だとします。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;method : post&lt;/li&gt;
&lt;li&gt;URL : example.com/comments&lt;/li&gt;
&lt;li&gt;parameter : body (コメント内容)&lt;/li&gt;
&lt;li&gt;条件 : ログイン必須（cookieを使って認証管理）&lt;/li&gt;
&lt;li&gt;方法 : &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; タグを利用して送信&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;HTMLはこんな感じ。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- example.com でのコメント投稿機能 --&amp;gt;
&amp;lt;form method="POST" action="https://example.com/comments"&amp;gt;
  &amp;lt;textarea placeholder="コメントを入力" name="body" rows="5" cols="33"&amp;gt;
  &amp;lt;button&amp;gt;コメント送信&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;もし、アクセスしたユーザーがログイン済みであれば、コメント投稿は成功します。&lt;br&gt;&lt;br&gt;
しかし、この実装のままだと、関係ないサービスからでもコメント投稿が成功してしまいます。&lt;br&gt;&lt;br&gt;
例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- example.net （.netなので無関係のサイト）からの、example.com のコメント投稿機能を悪用したいたずら --&amp;gt;
&amp;lt;form style="display: none;" method="POST" action="https://example.com/comments"&amp;gt;
  &amp;lt;textarea value="だれかの悪口。だれかの悪口。だれかの悪口。だれかの悪口。だれかの悪口。だれかの悪口。だれかの悪口。"&amp;gt;
  &amp;lt;button&amp;gt;コメント送信&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;このような実装で、ユーザーの意思とは関係なく、このformをsubmitすることで、そのログインユーザーのコメントとして投稿されてしまいます。&lt;br&gt;&lt;br&gt;
これがクロスサイトリクエストフォージェリーという攻撃です。&lt;/p&gt;

&lt;p&gt;tokenを使ってリクエストが example.com からであるかどうかを確認する方法でこの攻撃を防ぐのが、よく見る対応です。&lt;br&gt;&lt;br&gt;
この攻撃は、別のサイトからの意図しないリクエストであっても cookie 込みで送信されるという cookie の仕様を利用（悪用）した方法とも言えます。&lt;/p&gt;

&lt;p&gt;SameSite 属性を利用することで、 &lt;code&gt;関係ないサイト =&amp;gt; example.com&lt;/code&gt; へのリクエスト時に、cookie 込みで送信するかどうかを example.com 側で制御できるようになり、結果としてクロスサイトリクエストフォージェリー対策になります。&lt;/p&gt;

&lt;h2&gt;
  
  
  SameSite の確認方法
&lt;/h2&gt;

&lt;p&gt;Chrome DevToolsで確認可能です。&lt;br&gt;&lt;br&gt;
方法は2つあります。&lt;/p&gt;

&lt;h3&gt;
  
  
  ネットワークタブ
&lt;/h3&gt;

&lt;p&gt;Cookieが付与されているドメインのリクエストをネットワークタブで見つけ、詳細内の、 &lt;code&gt;Cookiesタブ&lt;/code&gt; で確認可能です。&lt;/p&gt;

&lt;h3&gt;
  
  
  アプリケーションタブ
&lt;/h3&gt;

&lt;p&gt;アプリケーションタブの &lt;code&gt;Storage&lt;/code&gt; &amp;gt; &lt;code&gt;Cookies&lt;/code&gt; でドメイン毎に確認可能です。&lt;/p&gt;

&lt;h2&gt;
  
  
  デモを使って確認
&lt;/h2&gt;

&lt;p&gt;さっそく、 SameSite を指定した Cookie がどのようになるのかデモとともにみていきます。&lt;br&gt;&lt;br&gt;
ここでは、サイトA（背景色が白）とサイトB（背景色がグレー）の２つのサイトで、3つのリクエストを例に見ていきます&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;サイトAからサイトBへの画面遷移&lt;/li&gt;
&lt;li&gt;サイトAでiframeを使って、サイトBを表示する際のリクエスト&lt;/li&gt;
&lt;li&gt;サイトAからサイトBへのXHR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;サイトBには、 &lt;code&gt;test=test&lt;/code&gt; という Cookieが付与されています。&lt;br&gt;&lt;br&gt;
サイトBを表示（リクエスト）する際、 &lt;code&gt;test=test&lt;/code&gt; のCookieが読み取れれば画面に表示し、読み取れなければ、 &lt;code&gt;test=&lt;/code&gt; と表示します。&lt;/p&gt;

&lt;p&gt;Cookieを設定する際、 &lt;code&gt;SameSite&lt;/code&gt; のオプションを変えて、上記3つのリクエストでCookieの読み取りにどんな違いがでるか見ていきます。&lt;/p&gt;

&lt;h2&gt;
  
  
  デモ結果
&lt;/h2&gt;

&lt;p&gt;サイトBでCookieの中身を読み取れるか？&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;sameSite&lt;/th&gt;
&lt;th&gt;ページ遷移&lt;/th&gt;
&lt;th&gt;iframe&lt;/th&gt;
&lt;th&gt;XHR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;strict&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lax&lt;/td&gt;
&lt;td&gt;⭕&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;⭕&lt;/td&gt;
&lt;td&gt;⭕&lt;/td&gt;
&lt;td&gt;⭕&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://samesite-cookie.web.app/" rel="noopener noreferrer"&gt;https://samesite-cookie.web.app/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SameSiteの利用パターン
&lt;/h2&gt;

&lt;p&gt;認証管理に例して考えるなら、、、&lt;/p&gt;

&lt;h3&gt;
  
  
  Cookieで認証管理しており、別ドメインからリクエストを行わないサービス
&lt;/h3&gt;

&lt;p&gt;SameSiteを利用することで、クロスサイトリクエストフォージェリーの攻撃を防ぐことができるので、可能な限り、 &lt;code&gt;SameSite=Strict&lt;/code&gt; や &lt;code&gt;SameSite=Lax&lt;/code&gt; の利用をしていきたいとこです。&lt;/p&gt;

&lt;h3&gt;
  
  
  Cookieで認証管理しており、別ドメインからリクエストを行うサービス
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;SameSite=Strict&lt;/code&gt; や &lt;code&gt;SameSite=Lax&lt;/code&gt; を利用すると別ドメインからのリクエストでは、ログイン済みでも、Cookieが付与されて送信されないため、未ログインとして扱われてしまします。&lt;/p&gt;

&lt;p&gt;また、Chrome, Firefox, Edgeでは SameSite が未指定の場合 &lt;code&gt;SameSite=Lax&lt;/code&gt; として扱うことを検討しており、 Chrome version 80で 未指定の場合、 &lt;code&gt;SameSite=Lax&lt;/code&gt; として扱い変更がリリースされる予定です。&lt;/p&gt;

&lt;p&gt;よって、何も対応してないと、2020年2月の Chrome version 80 のリリースのタイミングでこのケースのサービスでは Chrome で &lt;code&gt;ログインできない&lt;/code&gt; 不具合が発生します。&lt;br&gt;&lt;br&gt;
今まで同じ挙動にするためには、 &lt;code&gt;SameSite=None&lt;/code&gt; と &lt;code&gt;Secure&lt;/code&gt; のオプションを Cookie に設定する必要があります。&lt;/p&gt;

&lt;h3&gt;
  
  
  忘れがちなパターンの Chrome extension
&lt;/h3&gt;

&lt;p&gt;別ドメインでリクエストが発生する忘れがちなパターンに Chrome extension があります。&lt;br&gt;&lt;br&gt;
もし Chrome extension を開発している場合は、 2020年2月の Chrome version 80 のリリースのタイミングでトラブルにならないように確認しておきましょう。&lt;/p&gt;

&lt;h2&gt;
  
  
  SameSite未指定の場合、SameSite=Laxとして扱われることの確認方法
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://youtu.be/QSKky-bkTQ8?t=324" rel="noopener noreferrer"&gt;https://youtu.be/QSKky-bkTQ8?t=324&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Consider Hover UX for Tablet Device</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Fri, 08 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/consider-hover-ux-for-tablet-device-12i0</link>
      <guid>https://forem.com/t-jindai/consider-hover-ux-for-tablet-device-12i0</guid>
      <description>&lt;p&gt;Recently I bought Surface Go for browser testing and use it for my daily life too.&lt;br&gt;&lt;br&gt;
Sometime I met some sites which had hover based navigation but it didn’t work correctly on tablet device.&lt;br&gt;&lt;br&gt;
This is a capture when I used &lt;a href="https://kybarg.github.io/bootstrap-dropdown-hover/" rel="noopener noreferrer"&gt;bootstrap-dropdown-hover&lt;/a&gt; which is bootstrap hover based navigation on Surface go.&lt;/p&gt;

&lt;p&gt;It is difficult to tell what’s going on… I was trying to open dropdown menu but It didn’t work correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngij4t5tg3wn1yojak0c.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngij4t5tg3wn1yojak0c.gif" alt="operating dropdown menu on tablet device" width="602" height="416"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What’s the matter?
&lt;/h2&gt;

&lt;p&gt;When I use laptop the dropdown menu works!!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ccblb3z20blin0brqu1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ccblb3z20blin0brqu1.gif" alt="operating dropdown menu on laptop" width="514" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I use mobile the dropdown menu works correctly too.&lt;br&gt;&lt;br&gt;
This is because most of mobile browser treat &lt;code&gt;tapping&lt;/code&gt; and &lt;code&gt;after tapping&lt;/code&gt; state as &lt;code&gt;:hover&lt;/code&gt; CSS pseudo-class so if the hover based dropdown menu is implemented using &lt;code&gt;:hover&lt;/code&gt; it’s works!!!!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkja0ahfri6c8cd24y08h.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkja0ahfri6c8cd24y08h.gif" alt="operating dropdowwn menu on mobile" width="394" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote blog about this in my past blog post plz check more details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.tomoyukikashiro.me/post/how-to-set-active-style-to-button-in-mobile/" rel="noopener noreferrer"&gt;How to set :active style to button in mobile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But it doesn’t seems that Edge browser on Surface go treats &lt;code&gt;tapping&lt;/code&gt; and &lt;code&gt;after tapping&lt;/code&gt; state as &lt;code&gt;:hover&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;browser&lt;/th&gt;
&lt;th&gt;hover&lt;/th&gt;
&lt;th&gt;taping&lt;/th&gt;
&lt;th&gt;after tapping&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Edge on surface go&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;:active&lt;/td&gt;
&lt;td&gt;:focus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mobile Safari&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;:active&lt;/td&gt;
&lt;td&gt;:hover&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://codepen.io/Tkashiro/full/EaVVxr" rel="noopener noreferrer"&gt;demo site&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What should we do?
&lt;/h2&gt;

&lt;p&gt;whether the browser treat &lt;code&gt;tapping&lt;/code&gt; and &lt;code&gt;after tapping&lt;/code&gt; state as &lt;code&gt;:hover&lt;/code&gt; CSS pseudo-class or not is different in browsers so we need to detect that users use input device that works &lt;code&gt;:hover&lt;/code&gt; or not.&lt;/p&gt;
&lt;h2&gt;
  
  
  Common mistake
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* for mobile style */
/* .... */
@media (min-width: 768px) {
  /* for tablet style */
  /* .... */
}
@media (min-width: 1024px) {
  /* for laptop style */
  /* .... */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The common mistake is separating style based on device width using &lt;code&gt;min-width&lt;/code&gt; or &lt;code&gt;max-width&lt;/code&gt; media query then you avoid to use &lt;code&gt;:hover&lt;/code&gt; CSS pseudo based UI on tablet device.&lt;br&gt;&lt;br&gt;
In this way you don’t consider…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Device has tablet width and works &lt;code&gt;:hover&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Device has laptop width but doesn’t work &lt;code&gt;:hover&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example MS Edge on Surface Go has same width as table but doesn’t work &lt;code&gt;:hover&lt;/code&gt; CSS pseudo…&lt;/p&gt;
&lt;h2&gt;
  
  
  How do we detect the devices?
&lt;/h2&gt;

&lt;p&gt;We can detect &lt;code&gt;devices which work :hover&lt;/code&gt; and &lt;code&gt;devices which don't work :hover&lt;/code&gt; by using &lt;code&gt;Interaction Media Features&lt;/code&gt; specs below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pointing Device Quality&lt;/li&gt;
&lt;li&gt;Hover Capability&lt;/li&gt;
&lt;li&gt;Rare Interaction Capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prior knowledge
&lt;/h2&gt;

&lt;p&gt;Devices can connect multiple input device such as mouse or tablet pen with touch screen device.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pointing Device Quality
&lt;/h2&gt;

&lt;p&gt;This is a kind of &lt;code&gt;media query&lt;/code&gt; to detect accuracy of the user’s primary pointing device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* if user's primary input device includes a pointing device of limited accuracy */
@media (pointer: coarse) {
}

/* if user's primary input device includes a accurate pointing device */
@media (pointer: fine) {
}

/* no pointing device */
@media (pointer: none) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hover Capability
&lt;/h2&gt;

&lt;p&gt;This is a kind of &lt;code&gt;media query&lt;/code&gt; to detect hoverable of the user’s primary pointing device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* if user's primary input device includes a hoverable device */
@media (hover: hover) {
}

/* if user's primary input device doesn't includes a hoverable device */
@media (hover: none) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rare Interaction Capabilities
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Pointing Device Quality&lt;/code&gt; and &lt;code&gt;Hover Capability&lt;/code&gt; detect the capability of primary input device only so if user connect multiple input devices (like secondary input) those will be ignored.&lt;br&gt;&lt;br&gt;
On the other hand, You can detect those capabilities by using &lt;code&gt;any-pointer&lt;/code&gt; and &lt;code&gt;any-hover&lt;/code&gt; media queries.&lt;br&gt;&lt;br&gt;
Those detection are based on multiple input devices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* if user's primary input device includes "any" pointing device of limited accuracy */
@media (any-pointer: coarse) {
}

/* if user's primary input device includes "any" accurate pointing device */
@media (any-pointer: fine) {
}

/* no pointing device */
@media (any-pointer: none) {
}

/* if user's primary input device includes "any" hoverable device */
@media (any-hover: hover) {
}

/* if user's primary input device doesn't includes "any" hoverable device */
@media (any-hover: none) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Rare Interaction Capabilities&lt;/code&gt; could match multiple queries because it is based on multiple input devices.&lt;br&gt;&lt;br&gt;
For example, The query result of Surface go with tablet pen is below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@media (poiner: fine)&lt;/code&gt;： because of tablet pen&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@media (hover: hover)&lt;/code&gt;： because of tablet pen&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@media (any-pointer: fine)&lt;/code&gt; and &lt;code&gt;@media (any-pointer: coarse)&lt;/code&gt;： because of tablet pen(fine) and touch screen (coarse)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@media (any-hover: hover)&lt;/code&gt; because of tablet pen &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;note: surface tablet pen can hover on elements&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Plz check more detail and full of result of those queries below!!!!&lt;br&gt;&lt;br&gt;
&lt;a href="https://dev.opera.com/articles/media-features/" rel="noopener noreferrer"&gt;Interaction Media Features and their potential&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How can we use it?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@media (pointer: coarse)&lt;/code&gt; It might be better to make buttons bigger to tap easier&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@media (hover: none)&lt;/code&gt; It might be better to make other UI instead of hover one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But those queries don’t consider multiple input device so it could be better to use &lt;code&gt;any-pointer&lt;/code&gt; and &lt;code&gt;any-hover&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
If you want your UI to adapt user’s input device…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@media (any-pointer: coarse)&lt;/code&gt; It might be better to make other UI instead of hover one&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How to query in JavaScript
&lt;/h2&gt;

&lt;p&gt;You can use &lt;a href="https://developer.mozilla.org/ja/docs/Web/API/Window/matchMedia" rel="noopener noreferrer"&gt;matchMedia&lt;/a&gt; too in JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;window.matchMedia("(any-hover: coarse)").matches
// true or false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@media (hover: on-demand)&lt;/code&gt; and &lt;code&gt;@media (any-hover: on-demand)&lt;/code&gt; are old specs so those are deprecated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.chromestatus.com/feature/4719452646014976" rel="noopener noreferrer"&gt;Remove “on-demand” value for hover/any-hover media queries. (removed)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://css-tricks.com/touch-devices-not-judged-size" rel="noopener noreferrer"&gt;Touch Devices Should Not Be Judged By Their Size&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>ux</category>
    </item>
    <item>
      <title>How to control browser keyboard</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Sat, 26 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/tomoyukikashiro/how-to-control-browser-keyboard-1k01</link>
      <guid>https://forem.com/tomoyukikashiro/how-to-control-browser-keyboard-1k01</guid>
      <description>&lt;h2&gt;
  
  
  Control browser keyboard using input[type]
&lt;/h2&gt;

&lt;p&gt;Google explains the way to control browser keyboard for html form using &lt;code&gt;type attribute&lt;/code&gt; in &lt;a href="https://developers.google.com/web/fundamentals/design-and-ux/input/forms"&gt;Create Amazing Forms&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example if you use &lt;code&gt;type="email&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="email"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The keyboard which is customized for typing email address will show.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fwd95Kdh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/586d06662170831a992b8535defdddb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fwd95Kdh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/586d06662170831a992b8535defdddb7.png" alt="The keyboard when you set type=email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But this also has side effects.For example, if you use &lt;code&gt;type="number"&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="number"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;An unexpected element&lt;/code&gt; to support typing number will be shown inside the element and the number you type will be increased and decreased by scrolling when you hover the element.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ApwZ6s86--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/64d68d29a2cc4d2578ae2d522870be57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ApwZ6s86--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/64d68d29a2cc4d2578ae2d522870be57.png" alt="The keyboard when you set type=number"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can reset the former by CSS and reset the latter by JavaScript but you can’t use it easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is inputmode
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode"&gt;Web technology for developers &amp;gt; HTML: Hypertext Markup Language &amp;gt; Global attributes &amp;gt; inputmode&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The inputmode global attribute is an enumerated attribute that hints at the type of data that might be entered by the user while editing the element or its contents. It can have the following values:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;inputmode is a attribute which allow us to control browser keyboard.The value you can set are &lt;code&gt;none, text, decimal, numeric, tel, search, email, url&lt;/code&gt;. Let’s check how these value affect.I checked these browsers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safari - iOS 13 iPhone 8 (simulator)&lt;/li&gt;
&lt;li&gt;Chrome - Android 10 Pixel 3a&lt;/li&gt;
&lt;li&gt;Chrome - windows 10 Surface Go (tablet)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This browser below didn’t support it at this moment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edge - windows 10 Surface Go (table)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  inputmode=none
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" inputmode="none"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The value if you implement own software keyboard will not show system keyboard but…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safari - iOS 13 iPhone 8 (simulator)&lt;/li&gt;
&lt;li&gt;Edge - windows 10 Surface Go (tablet)&lt;/li&gt;
&lt;li&gt;Chrome - windows 10 Surface Go (tablet)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These browsers show system keyboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  inputmode=text
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" inputmode="text"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wcXXV_Fk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/8388776d57016142809a4a111494c17a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wcXXV_Fk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/8388776d57016142809a4a111494c17a.jpg" alt="iOS safari / Android Chrome inputmode=text"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qbGECHS1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/8758184cb340b8c3cb996ad1e20576ae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qbGECHS1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/8758184cb340b8c3cb996ad1e20576ae.png" alt="windows10 Surface Go Chrome inputmode=text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  inputmode=decimal
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" inputmode="decimal"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This value shows keyboard which allow user type decimal easily (not only number but also &lt;code&gt;.&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kBPqLyst--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/223edc350a21f4cc7798df5c2ff30ac7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kBPqLyst--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/223edc350a21f4cc7798df5c2ff30ac7.jpg" alt="iOS safari / Android Chrome inputmode=decimal"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JiFyRB26--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/d857e4c2709295b78e4d124753d4b362.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JiFyRB26--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/d857e4c2709295b78e4d124753d4b362.png" alt="windows10 Surface Go Chrome inputmode=decimal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  inputmode=numeric
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" inputmode="numeric"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Et8W8HMx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/3e573a853ccff69d6a111a339ed307b4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Et8W8HMx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/3e573a853ccff69d6a111a339ed307b4.jpg" alt="iOS safari / Android Chrome inputmode=numeric"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iJLMr_Zz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/d46af0f95db9ba8b167e4d1e55db932d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iJLMr_Zz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/d46af0f95db9ba8b167e4d1e55db932d.png" alt="windows10 Surface Go Chrome inputmode=numeric"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  inputmode=tel
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" inputmode="tel"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This value shows keyboard which allow user type phone number easily such as &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt; and &lt;code&gt;#&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vbYBuDk8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/f40a8006ebeaeb59087c8e4991fe9da9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vbYBuDk8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/f40a8006ebeaeb59087c8e4991fe9da9.jpg" alt="iOS safari / Android Chrome inputmode=tel"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---icmQrbh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/02882b133ef9c06fc2821879a7aa752c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---icmQrbh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/02882b133ef9c06fc2821879a7aa752c.png" alt="windows10 Surface Go Chrome inputmode=tel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  inputmode=search
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" inputmode="search"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kk7aWTd---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/72d39419f81bd977c2a4488308085550.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kk7aWTd---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/72d39419f81bd977c2a4488308085550.jpg" alt="iOS safari / Android Chrome inputmode=search"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6U1U-2NO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/b8046e696c1e4016042045e86384c00b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6U1U-2NO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/b8046e696c1e4016042045e86384c00b.png" alt="windows10 Surface Go Chrome inputmode=search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  inputmode=email
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" inputmode="email"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This value shows keyboard which allow user type email easily such as &lt;code&gt;alphabet&lt;/code&gt; and &lt;code&gt;@&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xoHynntv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/5ee833ea16161619b5dea0325a2835a9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xoHynntv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/5ee833ea16161619b5dea0325a2835a9.jpg" alt="iOS safari / Android Chrome inputmode=email"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9Q6d0-4D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/389f081db6a2125ff5c5dce524862805.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9Q6d0-4D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/389f081db6a2125ff5c5dce524862805.png" alt="windows10 Surface Go Chrome inputmode=email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  inputmode=url
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="text" inputmode="url"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This value shows keyboard which allow user type URL easily such as &lt;code&gt;/&lt;/code&gt; and &lt;code&gt;.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x6BNKvWh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/fe7cf2715d4080256965afeba30949ea.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x6BNKvWh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/fe7cf2715d4080256965afeba30949ea.jpg" alt="iOS safari / Android Chrome inputmode=url"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VkdIS8le--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/2a492b30e0650f302e8dc4780c9fef04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VkdIS8le--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.gyazo.com/2a492b30e0650f302e8dc4780c9fef04.png" alt="windows10 Surface Go Chrome inputmode=url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;p&gt;You can control browser keyboard using &lt;code&gt;inputmode&lt;/code&gt; but this doesn’t mean that you can control the value which user will type.For example, you can show user &lt;code&gt;email specialized keyboard&lt;/code&gt; using &lt;code&gt;inputmode=email&lt;/code&gt; but user can still input &lt;code&gt;email invalid value&lt;/code&gt;.So you need to validate values user input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser Support
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://caniuse.com/#feat=input-inputmode"&gt;https://caniuse.com/#feat=input-inputmode&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://codepen.io/Tkashiro/full/dyyROPJ"&gt;https://codepen.io/Tkashiro/full/dyyROPJ&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>javavscript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>What's new in Chrome DevTools 2019</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Sat, 01 Jun 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/what-s-new-in-chrome-devtools-2019-1emi</link>
      <guid>https://forem.com/t-jindai/what-s-new-in-chrome-devtools-2019-1emi</guid>
      <description>&lt;p&gt;I like &lt;a href="https://www.youtube.com/watch?v=mfuE53x4b3k&amp;amp;list=PLNYkxOF6rcIC4NQeXpdAy0RbOACI66Hvf&amp;amp;index=8&amp;amp;t=0s" rel="noopener noreferrer"&gt;What’s new in Chrome DevTools&lt;/a&gt; session in Google I/O to catch up latest updates!But unfortunately there was not that session in Google I/O 2019… so that I made it by myself !&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Eager Evaluation (v68) [&lt;a href="https://chromedevtools.fun/versions/v68#eager-evaluation" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;There is &lt;code&gt;Eager evaluation&lt;/code&gt; option in Settings in console panel. You can see result before execution if you turn it ON.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mghwdgvgogjp2vne5vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9mghwdgvgogjp2vne5vw.png" alt="image" width="681" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It might be useful when you write regular expression.This feature can be used in Canary version before but now everyone can use it in standard version of Chrome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmq2800n4pwtcon4vu0np.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmq2800n4pwtcon4vu0np.png" alt="image" width="287" height="55"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Argument Hints (v68) [&lt;a href="https://chromedevtools.fun/versions/v68#argument-hints" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;Funcnton parameter hints is shown in console panel while you typing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfohtozc8wujw0kwmyut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfohtozc8wujw0kwmyut.png" alt="image" width="520" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Autocomplete After Invoking Functions (v68) [&lt;a href="https://chromedevtools.fun/versions/v68#autocomplete-after-invoking-functions" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;Autocomplete is shown for function return value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9c73uvynnx50arhywyoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9c73uvynnx50arhywyoy.png" alt="image" width="509" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Live Expressions in the console (v70) [&lt;a href="https://chromedevtools.fun/versions/v70#live-expressions-in-the-console" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;You can set &lt;code&gt;Live Expression&lt;/code&gt; statement in console panel.In this case &lt;code&gt;activeElement&lt;/code&gt; will be change eveytime you change focus element.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiv5bpi5z2jnabmtpd4kn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiv5bpi5z2jnabmtpd4kn.png" alt="image" width="334" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Store DOM nodes as global variables (v71) [&lt;a href="https://chromedevtools.fun/versions/v71#store-dom-nodes-as-global-variables" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;You can set the element as javascript global variable by selecting &lt;code&gt;Store as global variable&lt;/code&gt; in context menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44w9ekrfsq2eg2d69ndg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44w9ekrfsq2eg2d69ndg.png" alt="image" width="442" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The element will be set as &lt;code&gt;temp${N}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ukofqme8mfb88dovsyx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ukofqme8mfb88dovsyx.png" alt="image" width="681" height="104"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Logpoint (v73) [&lt;a href="https://chromedevtools.fun/versions/v73#logpoints" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;Common debugging pattern for Front-end developer is &lt;code&gt;write console.log&lt;/code&gt; -&amp;gt; &lt;code&gt;execute javascript&lt;/code&gt; -&amp;gt; &lt;code&gt;remove console.log&lt;/code&gt;.Now you don’t need to edit code for it!!&lt;/p&gt;

&lt;p&gt;You can put logpoint to statement in source panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofgedb1isu4jkeqcwsw4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofgedb1isu4jkeqcwsw4.png" alt="image" width="352" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsp6x47l3n4jisytl40p0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsp6x47l3n4jisytl40p0.png" alt="image" width="321" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Element
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Detailed tooltips when inspecting nodes (v73) [&lt;a href="https://chromedevtools.fun/versions/v73#detailed-tooltips-when-inspecting-nodes" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;The detail of element is shown when you select it in element panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9sz5i7sq6lpih8tqm3v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9sz5i7sq6lpih8tqm3v.png" alt="image" width="430" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  AAA contrast ratio line in the Color Picker (v73) [&lt;a href="https://chromedevtools.fun/versions/v73#aaa-contrast-ratio-line-in-the-color-picker" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;You can check current &lt;code&gt;Contrast ratio&lt;/code&gt; and recommendation for it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7qc9krl1zb1zh61bcl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7qc9krl1zb1zh61bcl7.png" alt="image" width="463" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can check for more detail about Contrast ratio.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/web/fundamentals/accessibility/accessible-styles#color_and_contrast" rel="noopener noreferrer"&gt;Accessible Styles&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Highlight all nodes affected by CSS property (v74) [&lt;a href="https://chromedevtools.fun/versions/v74#highlight-all-nodes-affected-by-css-property" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;When you edit css property the elements which same css property apply to will be highlighted.The margin in &lt;code&gt;p&lt;/code&gt; elements are highlighted while editing that css property in this case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6f70qenzbt2p0diq0r2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6f70qenzbt2p0diq0r2.png" alt="image" width="577" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Performance metrics in the Timings section (v72) [&lt;a href="https://chromedevtools.fun/versions/v72/#performance-metrics-in-the-timings-section" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;You can check performance metrics such as &lt;code&gt;First Pain&lt;/code&gt;, &lt;code&gt;First Contentful Paint&lt;/code&gt; in Network panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7rg8840sn6ofoxw7u8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7rg8840sn6ofoxw7u8v.png" alt="image" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Long tasks in performance recordings (v74) [&lt;a href="https://chromedevtools.fun/versions/v74#long-tasks-and-first-paint-in-performance-recordings" rel="noopener noreferrer"&gt;watch on youtube&lt;/a&gt;]
&lt;/h3&gt;

&lt;p&gt;You can see &lt;code&gt;Long Task&lt;/code&gt; in Network panel.The tasks have red triangle label at upper right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcyqkrr446htdbos94cn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdcyqkrr446htdbos94cn.png" alt="image" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In the end
&lt;/h2&gt;

&lt;p&gt;There are bunch of updates!Thank you for best effort of ChromeDevtools team!!!!&lt;/p&gt;

&lt;p&gt;I made site where you can check all updates by version basis or feature basis.&lt;/p&gt;

&lt;p&gt;Check it out !!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chromedevtools.fun/" rel="noopener noreferrer"&gt;https://chromedevtools.fun/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqog4rstpt3yd61tq1ei6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqog4rstpt3yd61tq1ei6.png" alt="image" width="800" height="702"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>devtools</category>
      <category>css</category>
      <category>html</category>
    </item>
    <item>
      <title>AMP to PWA for Gatsby</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Sun, 17 Feb 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/amp-to-pwa-for-gatsby-1pn0</link>
      <guid>https://forem.com/t-jindai/amp-to-pwa-for-gatsby-1pn0</guid>
      <description>&lt;p&gt;&lt;strong&gt;This post was originally published at &lt;a href="https://blog.tomoyukikashiro.me/post/amp-to-pwa-for-gatsby" rel="noopener noreferrer"&gt;AMP to PWA for Gatsby&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s AMP to PWA
&lt;/h2&gt;

&lt;p&gt;It’s also known as &lt;a href="https://www.ampproject.org/docs/integration/pwa-amp/amp-to-pwa" rel="noopener noreferrer"&gt;Preload your Progressive Web App from your AMP pages&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A good strategy is to make the entry point into your site an AMP page, then warm up the PWA behind the scenes and switch to it for the onward journey:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For more detail plz check &lt;a href="https://www.ampproject.org/docs/integration/pwa-amp/amp-to-pwa" rel="noopener noreferrer"&gt;AMP official article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goal of this article
&lt;/h2&gt;

&lt;p&gt;I’ll explain how to implement it for blog using Gatsby.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prepare Blog &lt;/li&gt;
&lt;li&gt;Change article path&lt;/li&gt;
&lt;li&gt;Prepare AMP generation&lt;/li&gt;
&lt;li&gt;Add Service Worker installer in AMP for Non-AMP page&lt;/li&gt;
&lt;li&gt;Add AMP validation in Test (optional)&lt;/li&gt;
&lt;li&gt;Build&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prepare Blog
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install -g gatsby-cli
$ gatsby new my-blog-starter https://github.com/gatsbyjs/gatsby-starter-blog
$ cd my-blog-starter/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Change article path
&lt;/h2&gt;

&lt;p&gt;By default, Blog articles locate in root (e.g. &lt;code&gt;/hello-world&lt;/code&gt;, &lt;code&gt;/hi-folks&lt;/code&gt;). We want to publish Non-AMP article and AMP article so let’s separate directories like this.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-AMP : &lt;code&gt;/posts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AMP : &lt;code&gt;/amp/posts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, Change Non-AMP publish path.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change build destination of post at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/c29e8be855a88a1a5b29879e0647d6cb3bd1be89#diff-dab0f592402461060a5ef23fcb717452" rel="noopener noreferrer"&gt;gatsby-node.js&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - Change path in meta tags like &lt;code&gt;canonical&lt;/code&gt; at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/c29e8be855a88a1a5b29879e0647d6cb3bd1be89#diff-8f355b4311b3bd58787dcd954140e366" rel="noopener noreferrer"&gt;src/components/seo.js&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Change link path at contents&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/c29e8be855a88a1a5b29879e0647d6cb3bd1be89#diff-5fb7300a15156cb7af405410a26e9364" rel="noopener noreferrer"&gt;src/pages/index.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/c29e8be855a88a1a5b29879e0647d6cb3bd1be89#diff-7cb5d5854f562d9d4aa64433022ad9da" rel="noopener noreferrer"&gt;src/templates/blog-post.js&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Change path in RSS at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/c29e8be855a88a1a5b29879e0647d6cb3bd1be89#diff-0fbddf38e100e847d3a54e99e91f204b" rel="noopener noreferrer"&gt;gatsby-config.js&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prepare AMP generation
&lt;/h2&gt;

&lt;p&gt;To generate AMP page from HTML I use &lt;a href="https://www.gatsbyjs.org/packages/gatsby-plugin-html2amp/?=amp" rel="noopener noreferrer"&gt;gatsby-plugin-html2amp&lt;/a&gt;. This plugin allow you to generate AMP page using regular HTML so all you have to do is to install it and add configuration !&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install --save gatsby-plugin-html2amp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add configuration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add plugin configuration at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/5126d9cb6f07b71e91478f4e0fdfeec5d4407bd9#diff-0fbddf38e100e847d3a54e99e91f204b" rel="noopener noreferrer"&gt;gatsby-config.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;amphtml&lt;/code&gt; meta tag at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/5126d9cb6f07b71e91478f4e0fdfeec5d4407bd9#diff-8f355b4311b3bd58787dcd954140e366" rel="noopener noreferrer"&gt;src/components/seo.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add Google analytics settings for AMP at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/5126d9cb6f07b71e91478f4e0fdfeec5d4407bd9#diff-5226fffa574632e33a3d3c4d2391a8fd" rel="noopener noreferrer"&gt;static/gaConfig.json&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Add Service Worker installer in AMP for Non-AMP page
&lt;/h2&gt;

&lt;p&gt;This is the most important key point of this strategy. Once user access AMP page this site starts installing service worker to cache resources for Non-AMP page.&lt;/p&gt;

&lt;p&gt;After installation and user clicks link which links to Non-AMP page, the page load instantly because most resources are cached.&lt;a href="https://www.ampproject.org/docs/reference/components/amp-install-serviceworker" rel="noopener noreferrer"&gt;amp-install-serviceworker&lt;/a&gt; is AMP component for that.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;a href="https://www.gatsbyjs.org/packages/gatsby-plugin-html2amp/?=amp" rel="noopener noreferrer"&gt;gatsby-plugin-html2amp&lt;/a&gt; already has integration for it so what you need is to add configuration only !!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make service worker installer page at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/c26c038e71162394118f0e4d4635c1c7d22da76d#diff-7959d8932d44e96d61e4af13cbba1c42" rel="noopener noreferrer"&gt;static/amp-install-serviceworker.html&lt;/a&gt; (new file)&lt;/li&gt;
&lt;li&gt;Add gatsby-plugin-html2amp configuration at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/c26c038e71162394118f0e4d4635c1c7d22da76d#diff-0fbddf38e100e847d3a54e99e91f204b" rel="noopener noreferrer"&gt;gatsby-config.js&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Add AMP validation in Test
&lt;/h2&gt;

&lt;p&gt;This is optional. Let’s add test to check validation for AMP page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install --save-dev amphtml-validator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add test command at &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/pull/1/commits/db59726ff5b1326a1ad5d6a562a96007ccfaa908#diff-10bdf593d5a857c6c669e7974b210504" rel="noopener noreferrer"&gt;pacakge.json&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run test by following command
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build both
&lt;/h2&gt;

&lt;p&gt;Note that gatsby-plugin-html2amp generate AMP in build process only so when you run &lt;code&gt;npm run develop&lt;/code&gt; you can not browse AMP page. When you check Non-AMP and AMP page run following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run build
$ npm run serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sample
&lt;/h2&gt;

&lt;p&gt;I made Sample project &lt;a href="https://github.com/tomoyukikashiro/gatsby-pwamp-blog-samples/tree/master/amp-to-pwa" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>amp</category>
      <category>gatsby</category>
      <category>pwa</category>
    </item>
    <item>
      <title>AMP ⚡ using Gatsby</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Sun, 18 Nov 2018 07:48:04 +0000</pubDate>
      <link>https://forem.com/t-jindai/amp--using-gatsby-4kmo</link>
      <guid>https://forem.com/t-jindai/amp--using-gatsby-4kmo</guid>
      <description>&lt;p&gt;&lt;strong&gt;This post was originally published at &lt;a href="https://blog.tomoyukikashiro.me/post/amp-using-gatsby" rel="noopener noreferrer"&gt;AMP ⚡ using Gatsby&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I created gatsby plugin (called &lt;a href="https://github.com/tomoyukikashiro/gatsby-plugin-html2amp" rel="noopener noreferrer"&gt;gatsby-plugin-html2amp&lt;/a&gt;) for generating AMP (Accelerated Mobile Pages). I try to explain how to use it.&lt;/p&gt;

&lt;p&gt;It’s easy to use 😁&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare Gatsby blog
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install --global gatsby-cli
$ gatsby new gatsby-blog https://github.com/gatsbyjs/gatsby-starter-blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then check the blog&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd gatsby-blog
$ npm start

# Access http://localhost:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Make it AMP !
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add plugin
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install --save gatsby-plugin-html2amp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set plugin configuration to &lt;code&gt;gatsby-config.js&lt;/code&gt; at bottom of file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  resolve: 'gatsby-plugin-html2amp',
  options: {
    files: ['**/*.html'],
    dist: 'public/amp'
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Modify blog post template
&lt;/h3&gt;

&lt;p&gt;To make your post page valid as AMP add &lt;code&gt;canonical&lt;/code&gt; in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;src/templates/blog-post.js&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        author
      }
    }
    markdownRemark(fields: { slug: { eq: $slug } }) {
      id
      excerpt
      html
      fields { // ⚡ Add this fields.slug into Graphql
        slug
      }
      frontmatter {
        title
        date(formatString: "MMMM DD, YYYY")
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then add canonical&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;src/templates/blog-post.js&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Helmet
  htmlAttributes={{ lang: 'en' }}
  meta={[{ name: 'description', content: siteDescription }]}
  title={`${post.frontmatter.title} | ${siteTitle}`}&amp;gt;
  &amp;lt;link rel="canonical" href={`${post.fields.slug}`} /&amp;gt; // ⚡ Add canonical
&amp;lt;/Helmet&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can see AMP source at &lt;code&gt;public/amp&lt;/code&gt; ⚡&lt;/p&gt;

</description>
      <category>react</category>
      <category>gatsby</category>
      <category>amp</category>
    </item>
    <item>
      <title>Do not use Number.toFixed for Rounding</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Sun, 18 Nov 2018 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/do-not-use-numbertofixed-for-rounding-2k41</link>
      <guid>https://forem.com/t-jindai/do-not-use-numbertofixed-for-rounding-2k41</guid>
      <description>&lt;p&gt;This post was originally published at &lt;a href="https://blog.tomoyukikashiro.me/post/do-not-use-number-tofixed-for-rounding" rel="noopener noreferrer"&gt;Do not use Number.toFixed for Rounding&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sometimes I saw Use-case that developer use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed" rel="noopener noreferrer"&gt;Number.prototype.toFixed&lt;/a&gt; for &lt;code&gt;rounding&lt;/code&gt;. But It is not correct in some reasons. I try to explain why it’s not correct. 😥&lt;/p&gt;

&lt;h2&gt;
  
  
  Return String instead of Number/Float
&lt;/h2&gt;

&lt;p&gt;The result of &lt;code&gt;toFixed&lt;/code&gt; is &lt;code&gt;String&lt;/code&gt; so it case unexpected result if you calculate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// What you expect// 1.1 + 1 = 2.1
// Result1.12.toFixed(1) + 1// '1.1' + 1 = '1.11'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Not accurate in one case
&lt;/h2&gt;

&lt;p&gt;You can pass digits option to &lt;code&gt;toFixed([digits])&lt;/code&gt; it means …&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;digits&lt;/p&gt;

&lt;p&gt;Optional. The number of digits to appear after the decimal point; this may be a value between 0 and 20, inclusive, and implementations may optionally support a larger range of values. If this argument is omitted, it is treated as 0.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example you run &lt;code&gt;1.1N.toFixd(1)&lt;/code&gt; the return value would be &lt;code&gt;1.N&lt;/code&gt;.Okay let’s see what’s happened in real world example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.150.toFixed(1) // -&amp;gt; '1.1' expected '1.2' because of rounding
1.15.toFixed(1) // -&amp;gt; '1.1' expected '1.2' because of rounding
1.151.toFixed(1) // -&amp;gt; '1.2'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To rounding the number which next to digits should be greater than 0. 💩&lt;/p&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>How to use Google PageSpeed Test in CI</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Tue, 04 Jul 2017 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/how-to-use-google-pagespeed-test-in-ci-4fkp</link>
      <guid>https://forem.com/t-jindai/how-to-use-google-pagespeed-test-in-ci-4fkp</guid>
      <description>&lt;p&gt;This post was originally published at &lt;a href="https://blog.tomoyukikashiro.me/post/how-to-use-google-pagespeed-test-in-ci" rel="noopener noreferrer"&gt;How to use Google PageSpeed Test in CI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;You know site performance is important for SEO, Conversion but it is difficult to find how to test it continuously. (It was difficult for me…). So I will explain how to set up peformance test in CI using &lt;a href="https://developers.google.com/speed/pagespeed/insights/" rel="noopener noreferrer"&gt;Google PageSpeed Insights&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outline
&lt;/h2&gt;

&lt;p&gt;I will explain continuous performance test settings using Google PageSpeed Insights in Travis CI with heroku. Application I want to test is &lt;a href="https://blog.tomoyukikashiro.me" rel="noopener noreferrer"&gt;this blog&lt;/a&gt; which is generated by &lt;a href="https://blog.getpelican.com/" rel="noopener noreferrer"&gt;Pelican&lt;/a&gt; so the application is totally static site (no need DB and server side program).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heroku app&lt;/li&gt;
&lt;li&gt;Travis CI connected with github repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basic flow is below.&lt;/p&gt;

&lt;h2&gt;
  
  
  - 1 Make PR in github repository
&lt;/h2&gt;

&lt;p&gt;2 Start test process in Travis CI&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 Install depandencies&lt;/li&gt;
&lt;li&gt;2 Build application&lt;/li&gt;
&lt;li&gt;3 Push built application to heroku&lt;/li&gt;
&lt;li&gt;4 Run Google Page Insight test &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prepare heroku
&lt;/h2&gt;

&lt;p&gt;First step is setup heroku for test the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir ${app_name}
$ cd ${app_name}
$ git init
$ heroku apps:create ${app_name}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;a href="http://blog.teamtreehouse.com/deploy-static-site-heroku" rel="noopener noreferrer"&gt;article&lt;/a&gt; could be good reference to make static server on heroku !&lt;/p&gt;

&lt;h2&gt;
  
  
  Edit CI settings
&lt;/h2&gt;

&lt;p&gt;Second step is setup travis CI. You can see travis CI settings for repository like below.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/%24%7Baccount_name%7D/%24%7Brepository_name%7D/settings" rel="noopener noreferrer"&gt;https://travis-ci.org/${account_name}/${repository_name}/settings&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You need those settings in &lt;code&gt;Environment Variables&lt;/code&gt; section.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HEROKU_API_KEY&lt;/li&gt;
&lt;li&gt;TEST_SITE_GIT_REMOTE&lt;/li&gt;
&lt;li&gt;TEST_SITE_URL
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqy8m2w7ycf3semfeo0r6.png" alt="travis settings screen" width="800" height="175"&gt;
### HEROKU_API_KEY&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Heroku app is git repository and it’s private so to clone it in travis server you need this token. You can see it thru this command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bash&lt;br&gt;
$ heroku auth:token&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  TEST_SITE_GIT_REMOTE
&lt;/h3&gt;

&lt;p&gt;heroku app git url. git protocol would be better &lt;code&gt;git@heroku.com:${app_name}.git&lt;/code&gt; instead of https protocol not to be asked id/password everytime.&lt;/p&gt;
&lt;h3&gt;
  
  
  TEST_SITE_URL
&lt;/h3&gt;

&lt;p&gt;heroku app url to test.&lt;/p&gt;
&lt;h2&gt;
  
  
  Edit CI tasks
&lt;/h2&gt;

&lt;p&gt;Basic &lt;code&gt;travis.yml&lt;/code&gt; is here. You need replace &lt;code&gt;${your install process here}&lt;/code&gt; and &lt;code&gt;${your build process here}&lt;/code&gt; for your application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo: required
language: node_js
node_js:
  - "7"
install:
  - ${your install process here}
  - npm install
  - scripts/setup_heroku.sh
  - git clone $TEST_SITE_GIT_REMOTE output
before_script:
  - ${your build process here}
  - cd output &amp;amp;&amp;amp; git add --ignore-removal . &amp;amp;&amp;amp; git commit -m 'deploy for test' &amp;amp;&amp;amp; git push origin master -f &amp;amp;&amp;amp; cd -
script:
  - npm test $TEST_SITE_URL
after_script:
  - heroku keys:clear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  setup_heroku.sh
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/tomoyukikashiro/blog.tomoyukikashiro.me/blob/master/scripts/setup_heroku.sh" rel="noopener noreferrer"&gt;setup_heroku.sh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This script add &lt;code&gt;ssh private key&lt;/code&gt; to heroku to clone repository thu heroku CLI.&lt;/p&gt;

&lt;p&gt;I use nodejs heroku command which &lt;a href="https://devcenter.heroku.com/articles/heroku-cli#npm-version" rel="noopener noreferrer"&gt;is not recommended&lt;/a&gt; by heroku because I could not install other installation methods… If you have idea let me know!&lt;/p&gt;

&lt;h3&gt;
  
  
  npm test $TEST_SITE_URL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"devDependencies": {
    "psi": "^3.0.0"
  }, 
  "scripts": {
    "test": "npm run test_psi",
    "test_psi": "psi --strategy mobile"
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/addyosmani/psi" rel="noopener noreferrer"&gt;psi&lt;/a&gt; is npm module to do Google pageSpeed Insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;You can check example here &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftomoyukikashiro%2Fblog.tomoyukikashiro.me" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftomoyukikashiro%2Fblog.tomoyukikashiro.me" alt="https://github.com/tomoyukikashiro/blog.tomoyukikashiro.me" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me know if you have question !!&lt;/p&gt;

</description>
      <category>ci</category>
      <category>psi</category>
      <category>performance</category>
    </item>
    <item>
      <title>Add ticket number to git commit automatically</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Mon, 09 Jan 2017 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/add-ticket-number-to-git-commit-automatically-4fgh</link>
      <guid>https://forem.com/t-jindai/add-ticket-number-to-git-commit-automatically-4fgh</guid>
      <description>&lt;p&gt;This post was originally published at &lt;a href="https://blog.tomoyukikashiro.me/post/add-ticket-number-to-git-commit-automatically" rel="noopener noreferrer"&gt;Add ticket number to git commit automatically&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most of ticket tracker like Github, pivotal tracker have function to connect your commit to ticket(story). But every time when you commit copy and paste that of ticket number is annoy…&lt;/p&gt;

&lt;p&gt;So I created a script using git hook to add ticket number to your commit automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir -p ~/.git-templates/hooks
$ touch ~/.git-templates/hooks/prepare-commit-msg
$ chmod u+x ~/.git-templates/hooks/prepare-commit-msg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can copy &amp;amp; paste this script to &lt;code&gt;prepare-commit-msg&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/sh

LF=$'\\\x0A'
BRANCH_NAME=$(git symbolic-ref --short HEAD)

if [[$BRANCH_NAME =~ .*\/[0-9]* ]]; then
  PREFIX=$(echo $BRANCH_NAME | sed -e 's/\(.*\)\/\([0-9]*\)/\1/')
  NUMBER=$(echo $BRANCH_NAME | sed -e 's/\(.*\)\/\([0-9]*\)/\2/')
  if [$PREFIX = 'story']; then
      MESSAGE="[#$NUMBER]"
  else
      MESSAGE="GH-$NUMBER"
  fi
  if [$NUMBER]; then
    sed -i.back "1s/^/$LF$LF$MESSAGE$LF/" "$1"
  fi
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;To enable this script run this command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git config core.hooksPath ~/.git-templates/hooks/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;This script expects that your branch is named using this format&lt;/p&gt;

&lt;h3&gt;
  
  
  Pivotal Tracker
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;story/1111
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Github
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;issue/1111
fix/1111
feature/1111
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When every time you commit script add that number using this format to you commit !!&lt;/p&gt;

&lt;h3&gt;
  
  
  Pivotal Tracker
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[#1111]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Github
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GH-1111
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
    </item>
    <item>
      <title>Things to be aware of when change Capybara default_wait_time</title>
      <dc:creator>Tomoyuki Kashiro</dc:creator>
      <pubDate>Thu, 14 May 2015 00:00:00 +0000</pubDate>
      <link>https://forem.com/t-jindai/things-to-be-aware-of-when-change-capybara-defaultwaittime-3jh6</link>
      <guid>https://forem.com/t-jindai/things-to-be-aware-of-when-change-capybara-defaultwaittime-3jh6</guid>
      <description>&lt;p&gt;This post was originally published at &lt;a href="https://blog.tomoyukikashiro.me/post/things-to-be-aware-of-when-change-capybara_default_wait_time" rel="noopener noreferrer"&gt;Things to be aware of when change Capybara default_wait_time&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  About &lt;code&gt;Capybara.default_wait_time&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;According to &lt;a href="http://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Finders#find-instance_method" rel="noopener noreferrer"&gt;api document&lt;/a&gt;…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;find will wait for a set amount of time and continuously retry finding the element until either the element is found or the time expires. The length of time find will wait is controlled through Capybara.default_wait_time and defaults to 2 seconds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ATTENTION
&lt;/h2&gt;

&lt;p&gt;You had better not set much time to &lt;code&gt;Capybara_default_wait_time&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if you set 10 seconds to &lt;code&gt;Capybara.default_wait_time&lt;/code&gt; when you want to check the element dose not exist. Test time can be long. Because Capybara wait to check the element dose not exist in each test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# in rspec.rb
Capybara.default_wait_time = 10

# in feature test
expect(page).to have_no_selector(:css, "p a#doesnotexist") # wait 10 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;If you need more than 2 seconds(default value in Capybara.default_wait_time) to wait to check you can set &lt;code&gt;wait&lt;/code&gt; option to find instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expect(page).to have_selector(:css, "p a#doesnotexist", wait: 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>capybara</category>
      <category>test</category>
      <category>rails</category>
    </item>
  </channel>
</rss>
