TypeScriptを使用したNext.js 5からNext.js 6へ移行した時行った対応について

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Next.jsはこのサイトでも使っているのですが
比較的容易にBFF(バックエンドフォーフロントエンド)が実現できるツールとして大変有用です。
UXを実現していくためにSPA(シングルーページアプリケーション)という
アーキテクトがあげられますが
単純なSPAとしての問題点であげられるのが
- リクエストの複雑化によるランドトリップ
- 初回ロード時間の遅延
このあたりの課題の解決としてBFFというアーキテクチャの設計思想があります。
そのためこれらの解決を実現していくために
このサイトではNext.js
を採用しました。
そんなNext.js6が5月にリリースされたため
マイグレーションのログとして内容をまとめました。
環境
- React 16.3.2
- Next.js 5.1
- typescript 2.8.3
terminal$ yarn upgrade --latest next next-redux-wrapper typescript
terminal$ yarn upgrade --latest @zeit/next-typescript @types/next
packageのバージョン
- next@5.1 → next@6.1.1
- next-redux-wrapper@1.3.7 → next-redux-wrapper@2.0.0-beta.6
- typescript@2.8.3 → typescript@2.9.2
- @zeit/next-typescript@0.1.1 → @zeit/next-typescript@1.1.0
- @types/next@2.4.8 → @types/next@6.0.3
next-redux-wrapper関連
アップデート後に出たエラー
terminal__WEBPACK_IMPORTED_MODULE_2_next_redux_wrapper__ is not a function
解決方法
書き方が変わりました。
next-redux-wrapper1系
getInitialPropsを呼び出したReact
クラスをwithRedux
でラップすることで
ステートを子コンポーネントで参照できます。
./pages/index.tsx
typescriptimport * as React from 'React';
import { createStore } from 'redux';
import * as withRedux from 'next-redux-wrapper';
import Page from './components/page';
const reducer = (state = {hoge: ''}, action) => {
switch (action.type) {
case 'HOGE':
return {...state, hoge: action.payload};
default:
return state
}
};
const makeStore = (initialState, options) => {
return createStore(reducer, initialState);
};
class App extends React.Component<object> {
public static getInitialProps({ store }: Context): void{
const state = store.getState();
await store.dispatch({type: 'Hoge', payload: 'hoge'});
}
public render(): JSX.Element {
return (
<Page />
);
}
}
export default withRedux(makeStore)(App);
受け取った props
を出力
./components/page.tsx
import * as React from 'React';
const Page = (props) => {
return <div>Prop from Redux {props.hoge}</div>
}
export default connect()(Page);
next-redux-wrapper2系
getInitialPropsを呼び出しreact-redux
に渡しProviderします
。
そのReact
クラスをwithRedux
でラップすることで
ステートを子コンポーネントで参照できます。
./pages/_app.tsximport * as React from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App, { Container } from 'next/app';
import withRedux from 'next-redux-wrapper';
const reducer = (state = { foo: '' }, action) => {
switch (action.type) {
case 'FOO':
return { ...state, foo: action.payload };
default:
return state
}
};
const makeStore = (initialState, options) => {
return createStore(reducer, initialState);
};
class MyApp extends App<object> {
static getInitialProps({ Component, ctx }) {
const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};
return { pageProps };
}
render() {
const { Component, pageProps, store } = this.props;
return (
<Container>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</Container>
);
}
}
export default withRedux(makeStore)(MyApp);
単純に withRedux
の箇所を _app.tsx
に切り出す形になりましたが
pagesがかなりシンプルになりました
各ページごとにストアへ保存するデータを分けてかくケースについては
以前よりかなりスッキリ見やすくなっています。
./components/page.tsximport * as React from 'React';
import Page from './components/page';
class MyApp extends React.Component<object> {
public static getInitialProps({ store }: Context):void{
const state = store.getState();
store.dispatch({type: 'Hoge', payload: 'hoge'});
}
public render(): JSX.Element {
return (
<Page />
);
}
}
export default App;
コネクト関数については以前と同じ形で使用できます。
./pages/index.tsximport * as React from 'React';
const Page = (props: object) => {
return <div>Prop from Redux {props.hoge}</div>
}
export default connect()(Page);
@zeit/next-typescript関連
アップデート後に出たエラー
typescriptLoaderOptionsはサポートされなくなりました
terminalError: `typescriptLoaderOptions` in next.config.js is no longer supported. https://err.sh/next-plugins/typescript-loader-options
解決方法
以下を削除
next.config.js typescriptLoaderOptions: {
transpileOnly: false
}
'next / babel'モジュールを見つけることができません
terminalUnhandledPromiseRejectionWarning: Error: Cannot find module 'next/babel' from '/Users/XXXX/XXXX'
解決方法
.babelrcを作成し下記を記述
.babelrc{
"presets": [
"next/babel",
"@zeit/next-typescript/babel"
]
}
- article
【解決策】Next.js での CORS エラーの原因と対処方法まとめ
- article
Next.js で環境変数を安全に管理するベストプラクティス
- article
shadcn/ui × Next.js:モダンな UI を爆速構築する方法
- article
Next.js の Image コンポーネント徹底攻略:最適化・レスポンシブ・外部 CDN 対応
- article
NextJS で始める Web アプリケーションの多言語・国際化対応の方法
- article
【徹底解説】Next.js での SSG・SSR・ISR の違いと使い分け
- article
Pinia × TypeScript:型安全なストア設計入門
- article
TypeScript で実現するクリーンアーキテクチャ:層分離と依存性逆転の実践
- article
TypeScript × GitHub Copilot:型情報を活かした高精度コーディング
- article
TypeScript による型安全なエラーハンドリング:Result 型と Neverthrow の活用
- article
TypeScript と RxJS を組み合わせたリアクティブプログラミング完全ガイド
- article
Remix × TypeScript:型安全なフルスタック開発
- article
React 開発を加速する GitHub Copilot 活用レシピ 20 選
- article
Prisma の公式ドキュメントを使い倒すためのコツ
- article
GitHub Actions × Node.js:テストとデプロイを自動化する
- article
Pinia × TypeScript:型安全なストア設計入門
- article
Obsidian デイリーノート活用術:毎日の思考ログを資産に変える方法
- article
Git で特定のコミットを打ち消す!git revert の正しい使い方
- blog
iPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来