jQueryからNext.jsに移行する方法
公開: 2022-03-10この記事は、世界中から集まった素晴らしい才能の多様なグループであり、生産性を高めるWeb開発者向けのプラットフォームを提供するNetlifyの親愛なる友人たちによって親切にサポートされています。 ありがとう!
2006年にjQueryが登場したとき、多くの開発者や組織がプロジェクトにjQueryを採用し始めました。 ライブラリが提供するDOMを拡張および操作する可能性は非常に高く、jQueryメインライブラリでサポートされていないタスクを実行する必要がある場合に備えて、ページに動作を追加するためのプラグインも多数あります。 これにより、開発者の多くの作業が簡素化され、その時点で、JavaScriptがWebアプリケーションまたはシングルページアプリケーションを作成するための強力な言語になりました。
jQueryの人気の結果は、今日でも測定可能です。世界で最も人気のあるWebサイトのほぼ80%がjQueryを使用しています。 jQueryが非常に人気がある理由のいくつかは次のとおりです。
- DOM操作をサポートします。
- CSS操作を提供します。
- すべてのWebブラウザで同じように機能します。
- HTMLイベントメソッドをラップします。
- AJAX呼び出しを簡単に作成できます。
- 使いやすいエフェクトとアニメーション。
何年にもわたって、JavaScriptは大きく変化し、過去にはなかったいくつかの機能を追加しました。 ECMAScriptの再定義と進化により、jQueryが提供する機能の一部が標準のJavaScript機能に追加され、すべてのWebブラウザーでサポートされました。 これにより、プレーンJavaScriptでも同じことができるため、jQueryが提供する動作の一部は不要になりました。
一方、ユーザーインターフェイスの新しい考え方やデザインが登場し始めました。 React、Angular、Vueなどのフレームワークを使用すると、開発者は再利用可能な機能コンポーネントに基づいてWebアプリケーションを作成できます。 Reactは、つまり、メモリ内のDOM表現である「仮想DOM」と連携しますが、 jQueryはパフォーマンスの低い方法でDOMと直接対話します。 また、Reactは、状態管理などの特定の機能の開発を容易にする優れた機能を提供します。 この新しいアプローチとシングルページアプリケーションの人気が高まり始めたため、多くの開発者がWebアプリケーションプロジェクトにReactを使用し始めました。
また、フロントエンドの開発はさらに進化し、他のフレームワークの上にフレームワークが作成されました。 これは、たとえばNext.jsの場合です。 ご存知かもしれませんが、これはオープンソースのReactフレームワークであり、静的ページを生成し、サーバー側でレンダリングされたページを作成し、同じアプリケーションで両方のタイプを組み合わせる機能を提供します。 また、同じアプリ内にサーバーレスAPIを作成することもできます。
奇妙なシナリオがあります。これらのフロントエンドフレームワークは長年にわたってますます人気がありますが、jQueryは依然として大多数のWebページで採用されています。 これが発生する理由の1つは、WordPressを使用しているWebサイトの割合が非常に高く、 jQueryがCMSに含まれていることです。 もう1つの理由は、Bootstrapなどの一部のライブラリはjQueryに依存しており、それとそのプラグインを使用するすぐに使用できるテンプレートがいくつかあることです。
しかし、jQueryを使用するこの量のWebサイトの別の理由は、完全なWebアプリケーションを新しいフレームワークに移行するコストです。 簡単ではなく、安くもなく、時間がかかります。 しかし、最終的には、新しいツールやテクノロジーを使用することで、サポートの拡大、コミュニティの支援、開発者のエクスペリエンスの向上、プロジェクトでの作業のしやすさなど、多くのメリットがもたらされます。
ReactやNext.jsのようなフレームワークが私たちに課すアーキテクチャに従う必要がない(または望まない)シナリオはたくさんありますが、それは問題ありません。 ただし、jQueryは、不要になった多くのコードと機能を含むライブラリです。 jQueryが提供する機能の多くは、最新のJavaScriptネイティブ関数を使用して、おそらくよりパフォーマンスの高い方法で実現できます。
jQueryの使用をやめ、WebサイトをReactまたはNext.jsWebアプリケーションに移行する方法について説明しましょう。
移行戦略を定義する
図書館が必要ですか?
Webアプリケーションの機能によっては、フレームワークが実際には必要ない場合もあります。 前述のように、最新のWeb標準バージョンにはいくつかのjQuery機能(または少なくとも非常に類似した機能)が含まれていました。 だから、それを考慮して:
- jQueryの
$(selector)
パターンはquerySelectorAll()
に置き換えることができます。
行う代わりに:
$("#someId");
我々はできる:
document.querySelectorAll("#someId");
- CSSクラスを操作する場合は、プロパティ
Element.classList
があります。
行う代わりに:
$(selector).addClass(className);
我々はできる:
element.classList.add(className);
- 多くのアニメーションは、JavaScriptを実装する代わりに、CSSを使用して直接実行できます。
行う代わりに:
$(selector).fadeIn();
我々はできる:
element.classList.add('show'); element.classList.remove('hide');
そして、CSSスタイルを適用します。
.show { transition: opacity 400ms; } .hide { opacity: 0; }
- イベントを処理する場合は、addEventListener関数があります。
行う代わりに:
$(selector).on(eventName, eventHandler);
我々はできる:
element.addEventListener(eventName, eventHandler);
- jQuery Ajaxを使用する代わりに、
XMLHttpRequest
を使用できます。
行う代わりに:
$.ajax({ type: 'POST', url: '/the-url', data: data });
我々はできる:
var request = new XMLHttpRequest(); request.open('POST', '/the-url', true); request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); request.send(data);
詳細については、これらのバニラJavaScriptコードスニペットをご覧ください。
コンポーネントを特定する
アプリケーションでjQueryを使用している場合は、Webサーバーで生成されるHTMLコンテンツと、ページに双方向性を追加するJavaScriptコードが必要です。 おそらく、ページの読み込み時にイベントハンドラーを追加して、イベントが発生したときにDOMを操作し、CSSまたは要素のスタイルを更新します。 また、バックエンドサービスを呼び出してアクションを実行することもできます。これは、ページのDOMに影響を与えたり、ページをリロードしたりする可能性があります。
アイデアは、ページにあるJavaScriptコードをリファクタリングし、 Reactコンポーネントを構築することです。 これは、関連するコードを結合し、より大きな構成の一部となる要素を構成するのに役立ちます。 これを行うことで、アプリケーションの状態をより適切に処理できるようになります。 アプリケーションのフロントエンドを分析し、それを特定のタスク専用の部分に分割して、それに基づいてコンポーネントを作成できるようにする必要があります。
ボタンがある場合:
<button>Click</button>
次のロジックを使用します。
var $btnAction = $("#btn-action"); $btnAction.on("click", function() { alert("Button was clicked"); });
それをReactコンポーネントに移行できます:
import React from 'react'; function ButtonComponent() { let handleButtonClick = () => { alert('Button clicked!') } return <button onClick={handleButtonClick}>Click</button> }
ただし、アプリケーションが機能して使用されているため、移行プロセスがどのように実行されるかを評価する必要があります。また、アプリケーションに影響を与えたくありません(または、少なくとも影響を最小限に抑えます)。
良い移行
適切な移行とは、アプリケーションのすべての部分が新しいフレームワークまたはテクノロジーに完全に移行される移行です。 これは、すべてのパーツの同期を維持し、統合ツールと一意の参照バージョンを使用するため、アプリケーションにとって理想的なシナリオです。
通常、適切で完全な移行には、アプリのコードの完全な書き直しが含まれます。これは理にかなっています。 アプリを最初から作成する場合、新しいコードでどの方向に進むかを決定する可能性があります。 既存のシステムとワークフローに新しい視点を使用し、現時点での知識を使用して、最初にWebアプリケーションを作成したときよりも完全なまったく新しいアプリを作成できます。
しかし、完全な書き換えにはいくつかの問題があります。 まず第一に、それは多くの時間を必要とします。 アプリケーションが大きいほど、書き直す必要がある時間が長くなります。 もう1つの問題は、作業量と開発者の数です。 また、プログレッシブ移行を行わない場合は、アプリケーションが使用できなくなるまでの時間を考慮する必要があります。
通常、完全な書き換えは、小さなプロジェクト、頻繁に変更されないプロジェクト、またはビジネスにとってそれほど重要ではないアプリケーションで実行できます。
高速移行
別のアプローチは、アプリケーションをパーツまたはピースに分割することです。 アプリをパーツごとに移行し、準備ができたらそれらのパーツをリリースします。 そのため、ユーザーが利用できるアプリケーションの一部を移行し、既存の本番アプリと共存させました。
この段階的な移行により、アプリケーション全体が書き直されるのを待つ必要がないため、プロジェクトの個別の機能をより迅速にユーザーに提供できます。 また、ユーザーからのフィードバックが迅速になり、バグや問題を早期に検出できるようになります。
しかし、段階的な移行により、さまざまなツール、ライブラリ、依存関係、およびフレームワークが必要になります。 または、同じツールから異なるバージョンをサポートする必要がある場合もあります。 この拡張サポートにより、アプリケーションに競合が発生する可能性があります。
移行された各部分は異なる方法で機能する可能性があるため、グローバルスコープでポリシーを適用している場合でも問題が発生する可能性がありますが、システムにグローバルパラメーターを設定するコードの影響を受けます。 この例は、CSSスタイリングにカスケードロジックを使用することです。
新しいバージョンから後で作成されたモジュールに機能を追加したため、Webアプリケーション全体でさまざまなバージョンのjQueryを使用していると想像してください。 すべてのアプリを新しいバージョンのjQueryに移行するのはどれほど複雑ですか? ここで、同じシナリオを想像しますが、Next.jsのような完全に異なるフレームワークに移行します。 それは複雑になる可能性があります。
フランケンシュタインの移行
Denys Mishunovは、Smashing Magazineに、これら2つの移行のアイデアの代替案を提示する記事を書き、前の2つのアプローチであるFrankensteinMigrationを最大限に活用しようとしています。 移行プロセスは、マイクロサービスとWebコンポーネントの2つの主要コンポーネントに基づいています。
移行プロセスは、従うべきステップのリストで構成されています。
1.マイクロサービスを特定する
アプリコードに基づいて、1つの小さなジョブ専用の独立した部分に分割する必要があります。 ReactまたはNext.jsの使用を検討している場合は、マイクロサービスの概念をさまざまなコンポーネントにリンクできます。
例として、食料品リストアプリケーションについて考えてみましょう。 購入するもののリストと、リストにさらに物を追加するための入力があります。 したがって、アプリを小さな部分に分割したい場合は、「アイテムリスト」コンポーネントと「アイテムの追加」について考えることができます。 これにより、これらの各パーツに関連する機能とマークアップを異なるReactコンポーネントに分離できます。
コンポーネントが独立していることを確認するには、コンポーネントの1つをアプリから削除できる必要があり、他のコンポーネントはその影響を受けないようにする必要があります。 サービスからマークアップと機能を削除するときにエラーが発生した場合、コンポーネントを正しく識別していないか、コードの動作方法をリファクタリングする必要があります。
2.ホストからエイリアンへのアクセスを許可する
「ホスト」は既存のアプリケーションです。 「エイリアン」は、新しいフレームワークで作成を開始するものです。 どちらも独立して機能するはずですが、ホストからエイリアンへのアクセスを提供する必要があります。 2つのアプリケーションのいずれかを、もう一方のアプリケーションを壊すことなくデプロイできるはずですが、それらの間の通信は維持されます。
3.エイリアンコンポーネントを書く
新しいフレームワークを使用して、ホストアプリケーションからエイリアンアプリケーションにサービスを書き直します。 コンポーネントは、前に述べたのと同じ独立性の原則に従う必要があります。
食料品リストの例に戻りましょう。 「アイテムの追加」コンポーネントを特定しました。 jQueryを使用すると、コンポーネントのマークアップは次のようになります。
<input class="new-item" />
また、アイテムをリストに追加するためのJavaScript / jQueryコードは、次のようになります。
var ENTER_KEY = 13; $('.new-item').on('keyup', function (e) { var $input = $(e.target); var val = $input.val().trim(); if (e.which !== ENTER_KEY || !val) { return; } // code to add the item to the list $input.val(''); });
その代わりに、 AddItem
コンポーネントを作成できます。
import React from 'react' function AddItemInput({ defaultText }) { let [text, setText] = useState(defaultText) let handleSubmit = e => { e.preventDefault() if (e.which === 13) { setText(e.target.value.trim()) } } return <input type="text" value={text} onChange={(e) => setText(e.target.value)} onKeyDown={handleSubmit} /> }
4.エイリアンサービスの周りにWebコンポーネントラッパーを書く
作成したばかりのAlienサービスをインポートしてレンダリングするラッパーコンポーネントを作成します。 アイデアは、ホストアプリとエイリアンアプリの間にブリッジを作成することです。 新しいReactコンポーネントをコピーして機能させる必要があるため、現在のアプリケーションで機能するJavaScriptコードを生成するためにパッケージバンドラーが必要になる可能性があることに注意してください。
食料品リストの例に従って、HostプロジェクトにAddItem-wrapper.js
ファイルを作成できます。 このファイルには、すでに作成されているAddItem
コンポーネントをラップし、それを使用してカスタム要素を作成するコードが含まれます。
import React from "../alien/node_modules/react"; import ReactDOM from "../alien/node_modules/react-dom"; import AddItem from "../alien/src/components/AddItem"; class FrankensteinWrapper extends HTMLElement { connectedCallback() { const appWrapper = document.createElement("div"); appWrapper.classList.add("grocerylistapp"); ... ReactDOM.render( <HeaderApp />, appWrapper ); … } } customElements.define("frankenstein-add-item-wrapper", FrankensteinWrapper);
コンポーネントを機能させるにはインポートする必要があるため、必要なノードモジュールとコンポーネントをAlienアプリケーションフォルダーから取得する必要があります。
5.ホストサービスをWebコンポーネントに置き換えます
このラッパーコンポーネントは、ホストアプリケーションのコンポーネントを置き換え、使用を開始します。 したがって、本番環境でのアプリケーションは、ホストコンポーネントとエイリアンラップされたコンポーネントの組み合わせになります。
この例のホストアプリケーションでは、次のものを置き換える必要があります。
<input class="new-item" />
と
<frankenstein-add-item-wrapper></frankenstein-add-item-wrapper> ... <script type="module" src="js/AddItem-wrapper.js"></script>
6.すすぎ、繰り返します
識別されたマイクロサービスごとに、手順3、4、および5を実行します。
7.エイリアンに切り替えます
Hostは、Alienアプリケーションで作成したすべてのWebコンポーネントを含むラッパーコンポーネントのコレクションになりました。 識別されたすべてのマイクロサービスを変換したので、Alienアプリケーションが終了し、すべてのサービスが移行されたと言えます。 ここで、ユーザーにAlienアプリケーションを指定する必要があります。
フランケンシュタイン移行方法は、GoodアプローチとFastアプローチの両方の組み合わせとして機能します。 アプリケーション全体を移行しますが、完了したらさまざまなコンポーネントをリリースします。 したがって、それらはより早く使用でき、本番環境のユーザーによって評価されます。
ただし、このアプローチでは過剰な作業を行っていることを考慮する必要があります。 Alienアプリケーション用に作成したコンポーネントを使用する場合は、ホストアプリに含めるラッパーコンポーネントを作成する必要があります。 これにより、これらのラッパー要素のコードの開発に時間を費やすことができます。 また、ホストアプリケーションでそれらを使用することにより、コードと依存関係の包含を複製し、アプリケーションのパフォーマンスに影響を与えるコードを追加しています。
Stranglerアプリケーション
私たちが取ることができる別のアプローチは、レガシーアプリケーションの絞殺です。 既存のWebアプリケーションのエッジを特定し、アプリに機能を追加する必要がある場合は常に、古いシステムが「絞殺」されるまで、新しいフレームワークを使用してそれを行います。 このアプローチは、アプリの移行中に実験できる潜在的なリスクを軽減するのに役立ちます。
このアプローチに従うには、Frankenstein Migrationの場合と同様に、さまざまなコンポーネントを識別する必要があります。 アプリを関連する命令型コードのさまざまな部分に分割したら、それらを新しいReactコンポーネントでラップします。 追加の動作を追加するのではなく、既存のコンテンツをレンダリングするReactコンポーネントを作成するだけです。
さらに明確にするために例を見てみましょう。 アプリケーションに次のHTMLコードがあるとします。
<div class="accordion"> <div class="accordion-panel"> <h3 class="accordion-header">Item 1</h3> <div class="accordion-body">Text 1</div> </div> <div class="accordion-panel"> <h3 class="accordion-header">Item 2</h3> <div class="accordion-body">Text 2</div> </div> <div class="accordion-panel"> <h3 class="accordion-header">Item 3</h3> <div class="accordion-body">Text 3</div> </div>> </div>
そしてこのJavaScriptコード(すでにjQuery関数を新しいJavaScript標準機能に置き換えました)。
const accordions = document.querySelectorAll(".accordion"); for (const accordion of accordions) { const panels = accordion.querySelectorAll(".accordion-panel"); for (const panel of panels) { const head = panel.querySelector(".accordion-header"); head.addEventListener('click', () => { for (const otherPanel of panels) { if (otherPanel !== panel) { otherPanel.classList.remove('accordion-expanded'); } } panel.classList.toggle('accordion-expanded'); }); } }
これは、JavaScriptのaccordion
コンポーネントの一般的な実装です。 ここでReactを紹介したいので、既存のコードを新しいReactコンポーネントでラップする必要があります。
function Accordions() { useEffect(() => { const accordions = document.querySelectorAll(".accordion") for (const accordion of accordions) { const panels = accordion.querySelectorAll(".accordion-panel") for (const panel of panels) { const head = panel.querySelector(".accordion-header") head.addEventListener("click", () => { for (const otherPanel of panels) { if (otherPanel !== panel) { otherPanel.classList.remove("accordion-expanded") } } panel.classList.toggle("accordion-expanded") }); } } }, []) return null } ReactDOM.render(<Accordions />, document.createElement("div"))
コンポーネントは新しい動作や機能を追加していません。 コンポーネントがドキュメントにマウントされているため、 useEffect
を使用します。 フックがコンポーネントを返す必要がないため、関数がnullを返すのはそのためです。
そのため、既存のアプリに新しい機能を追加しませんでしたが、動作を変更せずにReactを導入しました。 今後、コードに新しい機能や変更を追加するときは常に、新しく選択したフレームワークを使用してそれを行います。
クライアント側のレンダリング、サーバー側のレンダリング、または静的生成?
Next.jsを使用すると、Webアプリケーションの各ページをどのようにレンダリングするかを選択できます。 Reactがすでに提供しているクライアント側のレンダリングを使用して、ユーザーのブラウザーで直接コンテンツを生成できます。 または、サーバー側のレンダリングを使用して、サーバー内のページのコンテンツをレンダリングすることもできます。 最後に、静的生成を使用して、ビルド時にページのコンテンツを作成できます。
このアプリケーションでは、JavaScriptライブラリまたはフレームワークとの対話を開始する前に、ページの読み込み時にコードを読み込んでレンダリングする必要があります。 ASP.NET、PHP、Node.jsなどのサーバー側のレンダリングプログラミング言語またはテクノロジを使用している可能性があります。 Next.jsの機能を利用して、現在のレンダリング方法をNext.jsサーバー側のレンダリング方法に置き換えることができます。 これを行うことで、選択したフレームワークの傘下で機能する同じプロジェクト内ですべての動作を維持します。 また、メインページとReactコンポーネントのロジックを、ページに必要なすべてのコンテンツを生成する同じコード内に保持します。
例としてダッシュボードページについて考えてみましょう。 ユーザーのWebブラウザーでReactを使用してページを生成する代わりに、サーバーでロード時にページのすべての初期マークアップを生成できます。
const DashboardPage = ({ user }) => { return ( <div> <h2>{user.name}</h2> // User data </div> ) } export const getServerSideProps = async ({ req, res, params }) => { return { props: { user: getUser(), }, } }, }) export default DashboardPage
ページの読み込み時にレンダリングするマークアップが予測可能であり、ビルド時に取得できるデータに基づいている場合は、静的生成が適しています。 ビルド時に静的アセットを生成すると、アプリケーションがより速く、より安全に、スケーラブルになり、保守が容易になります。 また、アプリのページで動的コンテンツを生成する必要がある場合は、Reactのクライアント側レンダリングを使用して、サービスまたはデータソースから情報を取得できます。
多くのブログ投稿があるブログサイトがあると想像してください。 静的生成を使用する場合、Next.jsアプリケーションで汎用[blog-slug].js
ファイルを作成できます。次のコードを追加すると、ビルド時にブログ投稿のすべての静的ページが生成されます。
export const getStaticPaths = async () => { const blogPosts = await getBlogPosts() const paths = blogPosts.map(({ slug }) => ({ params: { slug, }, })) return { paths, fallback: false, } } export const getStaticProps = async ({ params }) => { const { slug } = params const blogPost = await getBlogPostBySlug(slug) return { props: { data: JSON.parse(JSON.stringify(blogPost)), }, } }
APIルートを使用してAPIを作成する
Next.jsが提供する優れた機能の1つは、APIルートを作成できることです。 それらを使用すると、Node.jsを使用して独自のサーバーレス関数を作成できます。 NPMパッケージをインストールして機能を拡張することもできます。 これのすばらしい点は、APIがフロントエンドと同じプロジェクト/アプリに残るため、CORSの問題が発生しないことです。
jQuery AJAX機能を使用してWebアプリケーションから呼び出されるAPIを維持している場合、 APIルートを使用してそれらを置き換えることができます。 これにより、アプリのすべてのコードベースを同じリポジトリに保持し、アプリケーションのデプロイを簡単にします。 サードパーティのサービスを使用している場合は、APIルートを使用して外部URLを「マスク」できます。
ページで使用するデータを返すAPIルート/pages/api/get/[id].js
を作成できます。
export default async (req, res) => { const { id } = req.query try { const data = getData(id) res.status(200).json(data) } catch (e) { res.status(500).json({ error: e.message }) } }
そして、私たちのページのコードからそれを呼び出します。
const res = await fetch(`/api/get/${id}`, { method: 'GET', }) if (res.status === 200) { // Do something } else { console.error(await res.text()) }
Netlifyにデプロイする
Netlifyは、Webアプリケーションの自動化、管理、構築、テスト、展開、およびホストに使用できる完全なプラットフォームです。 最新のWebアプリケーション開発をより簡単かつ迅速にする多くの機能を備えています。 Netlifyのハイライトは次のとおりです。
- グローバルCDNホスティングプラットフォーム、
- サーバーレス機能のサポート、
- Githubプルリクエストに基づいてプレビューをデプロイします。
- Webhook、
- インスタントロールバック、
- ロールベースのアクセス制御。
Netlifyは、Next.jsアプリケーションを管理およびホストするための優れたプラットフォームであり、Netlifyを使用してWebアプリをデプロイするのは非常に簡単です。
まず、GitリポジトリでNext.jsアプリのコードを追跡する必要があります。 NetlifyはGitHub(または私たちが好むGitプラットフォーム)に接続し、ブランチに変更が導入されるたびに(コミットまたはプルリクエスト)、自動の「ビルドとデプロイ」タスクがトリガーされます。
アプリのコードを含むGitリポジトリを作成したら、そのための「Netlifyサイト」を作成する必要があります。 これを行うには、2つのオプションがあります。
- NetlifyCLIの使用
CLIをインストールし(npm install -g netlify-cli
)、Netlifyアカウントにログインした後(ntl login
)、アプリケーションのルートディレクトリに移動し、ntl init
を実行して、手順を実行します。 - NetlifyWebアプリの使用
https://app.netlify.com/startにアクセスする必要があります。 Gitプロバイダーに接続し、リストからアプリケーションのリポジトリを選択し、いくつかのビルドオプションを構成して、デプロイします。
どちらの方法でも、ビルドコマンドがnext build
になり、デプロイするディレクトリがout
になることを考慮する必要があります。
最後に、Essential Next.jsプラグインが自動的にインストールされます。これにより、APIルート、動的ルート、プレビューモードをデプロイして使用できるようになります。 これで、Next.jsアプリケーションが高速で安定したCDNホスティングサービスで稼働します。
結論
この記事では、jQueryライブラリを使用してWebサイトを評価し、ReactやNext.jsなどの新しいフロントエンドフレームワークと比較しました。 新しいツールへの移行を開始する方法を定義しました。 さまざまな移行戦略を評価し、Next.jsWebアプリケーションプロジェクトに移行できるシナリオの例をいくつか見ました。 最後に、Next.jsアプリケーションをNetlifyにデプロイして、起動して実行する方法を確認しました。
さらに読むとリソース
- フランケンシュタインの移行:フレームワークにとらわれないアプローチ
- GitHub.comフロントエンドからjQueryを削除する
- Next.js入門
- Next.jsサイトをNetlifyにデプロイする方法
- NetlifyブログのNext.jsの記事