- 投稿日:2020-02-05T23:42:44+09:00
【動画付き】Next.js の Server Side Rendering (SSR) を理解する。create-react-app と比べてみた。
Next.jsのサイト、かっこいいですよね ?
クールで、パフォーマンスにも優れていてエンジニアを魅了します。
日本では Nuxt.js が人気のようですが、個人的には Next.js を推しています。さて、先日 Next.js のチュートリアル を通してサーバサイドレンダリングについて考えさせられる機会がありました。本記事では、そもそもサーバサイドレンダリングのメリットとは?というところから初めて、
create-react-app
によって実装された SPA と、next
によって実装された SSR ではどのような違いがあるのかを検証してみました。以下の動画は本記事のサマリーです。
作成したアプリケーションへのリンクも貼っておきます。
右の方がちょっとだけ描画が遅いのがわかりますね。?(左)next.js で SSR、(右)create-react-app で SPA ?
サーバサイドレンダリング(SSR)とは
従来の React ベースのアプリケーションの構成を振り返ってみましょう(右図)。この構成の場合、ユーザからのリクエストは、まずはじめに React サーバ(S3 や Netlify)から JavaScript のソースと必要最小限のほとんど空っぽな HTML を返します。それからフロントエンドで HTML 要素をレンダリングする方法をとります。
このようにバックエンド API とフロントエンドの描画を完全に分離する事によって、開発体制を分離した生産性向上や、ユーザに優れた UX を提供できるようになりました。
その一方で、過度なネットワーク通信が発生したり、JavaScript によって生成された Web サイトを検索エンジンのクローラが検知できなくなりました。その結果として、Google の検索項目の上位に自サイトが表示されにくいなどのデメリットも招いてしました。※こちらの記事で紹介されていますが、最近ではあまり問題にならなくなっているようです。さて、このような問題を解消するためのテクニックがサーバサイドレンダリング(ServerSideRendering)です(左図)。サーバサイドレンダリングは従来フロントエンドで行なっていたレンダリングをバックエンドの Node.js サーバにも移譲しようという考え方です。これにより、モバイル端末がどんなに脆弱でも、ハイパフォーマンスなサーバを使用してレンダリングできます。さらに無駄なネットワーク通信回数も最小限に減らせるでしょう。「バックエンドの Node.js サーバにも」と強調しているのは、フロントエンドでももちろん描画ができる、ということです。初期ページの一部だけはサーバサイドでレンダリングして、残りの要素はフロントエンドからフェッチしてきてレンダリングするといったように用途に応じて使い分けができます。
パフォーマンス
遅いデバイスを使用していると、最初のページのレンダリングに時間がかかり、ユーザ体験が低下します。計算をより強力なサーバーにオフロードすることで、ユーザーが待機する時間を最小限に抑えることができます。
また、サーバーで初期データをプリフェッチしてページを構築すると、サイトを表示するために必要なラウンドトリップの回数が大幅に削減されます。これにより、待ち時間の短縮と帯域幅消費の削減につながります。SEO 対策
SSR を行なっているサイトは、ページが検索エンジンで簡単にインデックス化されます。クライアント側でルーティング制御を行なっていると、検索エンジンのウェブクロールを遅らせてしまいます。この結果、検索エンジンの上位にリンクを表示することが難しくなります。
Next.js ことはじめ
SSR を理解するために必要最小限の構成で Next.js アプリケーションを組み立てていきます。
必要なライブラリとアプリケーションの実行
$ mkdir next.ssr $ cd next.ssr $ yarn init -yNext.js を最小構成で始めるために必要なライブラリは
next
とreact
,react-dom
だけです。早速yarn
でインストールしましょう(npm
でもよいですよ)$ yarn add react react-dom next
package.json
には以下のnpm scripts
を記載しておいて開発を楽に進められるようにしておきましょう。package.json"scripts": { "dev": "next", "build": "next build", "start": "next start" }それぞれのコマンドは以下のように使用します。
- dev - ローカルでアプリケーションを起動します。
- build - プロダクション用にアプリケーションをビルドします。
- start - プロダクション環境でアプリケーションを実行します。
ルーティング
Next.js は非常にシンプルな設計思想でフロント画面が作れるように構成されています。
/pages
ディレクトリ配下に配置されている js ファイルごとにパスルーティングが行われます。はじめの一歩として/pages/index.js
にファイルを配置して、/
という URL で表示できるようにしてみましょう。詳細なドキュメントはこちら$ mkdir pages $ touch pages/index.jspages/index.jsconst Index = () => { return <h1>Hello World</h1>; }; export default Index;ファイルパスと URL パスには以下のような対応関係があります。
ファイルパス URL パス pages/index.js / pages/blog/index.js /blog pages/blog/first-post.js /blog/first-post pages/dashboard/settings/username.js /dashboard/settings/username pages/blog/[slug].js /blog/:slug (/blog/hello-world) pages/[username]/settings.js /:username/settings (/foo/settings) pages/post/[...all].js /post/* (/post/2020/id/title) さて、ここまでできれば準備完了です。アプリケーションを起動してみましょう。
$ yarn devブラウザを起動し、
/
にアクセスすると画面が表示されるはずです。サーバサイドレンダリングの実装
ここから SSR ができるような機能を作っていきましょう。
<Link>
コンポートを使用して、他ページに遷移します。以下の例だと/shows/[id]
へ遷移させようとしています。また、Next.js には、ページのデータを取得するための標準 API が付属しています。getInitialProps
という非同期関数を使用して実行します。
getInitialProps
を使用すると、特定のページのデータをフェッチしてページに渡すことができます。getInitialProps
はサーバーとクライアントの両方で動作します。
このgetInitialProps
の振る舞いを観測し、SSR を理解していきましょう。index.jsimport Link from "next/link"; import fetch from "isomorphic-unfetch"; const Index = props => ( <div> <h1>Batman TV Shows</h1> <ul> {props.shows.map(show => ( <li key={show.id}> <Link href="/shows/[id]" as={`/shows/${show.id}`}> <a>{show.name}</a> </Link> </li> ))} </ul> </div> ); Index.getInitialProps = async function() { const res = await fetch("https://api.tvmaze.com/search/shows?q=batman"); const data = await res.json(); console.log(`Show data fetched. Count: ${data.length}`); return { shows: data.map(entry => entry.show) }; }; export default Index;
pages
配下に/shows/[id].js
を配置し、Dynamic Routing ができるようにしておきます。pages/[id].jsimport fetch from "isomorphic-unfetch"; const Post = props => ( <div> <h1>{props.show.name}</h1> <p>{props.show.summary.replace(/<[/]?[pb]>/g, "")}</p> {props.show.image ? <img src={props.show.image.medium} /> : null} </div> ); Post.getInitialProps = async function(context) { const { id } = context.query; const res = await fetch(`https://api.tvmaze.com/shows/${id}`); const show = await res.json(); console.log(`Fetched show: ${show.name}`); return { show }; }; export default Post;
/
を表示してみましょう。サーバサイドにログShow data fetched: 10
が表示されるはずです。index.js
をサーバサイドでレンダリングしたという事になりますね。
次にリンクをクリックして/shows/975
に遷移するとブラウザのコンソールにログが表示されてます。これはフロントエンドでデータフェッチとレンダリングが行われたということを意味しています。デプロイ
最後にビルドして、デプロイします。ZEIT の now にデプロイします。素晴らしい DX(DeveloperExperimence)です。本当に必要な要素以外全て削ぎ落とした、最高の PaaS だと思ってます。いつも愛用しています。こちらの記事にて丁寧に解説されていました。
bash$ yarn build # ビルド $ now # デプロイデプロイしたら動作を確認してパフォーマンスを検証しましょう。Chrome の開発者コンソールを開き、Audit を実行します。
https://batman-tv-shows.geeawa.now.sh/
First Meaningful Paint が 1.0s とでました。まずまずです。
create-react-app との比較
ここまでできたので Next.js で作成されたアプリケーションと
create-react-app
で作成されたアプリケーションを比較してみましょう。以下のようにほぼ同様のソースを使用して、
create-react-app
アプリケーションを作成します。以下にデプロイしてあります。https://badman-tv-shows-create-react-app.now.sh/
index.jsimport React from "react"; import fetch from "isomorphic-unfetch"; class Index extends React.Component { constructor(props) { super(props); this.state = { shows: [] }; } async componentDidMount() { const res = await fetch("https://api.tvmaze.com/search/shows?q=batman"); const data = await res.json(); console.log(`Show data fetched. Count: ${data.length}`); this.setState({ shows: data.map(entry => entry.show) }); } render() { return ( <div> <h1>Batman TV Shows</h1> <ul> {this.state.shows.map(show => ( <li key={show.id}> <a href="">{show.name}</a> </li> ))} </ul> </div> ); } } export default Index;デプロイができたので Audit を実行します。
First Meaningful Paint は 1.4s となり、Next.js によって SSR できるようになったサイトと比較すると少しだけ遅い結果がでました。さいごに
今回作成されたアプリケーションは非常にシンプルで、1つの API しか実行しませんし、レンダリングする DOM 要素も少なかったためパフォーマンスにそれほど大きな違いはみられませんでした。それでもアプリケーションが肥大したり、ネットワークの遅い環境、古くて脆弱なモバイルデバイスを使用するとパフォーマンスの違いは顕著になってくるでしょう。SSR の技術は適材適所を見極めて投下していきたいですね。
- 投稿日:2020-02-05T23:42:44+09:00
【比較検証】Next.js の Server Side Rendering (SSR) を理解する。create-react-app と比べてみた。
Next.jsのサイト、かっこいいですよね ?
クールで、パフォーマンスにも優れていてエンジニアを魅了します。
日本では Nuxt.js が人気のようですが、個人的には Next.js を推しています。さて、先日 Next.js のチュートリアル を通してサーバサイドレンダリングについて考えさせられる機会がありました。本記事では、そもそもサーバサイドレンダリングのメリットとは?というところから初めて、
create-react-app
によって実装された SPA と、next
によって実装された SSR ではどのような違いがあるのかを検証してみました。以下の動画は本記事のサマリーです。
作成したアプリケーションへのリンクも貼っておきます。
右の方がちょっとだけ描画が遅いのがわかりますね。?(左)next.js で SSR、(右)create-react-app で SPA ?
サーバサイドレンダリング(SSR)とは
従来の React ベースのアプリケーションの構成を振り返ってみましょう(右図)。この構成の場合、ユーザからのリクエストは、まずはじめに React サーバ(S3 や Netlify)から JavaScript のソースと必要最小限のほとんど空っぽな HTML を返します。それからフロントエンドで HTML 要素をレンダリングする方法をとります。
このようにバックエンド API とフロントエンドの描画を完全に分離する事によって、開発体制を分離した生産性向上や、ユーザに優れた UX を提供できるようになりました。
その一方で、過度なネットワーク通信が発生したり、JavaScript によって生成された Web サイトを検索エンジンのクローラが検知できなくなりました。その結果として、Google の検索項目の上位に自サイトが表示されにくいなどのデメリットも招いてしました。※こちらの記事で紹介されていますが、最近ではあまり問題にならなくなっているようです。さて、このような問題を解消するためのテクニックがサーバサイドレンダリング(ServerSideRendering)です(左図)。サーバサイドレンダリングは従来フロントエンドで行なっていたレンダリングをバックエンドの Node.js サーバにも移譲しようという考え方です。これにより、モバイル端末がどんなに脆弱でも、ハイパフォーマンスなサーバを使用してレンダリングできます。さらに無駄なネットワーク通信回数も最小限に減らせるでしょう。「バックエンドの Node.js サーバにも」と強調しているのは、フロントエンドでももちろん描画ができる、ということです。初期ページの一部だけはサーバサイドでレンダリングして、残りの要素はフロントエンドからフェッチしてきてレンダリングするといったように用途に応じて使い分けができます。
パフォーマンス
遅いデバイスを使用していると、最初のページのレンダリングに時間がかかり、ユーザ体験が低下します。計算をより強力なサーバーにオフロードすることで、ユーザーが待機する時間を最小限に抑えることができます。
また、サーバーで初期データをプリフェッチしてページを構築すると、サイトを表示するために必要なラウンドトリップの回数が大幅に削減されます。これにより、待ち時間の短縮と帯域幅消費の削減につながります。SEO 対策
SSR を行なっているサイトは、ページが検索エンジンで簡単にインデックス化されます。クライアント側でルーティング制御を行なっていると、検索エンジンのウェブクロールを遅らせてしまいます。この結果、検索エンジンの上位にリンクを表示することが難しくなります。
Next.js ことはじめ
SSR を理解するために必要最小限の構成で Next.js アプリケーションを組み立てていきます。
必要なライブラリとアプリケーションの実行
$ mkdir next.ssr $ cd next.ssr $ yarn init -yNext.js を最小構成で始めるために必要なライブラリは
next
とreact
,react-dom
だけです。早速yarn
でインストールしましょう(npm
でもよいですよ)$ yarn add react react-dom next
package.json
には以下のnpm scripts
を記載しておいて開発を楽に進められるようにしておきましょう。package.json"scripts": { "dev": "next", "build": "next build", "start": "next start" }それぞれのコマンドは以下のように使用します。
- dev - ローカルでアプリケーションを起動します。
- build - プロダクション用にアプリケーションをビルドします。
- start - プロダクション環境でアプリケーションを実行します。
ルーティング
Next.js は非常にシンプルな設計思想でフロント画面が作れるように構成されています。
/pages
ディレクトリ配下に配置されている js ファイルごとにパスルーティングが行われます。はじめの一歩として/pages/index.js
にファイルを配置して、/
という URL で表示できるようにしてみましょう。詳細なドキュメントはこちら$ mkdir pages $ touch pages/index.jspages/index.jsconst Index = () => { return <h1>Hello World</h1>; }; export default Index;ファイルパスと URL パスには以下のような対応関係があります。
ファイルパス URL パス pages/index.js / pages/blog/index.js /blog pages/blog/first-post.js /blog/first-post pages/dashboard/settings/username.js /dashboard/settings/username pages/blog/[slug].js /blog/:slug (/blog/hello-world) pages/[username]/settings.js /:username/settings (/foo/settings) pages/post/[...all].js /post/* (/post/2020/id/title) さて、ここまでできれば準備完了です。アプリケーションを起動してみましょう。
$ yarn devブラウザを起動し、
/
にアクセスすると画面が表示されるはずです。サーバサイドレンダリングの実装
ここから SSR ができるような機能を作っていきましょう。
<Link>
コンポートを使用して、他ページに遷移します。以下の例だと/shows/[id]
へ遷移させようとしています。また、Next.js には、ページのデータを取得するための標準 API が付属しています。getInitialProps
という非同期関数を使用して実行します。
getInitialProps
を使用すると、特定のページのデータをフェッチしてページに渡すことができます。getInitialProps
はサーバーとクライアントの両方で動作します。
このgetInitialProps
の振る舞いを観測し、SSR を理解していきましょう。index.jsimport Link from "next/link"; import fetch from "isomorphic-unfetch"; const Index = props => ( <div> <h1>Batman TV Shows</h1> <ul> {props.shows.map(show => ( <li key={show.id}> <Link href="/shows/[id]" as={`/shows/${show.id}`}> <a>{show.name}</a> </Link> </li> ))} </ul> </div> ); Index.getInitialProps = async function() { const res = await fetch("https://api.tvmaze.com/search/shows?q=batman"); const data = await res.json(); console.log(`Show data fetched. Count: ${data.length}`); return { shows: data.map(entry => entry.show) }; }; export default Index;
pages
配下に/shows/[id].js
を配置し、Dynamic Routing ができるようにしておきます。pages/[id].jsimport fetch from "isomorphic-unfetch"; const Post = props => ( <div> <h1>{props.show.name}</h1> <p>{props.show.summary.replace(/<[/]?[pb]>/g, "")}</p> {props.show.image ? <img src={props.show.image.medium} /> : null} </div> ); Post.getInitialProps = async function(context) { const { id } = context.query; const res = await fetch(`https://api.tvmaze.com/shows/${id}`); const show = await res.json(); console.log(`Fetched show: ${show.name}`); return { show }; }; export default Post;
/
を表示してみましょう。サーバサイドにログShow data fetched: 10
が表示されるはずです。index.js
をサーバサイドでレンダリングしたという事になりますね。
次にリンクをクリックして/shows/975
に遷移するとブラウザのコンソールにログが表示されてます。これはフロントエンドでデータフェッチとレンダリングが行われたということを意味しています。デプロイ
最後にビルドして、デプロイします。ZEIT の now にデプロイします。素晴らしい DX(DeveloperExperimence)です。本当に必要な要素以外全て削ぎ落とした、最高の PaaS だと思ってます。いつも愛用しています。こちらの記事にて丁寧に解説されていました。
bash$ yarn build # ビルド $ now # デプロイデプロイしたら動作を確認してパフォーマンスを検証しましょう。Chrome の開発者コンソールを開き、Audit を実行します。
https://batman-tv-shows.geeawa.now.sh/
First Meaningful Paint が 1.0s とでました。まずまずです。
create-react-app との比較
ここまでできたので Next.js で作成されたアプリケーションと
create-react-app
で作成されたアプリケーションを比較してみましょう。以下のようにほぼ同様のソースを使用して、
create-react-app
アプリケーションを作成します。以下にデプロイしてあります。https://badman-tv-shows-create-react-app.now.sh/
index.jsimport React from "react"; import fetch from "isomorphic-unfetch"; class Index extends React.Component { constructor(props) { super(props); this.state = { shows: [] }; } async componentDidMount() { const res = await fetch("https://api.tvmaze.com/search/shows?q=batman"); const data = await res.json(); console.log(`Show data fetched. Count: ${data.length}`); this.setState({ shows: data.map(entry => entry.show) }); } render() { return ( <div> <h1>Batman TV Shows</h1> <ul> {this.state.shows.map(show => ( <li key={show.id}> <a href="">{show.name}</a> </li> ))} </ul> </div> ); } } export default Index;デプロイができたので Audit を実行します。
First Meaningful Paint は 1.4s となり、Next.js によって SSR できるようになったサイトと比較すると少しだけ遅い結果がでました。さいごに
今回作成されたアプリケーションは非常にシンプルで、1つの API しか実行しませんし、レンダリングする DOM 要素も少なかったためパフォーマンスにそれほど大きな違いはみられませんでした。それでもアプリケーションが肥大したり、ネットワークの遅い環境、古くて脆弱なモバイルデバイスを使用するとパフォーマンスの違いは顕著になってくるでしょう。SSR の技術は適材適所を見極めて投下していきたいですね。
- 投稿日:2020-02-05T22:31:59+09:00
Next.jsでCSSを読み込む方法
Next.jsでCSSを読み込むときは、Headを定義しlinkタグにて読み込む
以下のような感じ
linkタグで読み込めばOKimport React from "react"; import Header from "../includes/header"; import Head from "next/head"; const MainLayout = props => { return ( <> <Head> <title>My Awesome app</title> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" /> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" /> <link href="#" rel="stylesheet" /> </Head> <Header /> {props.children} </> ); }; export default MainLayout;
- 投稿日:2020-02-05T18:50:41+09:00
[React]テーブルのセルを結合する
概要
- Reactで配列をループさせてテーブルを描画する
- 特定の項目についてセルを結合させたい
作成イメージ
- 共通する項目についてセルを結合する
調べたこと
<table border="3"> <tr> <td rowspan="3">垂直方向の結合</td> <td>データ1</td> </tr> <tr> <td>データ2</td> </tr> <tr> <td>データ3</td> </tr> </table>実装
- 表示する配列
src/constants/GroupList.jsimport { nogizaka, keyakizaka, hinatazaka } from "./Color"; const groupList = [ { id: 1, name: "乃木坂46", color: nogizaka.color, memberList: [ { id: 1, name: "齋藤飛鳥", age: 21 } ] }, { id: 2, name: "欅坂46", color: keyakizaka.color, memberList: [ { id: 1, name: "渡邉理佐", age: 21 }, { id: 2, name: "小林由依", age: 20 } ] }, { id: 3, name: "日向坂46", color: hinatazaka.color, memberList: [ { id: 1, name: "齊藤京子", age: 22 }, { id: 2, name: "小坂菜緒", age: 17 }, { id: 3, name: "上村ひなの", age: 15 } ] } ]; export default groupList;
- 表示するコンポーネント
src/App.jsimport React from "react"; import { Table } from "react-bootstrap"; import styled from "styled-components"; import groupList from "./constants/GroupList"; const ColorTr = styled.tr` color: ${({ color }) => color}; `; function App() { return ( <Table bordered> <thead> <tr> <th>グループ</th> <th>名前</th> <th>年齢</th> </tr> </thead> <tbody> {groupList.map(group => group.memberList.map((member, i) => i === 0 ? ( <ColorTr key={member.id} color={group.color}> <td rowSpan={group.memberList.length}>{group.name}</td> <td>{member.name}</td> <td>{member.age}</td> </ColorTr> ) : ( <ColorTr key={member.id} color={group.color}> <td>{member.name}</td> <td>{member.age}</td> </ColorTr> ) ) )} </tbody> </Table> ); } export default App;行ったこと
- 配列の個数を結合させる行数として
rowspan
の値に設定src/App.js<td rowSpan={group.memberList.length}>{group.name}</td>
- ループさせる配列のインデックスをとり、先頭行の場合(インデックスが0の場合)とそうでない場合を分岐
src/App.js{groupList.map(group => group.memberList.map((member, i) => i === 0 ? ( <ColorTr key={member.id} color={group.color}> <td rowSpan={group.memberList.length}>{group.name}</td> // 省略 </ColorTr> ) : ( // 省略 ) ) )}終わりに
- とりあえず実現してみたけど何だか冗長・・・
- もっと良い方法をご存知の方いましたらコメントください
余談
本題とは全く関係ありませんが、今回使用したカラーコードはそれぞれ以下を参考にしています。
- 投稿日:2020-02-05T17:21:26+09:00
React 360でも正規表現を直さないとエラーになります。
先日、この記事を自分用に記載してシェアした訳ですが、
https://qiita.com/Camity/items/f54fdee02d49ca3aa9cdReact VRではなく、最新のReact 360で同様の動作を試してみましたが、
やはり手続き通りにやると同様のエラーが出ました。下記がReact 360で参照した記事。
https://qiita.com/yushimatenjin/items/870c2b8c965489884571因みに動作環境は前回と同様Windouwsです。
要するに正規表現の記述が異なる為にエラーが出ます。An error occurred during the packager process. Exited with code 1.
Look at the packager output above to see what went wrong.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! プロジェクト名@0.0.1 start:node node_modules/react-360/scripts/packager.js
npm ERR! Exit status 1
~直すべきファイルの存在する場所は、
C:\~\React360のプロジェクト名\node_modules\metro\src
の下にblacklist.jsというファイルがあるので、その中のvar sharedBlacklistから始まる該当部分を直せば動きます。もしも、また仕様が変わって、上記のパスにも存在しない場合は、プロジェクト内をblacklist.jsで検索をかけてみると該当ファイルがあると思います。
記述を直す前に一応、コピーを取る事をお勧めします。var sharedBlacklist = [
/node_modules[/\]react[/\]dist[/\].*/,/website\/node_modules\/.*/,
/heapCapture\/bundle.js/,
/.\/tests\/./];
↓↓↓↓↓↓↓↓
var sharedBlacklist = [
/node_modules[\/\]react[\/\]dist[\/\].*/,/website\/node_modules\/.*/,
/heapCapture\/bundle.js/,
/.\/tests\/./];
因みに参照した記事のyarnはインストールをしてないと使えませんので、
npm startとかでnpmで代用できます。yarnとはに関しては下記参照
https://qiita.com/lelouch99v/items/c97ff951ca31298f3f24まだ、XRの分野は新しい分野なのかこの手のエラーというか手直しの部分は多いのかもしれません。
みんなが簡単に出来るように、React360に関しても体系的な知識を自分のサイトにいずれまとめる予定です。
- 投稿日:2020-02-05T16:49:29+09:00
【React】Font Awesomeを導入するメモ
React.jsのアプリケーションにFont Awesomeを導入する際にいつも忘れて一から調べているので備忘録を残します。
言語はTypeScriptを使ってますのでJavaScriptの方は適宜読み替えてください。対象
- Reactアプリ(not React Native)
- Font Awesome無料版(有料版は使ったことないのでわからない)
パッケージ
インストール必須なもの
npm install @fortawesome/react-fontawesome npm install @fortawesome/fontawesome-svg-core使用するアイコンによってインストールするもの
npm install @fortawesome/free-brands-svg-icons npm install @fortawesome/free-regular-svg-icons npm install @fortawesome/free-solid-svg-iconsどのパッケージをインストールするかは、下の画像の赤枠で判断できます。
使いたいアイコンをFont Awesomeで調べてください。
使い方
@fortawesome/react-fontawesome
からFontAwesomeIcon
をimport
。
使いたいアイコンの定義を@fortawesome/free-brands-svg-icons
などからimport
して、FontAwesomeIcon
のicon
プロパティに渡します。import React from 'react'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faTwitter } from "@fortawesome/free-brands-svg-icons"; import { faCalendar } from "@fortawesome/free-regular-svg-icons"; import { faCoffee } from "@fortawesome/free-solid-svg-icons"; const App: React.FC = () => { const iconStyle: React.CSSProperties = { padding: 10, fontSize: 50 }; return ( <div style={{ textAlign: "center", padding: 50 }}> <FontAwesomeIcon style={iconStyle} icon={faTwitter} /> <FontAwesomeIcon style={iconStyle} icon={faCalendar} /> <FontAwesomeIcon style={iconStyle} icon={faCoffee} /> </div> ); }おしまい。
- 投稿日:2020-02-05T13:49:37+09:00
NextJS(Typescript)の環境に ESLINT/Prettier をツッコミ CircleCI の設定に追加する
NextJS(Typescript)の環境に ESLINT/Prettier をツッコミ CircleCI の設定に追加する
tslint を利用しようと思いましたが、2019 年に ESLINT に統一するようになるよって話があるのでhttps://github.com/palantir/tslint/issues/4534ESLINT に変更して作成します。
今回のレポですが、環境作成の準備段階として、
- NextJS(Typescript)を now にデプロイする
- Next.jsではじめるTypescript環境
の続きです。Table of Contents
- Prettier と es-lint を追加する
- husky を追加して precommit/prepush の前に lint と formatter を走らす
- CircleCI の build をする前に lint test を走らす
1. Prettier と ts-lint を追加する
Prettierの有効かをしていきます。
1-1, Prettier を install する
install するのは 2 種類。perttier と pretty-quick を install します。
$ npm install -D prettier pretty-quick1-2. Prettier の設定ファイルを作成する
$ touch .prettierrc中身は個人的に基本的な設定のみ対応します。
{ "semi": true, "trailingComma": "all", "singleQuote": true, "printWidth": 100, "tabWidth": 2 }install した pretty-quick が利用できるように、package.json に追加します。
package.json... "scripts": { "dev": "next", "build": "next build", "start": "next start", "prettier:quick": "pretty-quick --staged" }, ...試しに実行すると、github 場で変更したファイルを確認して prettier を実行してくれます。
$ npm run prettier:quick ? Finding changed files since git revision 43aa1b4. ? Found 0 changed files. ✅ Everything is awesome!1-3. lint を install する
lint の設定は、lint をインストールして設定ファイルを作成します。
$ npm install -D eslint1-4. lint の設定をする
es-lint の設定ファイル eslint.json を作成していきます。
--init を利用しファイルを作成していきます。$ npx eslint --init ? How would you like to use ESLint? To check syntax, find problems, and enforce code style ? What type of modules does your project use? JavaScript modules (import/export) ? Which framework does your project use? React ? Does your project use TypeScript? Yes ? Where does your code run? Browser ? How would you like to define a style for your project? Use a popular style guide ? Which style guide do you want to follow? Standard: https://github.com/standard/stan dard ? What format do you want your config file to be in? JSON作成させた eslintrc は以下になります。
{ "env": { "browser": true, "es6": true }, "extends": ["plugin:react/recommended", "standard"], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 2018, "sourceType": "module" }, "plugins": ["react", "@typescript-eslint"], "rules": {} }react を利用する際に error が生じるため、以下の設定を追加します。
eslintrc.json{ "env": { "browser": true, "es6": true }, "extends": ["plugin:react/recommended", "standard"], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 2018, "sourceType": "module" }, "plugins": ["react", "@typescript-eslint"], "rules": {}, "settings": { "react": { "version": "detect" } } }lint がコマンドから叩けるように package.json を編集します。
package.json... "scripts": { "dev": "next", "build": "next build", "start": "next start", "lint": "eslint src/** --ext .ts,.tsx", "lint:fix": "npm lint --fix" }, ...次に prettier の rule を lint の rule にも追加するように設定します。
$ npm install -D eslint-plugin-prettiereslintrc.json{ "env": { "browser": true, "es6": true }, "extends": ["plugin:react/recommended", "standard"], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 2018, "sourceType": "module" }, "plugins": ["react", "@typescript-eslint", "prettier"], "rules": { "prettier/prettier": "error" }, "settings": { "react": { "version": "detect" } } }次にコマンドが正常に動くか確認します。
$ npm run lint成功したら husky の設定をしていきます。
2. husky を追加して precommit/prepush の前に lint と formatter を走らす
huskyは、git のアクションにフックして、コマンドを走らせることができます。
husky を install して設定していきます。
$ npm install husky --save-dev今回はコミットの前にフォーマットを走らせ、push の前に lint を走らせるよに変更します。
package.json"husky": { "hooks": { "pre-commit": "pretty-quick --staged", "pre-push": "npm run lint" } }3. CircleCI の build をする前に lint test を走らす
circleci に設定を追加してきます。
deploy する前に test をはしらせて、失敗したら deploy しないように設定していきます。テストの内容を追加していきます。
circleci/config.ymlversion: 2.1 executors: node: working_directory: ~/project docker: - image: circleci/node:10.12-browsers ## ここから追記 jobs: test-lint: executor: name: node steps: - checkout - attach_workspace: at: . - run: name: linting code command: npm run lint ## ここまで追記job の作成が完了したら、workflow に追加します。
circleci/config.ymlworkflows: version: 2 build-and-cache: jobs: - build - test-lint: requires: - build - deploy-now: requires: - test-lintrequires で build 後に lint が走るように設定し、deploy については lint を通した後に実装するように変更しました。
- 投稿日:2020-02-05T13:18:30+09:00
create-react-appで生成したReactのimportを絶対パスでやる(VSCode対応)
- 投稿日:2020-02-05T11:29:29+09:00
ポートフォリオ作ってみた
- React
- GitHub pages
- Material-Ui
あたりをつかってさくっと作ってみました。
基本的にはcreate-react-appしてMaterial-Uiのタブを使っただけです。
create-react-appからGitHubPagesにデプロイするのはこのあたりの記事を参考にさせていただきました。
あとは、コンテンツをなんとなくマークダウンで書きたいお気持ちだったので、マークダウンでprofileなどをかいて読み込もうとしたら、Create React AppはまだMarkdownを簡単にLoadする手段がないという記事を発見。
上記の記事に書いてあったraw.macroをつかってマークダウンを読み込むことに成功しました!const raw = require('raw.macro') const aboutMe = raw('../data/aboutMe.md') ... <ReactMarkdown className="MainPage-contents" source={aboutMe} /> ...読み込んだマークダウンはreact-markdownを使って処理しています。
作ったはいいけど、コンテンツが薄いので、2020年はworksなどを充実させていきたいです。
- 投稿日:2020-02-05T01:53:13+09:00
NextJS(Typescript)を now にデプロイする
NextJS(Typescript)を now にデプロイする
これの続きとなります。。。
ので、nextjsの初期設定、circleCIでのプロジェクト作成は簡易的にできているながれですすめたい。Table of Contents
- now、Nextjs とは
- now の初期設定をする
- nextjs を now に手動デプロイする
- nextjs を CircleCI を使って Auto Deploy する
0. now、Nextjs とは
next.jsとは、Zeit社が提供しているReactを用いたSSR(SST)のOpen Source Projectです。
Vueで言うところのNuxtくらいの認識です。nowとは、ZEIT社が提供しているconfigなしでデプロイできるHostToolです。使ってみ思いましたがひくくらい簡単です。
1. now の初期設定をする
nowにアクセスをし、ユーザー登録をおこなっていきます。
下の画面の Deploy Free ボタンをクリックしてアカウント作成に移動します。今回は Contenue With GitHub を使って GitHub でアカウントを作成していきます。
アカウントの作成が完了するとダッシュボードに行くことができます。
これで web 上の設定は完了です。
次に、now コマンドを install していきます。$ npm install -g now # インストールが完了したら一応バージョンを確認いたします。 $ now --version 16.7.3コマンドが完了したら、nowコマンドを利用してログインしていきます。
メールアドレスを求められるので、ログインしたアカウントの Email アドレスを利用してログインをしていきます。$ now login We sent an email to YOUR_EMAIL_ADDRESS Please follow the steps provided inside it and make sure the security code matches Happy Magellanic Penguin. ✔ Email confirmed > Congratulations! You are now logged in. In order to deploy something, run `now`.2. nextjs を now に手動デプロイする
$ pwd /your/project/directory現状のディレクトリにいることを確認します。
nowでconfigで扱う、now.jsonファイルを作成していきます。now.json{ "name": "next-sample" }これで、プロジェクト名を固定してdeployすることができます。
ちなみにプロジェクト名を指定しない場合は、projectのroot directoryの名前が優先されるっぽいです。Gitのレポジトリとかpackage.jsonっぽい感じもしましたが、directory名っぽい。$ now --prod Deploying ~/your/project/directory under YOUR_PC > Using project PROJECT_NAME > NOTE: To deploy to production (YOUR_PRJECT_NAME.now.sh), run `now --prod` > Synced 1 file [4s] > https://XXX.now.sh [4s] > Ready! Deployed to https:/XXX.now.sh [in clipboard] [24s]コマンドを入力すると build されてデプロイされます。
表示された URL を確認すると、作成した URL が表記されてるかと思います。4. nextjs を CircleCI を使って Auto Deploy する
これ書いてから気づいたのですが、PRなどの作成タイミングでauto deployがはしります。www
circleCIをdeployのみで考えている場合は必要ありません。circleCI での now の設定は3段階。
1.now の token を発行して、circleCI の env に記載。最後に、circleCI の config から参照して deploy する形となります。4-1. now token を発行する
nowのtokenが作られるタイミングは、loginの際に発行するものと、自分で作成するものがあります。
自分でtokenをの発行する方法は、ダッシュボード画面にいき Settings から token を発行することができます。dashboardにいき右上のユーザーアイコンから、Settings リンクをクリック。
setting画面にあるTokenリンクから、とtokenの設定画面に遷移します。
現状tokenを利用している一覧表示のCreateをクリック
tokenを利用する名前を設定し、create tokenをクリックするとtokenが表示されます。
4-2. CircleCIに Environmentを設定する
nowのtokenの発行がおわったら、CircleCIのEnvironmentに記載していきます。
(Projectがある前提で話をしていきます。)設定画面にいったらEnvironment VariablesからAdd Variablesを選択
先ほどCopyしたnow Tokenを入力して、Environmentの設定をします。
これで、.circleci/config.ymlで $NOW_TOKENで登録したtokenを利用できるようになりました。
最後にCIの設定をしていきます。4-3. CircleCIの設定
設定が完了したら、circleciでデプロイできるよに、.circleci/config.ymlの編集をしていきます。
circleci/config.ymlversion: 2.1 executors: node: working_directory: ~/project docker: - image: circleci/node:10.12-browsers jobs: build: executor: name: node steps: - checkout - run: name: update-npm command: "sudo npm install -g npm@latest" - restore_cache: key: node-{{ .Branch }}-{{ checksum "package-lock.json" }} - run: name: npm install on ci command: npm ci - save_cache: key: node-{{ .Branch }}-{{ checksum "package-lock.json" }} paths: - ./node_modules - persist_to_workspace: root: . paths: - . - run: name: build flat command: npm run build # ここから追記 deploy-now: executor: name: node steps: - checkout - run: name: update-npm command: "sudo npm install -g npm@latest" - run: name: install now on global command: "sudo npm install -g now" - attach_workspace: at: . - run: name: deploy to now command: now deploy --token $NOW_TOKEN # ここまで追記 workflows: version: 2 build-and-cache: jobs: - build - deploy-now: requires: - buildでdeplpyすると、CircleCI経由でdeployすることが可能になります。
nowでauto deployもできるのでこの内容だけだと必要性を感じません。。。
now 自体も色々あるのであとで記載していこうかと。