# Next.jsのチュートリアル、その2
昨日のNext.jsのチュートリアル、その1の続きです。
# Assets, Metadata, and CSS
昨日作った pages/posts/first-post.js
は全くスタイル的なアレはないので、CSSを追加していきましょうという内容。Next.jsはCSSとSassがビルトインでサポートされているとのことですが、個人的にはSassには全く馴染みがありません…笑
そして、このチュートリアルではCSSを使っていくということで一安心w
Next.jsが画像とかページのメタデータ(例えばタイトルタグ)をどうやって取り扱うか的な内容だそうです。
# このレッスンを通して学ぶこと
- どうやって画像等の静的なファイルをNext.jsアプリに追加するか
- どうやってheadの中をページごとにカスタマイズするか
- CSS Modules(個人的にははじめて https://github.com/css-modules/css-modules をチラ見したレベルですがw)を使って再利用可能なReact componentを作る
pages/_app.js
にグローバルなCSSを追加する方法- Next.jsでのスタイリングに関するusefulなTips
とのことですが、CSSの基本的なことは扱わないのでね〜ってことだそうです。
# ってことでAssetsから
public
ディレクトリにファイル置いてねって感じで、今回はpublicの中にimagesというディレクトリを作ります、と。んでもって自分の画像をprofile.jpgって名前でそこに保存します。画像のサイズは400px by 400pxくらい、と。後は使わないSVGロゴファイルは消してしまいましょう、と。
最適化されていない普通のHTMLの場合は画像は↓こんな感じになります、と。
<img src="/images/profile.jpg" alt="Your Name" />
これだと色々と手動で対応しないといけません、と。
- スクリーンのサイズによるレスポンシブなヤツ
- それっぽいライブラリとか使った最適化
- 見られる時(viewport)にだけ画像を読み込む
そこで、Next.jsはImageコンポーネントっていうのを作ったよ、と。これで諸々やってくれるらしい。
ってことで、next/image
を使っていきますが、これはリサイズとか最適化とかやりつつブラウザがサポートしてればWebPっていうモダンなフォーマットにできるので〜っていう。そして外部の画像ソースでもAutomatic Image Optimizationしてくれるとのことです。
こと画像に関しては最適化はビルド時に行われるのではなく、ユーザーがリクエストした時ということで、ビルド時間は画像が沢山あっても変わらないのでご安心あれ的な。 画像はデフォルトでlazyロードされるので画像が見られる時以外は気にしなくてOKですよ、と。
そして、(SEOとか詳しくないのでアレなのですが、、)Googleが検索ランキングで利用するCore Web VitalのCumulative Layout Shiftにならないように画像はいつもレンダリングされているということです…
そして、今回のプロフィール画像はheight
とwidth
プロパティを使ってdesiredなレンダリングサイズを指定して元画像に合わせたアスペクトレシオと。
↓こんな感じ。
import Image from 'next/image'
const YourComponent = () => (
<Image
src="/images/profile.jpg" // Route of the image file
height={144} // Desired size with correct aspect ratio
width={144} // Desired size with correct aspect ratio
alt="Your Name"
/>
)
# 続いてMetadata
titleタグのようなheadの中のメタデータを変更する場合について。HTMLの<head>
ではなく、Reactコンポーネントの<Head>
というのがNext.jsにはビルトインされているんだそうで、それはnext/head
モジュールからインポートできるのだそうです。
ってことで、/posts/first-post
にタイトルを追加していきます。
まずは
import Head from 'next/head'
からの
export default function FirstPost() {
return (
<>
<Head>
<title>First Post</title>
</Head>
<h1>First Post</h1>
<h2>
<Link href="/">
<a>Back to home</a>
</Link>
</h2>
</>
)
}
でもって、例えば html タグのlang
属性をカスタマイズしたいとかあたら、pages/_document.js
というファイルでやりくりできるらしいけど、それはカスタムDocument
に関するドキュメントを見てね、とのことでした。
ってことで先に進みます。
# CSS Styling
いよいよスタイルシートですね、と。pages/index.jsは既にスタイルが適用されていて↓こんなのがあると思います、と。
<style jsx>{`
…
`}</style>
これはstyled-jsxというものなのだそうですが、styled-componentsやemotionというものも使えるそうです。(私にはどれも馴染みがないですが…笑)
Next.jsはCSSとSCSSがビルトインでサポートされているので .css
とか .scss
ファイルもオッケーですし、ポピュラーなCSSライブラリであるTailwind CSSもサポートしてますよ、と。
このレッスンではCSSファイルをインポートしてやっていくし、更にCSS ModulesとSassについても触れていくそうです。
# Layout Component
全ページで共有して使われるLayoutコンポーネントを作っていく的なヤツ。
componentsっていうディレクトリを作ってその中にlayout.js
を作っていく。
export default function Layout({ children }) {
return <div>{children}</div>
}
そして、pages/posts/first-post.js
で上記のLayoutコンポーネントをインポートして使っていきます。
import Head from 'next/head'
import Link from 'next/link'
import Layout from '../../components/layout'
export default function FirstPost() {
return (
<Layout>
<Head>
<title>First Post</title>
</Head>
<h1>First Post</h1>
<h2>
<Link href="/">
<a>Back to home</a>
</Link>
</h2>
</Layout>
)
}
しかし、まぁ、こうやって補完してくれるのありがたいですねぇ。VS Code。
そしてスタイルシートをLayoutコンポーネントに追加していくぞ、と。ここではCSS Modulesを使ってReactコンポーネントとしてインポートが出来るようにということらしい。
ということで、先ほど作ったcomponentsの中にlayout.module.cssというファイルを作って↓こんな定義をします、と。
.container {
max-width: 36rem;
padding: 0 1rem;
margin: 3rem auto 6rem;
}
ちな、CSS Modulesを使うにはファイルの末尾は .module.css じゃないとダメなんですって。
ということで、このCSSの containerクラスを使うには、
- CSSをインポートして styles といった名前をつける
- classNameとして
styles.container
を使う
ということをするってことで、layout.jsを以下のように。(というか、こういう汎用的なdivタグのことをコンテナとか読んだりするすら今の会社に入るまであんまり馴染みなかったかも…汗)
import styles from './layout.module.css'
export default function Layout({ children }) {
return <div className={styles.container}>{children}</div>
}
ってことで、スタイルシートによって余白ができましたよ、と。
そして、確かにdivのクラス名がユニークになってる!これによってクラス名の競合が〜みたいな心配をしなくてイイ、と。これはCSS Modulesによるものだそうで、.cssファイルはビルドの時に生成されてロードされるのだそうです。
# 続いてGlobal Styles
CSS Modulesでコンポーネントレベルでスタイルがやりくりできるのは便利だけど、全部のページで同じスタイルしたかったら?っていうのがGlobal CSSってことらしいのですが、それをするにはpages/_app.js
を↓こんな風にしてやるんだそうで。
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}
このAppっていうのはトップレベルのコンポーネントで全てのページに行き渡るそうです。そして、注意というか、pages/_app.js
を追加した時はサーバーの再起動が必要なので、コントロール+Cで一回止めて、npm run devしてあげます。
ってことで、stylesディレクトリを作ってそこにglobal.cssというファイルを作っていきます。aタグの色とか変えてくよ、と。
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
line-height: 1.6;
font-size: 18px;
}
* {
box-sizing: border-box;
}
a {
color: #0070f3;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
img {
max-width: 100%;
display: block;
}
そして、これを_app.jsでインポートしていきます。
import '../styles/global.css'
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}
おー、変わった変わった。
# レイアウトをいい感じにしていく
今までは最小限にReactとCSSのコードを使ってやってきたけど、次のデータフェッチの章に行く前にUIをいい感じしていきましょうってことで、ここはちょっとコピペおじさんな感じになりそうですが…w
まずはcomponents/layout.module.cssを変更して、次にstyles/util.module.cssを作成して、components/layout.jsをいい感じにして(名前を自分のに変える)、pages/index.jsも。
ってことで。笑
# スタイリングのTips
別に変更しなくてもザザっと読んどけばOKよんってことで。
classnamesっていうライブラリを使うと↓こんなCSS(例: alert.module.css)を作っておくと
.success {
color: green;
}
.error {
color: red;
}
↓こんな風に書ける。
import styles from './alert.module.css'
import cn from 'classnames'
export default function Alert({ children, type }) {
return (
<div
className={cn({
[styles.success]: type === 'success',
[styles.error]: type === 'error'
})}
>
{children}
</div>
)
}
デフォルトだと、Next.jsはPostCSSというのを使っているそうで、それをカスタマイズするには postcss.config.js というのをトップレベルファイルとして作るのだそうですが、Tailwind CSSを使ってると便利だったりするそうです。npmで諸々入れてあげて↓こんなのを postcss.config.js に書いてあげる、と。
module.exports = {
plugins: [
'tailwindcss',
'postcss-flexbugs-fixes',
[
'postcss-preset-env',
{
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3,
features: {
'custom-properties': false
}
}
]
]
}
あとは使ってないCSSをtailwind.config.css というファイルに purge っていうオプションで↓こんな風にすると良いのだそうです。
module.exports = {
purge: [
// Use *.tsx if using TypeScript
'./pages/**/*.js',
'./components/**/*.js'
]
// ...
}
この辺はあんまり良くわかってないのと、Sassを使う場合は〜みたいな話しも出てくるけど、一旦今日のところはここまでにします。
いやー、、それでも結構なボリュームだわ。ゴールデン・ウィークにせっせこ進めますかねー