「Next.js v13対応コード」

Next.js version 13を使った場合の表示崩れについて

2022年11月初頭にNext.jsの最新バージョン13がリリースされたため、本書での指示通り「npx create-next-app next-portfolio --use-npm」を実行するとv13が自動でインストールされます。しかし本書はv12をベースに書かれており、v13ではnext/imageコンポーネントに大きな変更が加えられたため、本書の通りにコードを書くと表示の崩れる箇所が出てきます。

解決策はnextのバージョンを本書で使用しているv12に戻すことです。ターミナルで次のコマンドを実行し、本書で使用しているバージョンに準拠させてください。

npm install next@12.1.5

あるいはv13を使う場合はいくつかのコードを書き加えてください。以下紹介します。

コンポーネント内からタグを削除

v13では<Link><a>タグを一緒に使う必要がなくなったので、各ファイルから<Link>コンポーネント内の<a>タグを削除します(あるいは<Link legacyBehavior>と書くことで<a>タグを残すことも可能です)。

prevNext.jsファイルでは<a>タグにclassNameが置いてあるので、下のように<a>タグ削除後はsingleBlog.module.scssも下記のように修正してください。

// prevNext.js

const PrevNext =(props) => {
    return (
        <div className={style.pnWrapper}>
            {0 < props.prev.length && 
                <Link href={`/blog/${props.prev[0].slug}`}>
                    <a className={style.linkCard}>    // 削除
                        <img src="/images/arrow-left.svg" alt="arrow-left"/>
                        <h3> {props.prev[0].frontmatter.title}</h3>
                    </a>                               // 削除
                </Link>
            }
            {0 < props.next.length && 
                <Link href={`/blog/${props.next[0].slug}`}>
                    <a className={style.linkCard}>   // 削除
                        <h3>{props.next[0].frontmatter.title}</h3>
                        <img src="/images/arrow-right.svg" alt="arrow-right"/>
                    </a>                            // 削除
                </Link>
            }
        </div>
    )
}

export default PrevNext 
// singleBlog.module.scss

...

// PrevNext
.pnWrapper {
    display: flex;
    justify-content: center;
    gap: 2rem;
    margin-top: 5rem;
    @extend %container;
    @media (max-width: $break-s){ flex-wrap: wrap; }
    a {                             // 「.linkCard」を「a」に変更
        display: flex;
        justify-content: center;
        border: 2px solid $primary-color;
        width: 100%;
        padding: 2rem 5rem;
        color: inherit;
        &:hover {
            opacity: 0.8;
        }
    }
}

Indexページの修正

Indexページは下のように修正してください。

// index.js

...
<div className="profile">
    <div>
        <h2>JavaScript Nerd</h2>
        <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
    </div>
    <div className={style.imageContainer}>  // 追加
        <Image src="/images/profile.jpg" alt="hero" fill quality={90} />  // 修正
    </div>    // 追加
</div>
...

// index.module.scss

...

    @media(max-width: $break-s){ 
        padding: 5rem 0;
        grid-template-columns: 1fr;
        grid-row-gap: 3rem;
    }
    p {
        margin-bottom: 0;
    }
}

// ↓追加
.profile > .imageContainer{
    position: relative;
}

.profile > .imageContainer > img {
    min-height: 1195;
    width: 100%;
    position: relative !important;
}
// ↑追加

.skills{ 
    padding: 0 0 10rem;
    ...

Blogページの修正

Blogページは下のように修正してください。

// blog.module.scss

        ...
        .cardImg {
            height: 300px;
            img{
                min-height: 300px;
                // ↓追加
                width: 100%;
                object-fit: cover;
                // ↑追加
            }
            @media(max-width: $break-s) { 
                order: -1;
            }
        }
    }
}

SingleBlogページの修正

SingleBlogページは下のように修正してください。

// singleBlog.module.scss

@import './variables.scss';

// ↓追加
.hero {
    text-align: center;
    max-width: 1000px;
    margin: auto;
}

.hero > img {
    width: 100%;
    object-fit: cover;
}
// ↑追加

.wrapper {
    padding: 5rem 0 10rem;
    .container {  
    ..