node12をnode16にupgradeする

背景

  • node 12.16.0のサポートが終了したのでアップグレードを実施した

upgrade時の決め事

  • bootstrapに関してはアップグレードコストが高すぎるのでとりあえず見送った
    • yarn upgrade –-lastestでupgrade対象のパッケージを選択した

発生したエラーをまとめてみた

React 16 -> 18 & React Router v6

ルート

// before
import { render } from 'react-dom'
const root = document.getElementById('root')
render(<Router />, root)
// after
import { createRoot } from 'react-dom/client'
const container = document.getElementById('root')
const root = createRoot(container!) // createRoot(container!) if you use TypeScript
root.render(<Router />)

<Switch /><Routes /> に変更

// before
import React from 'react'
import { BrowserRouter, Switch, Route } from "react-router-dom"
import { Queries } from './pages/Queries'

const Router = () =>
  <BrowserRouter>
    <Switch>
      <Route path="/api-test" component={ApiTest} />
      ...
    </Switch>
  </BrowserRouter>
// after
import React from 'react'
import { BrowserRouter, Routes, Route } from "react-router-dom"
import { Queries } from './pages/Queries'

const Router = () =>
  <BrowserRouter>
    <Routes>
      <Route path="/api-test" element={<ApiTest />} />
      ...
    </Routes>
  </BrowserRouter>

useHistory を useNavigate に変更

// before
import { useHistory } from 'react-router-dom'
const history = useHistory()
history.push(uri)
// after
const navigate = useNavigate()
import { useNavigate } from 'react-router-dom'
navigate(uri)

useParams

// before
import { RouteComponentProps } from "react-router-dom"
interface Props extends RouteComponentProps<{ id: string }> { }

export const Editor: React.FC<Props> = ({ match }) => {
  match.id
  ...
}
// after
import { useParams } from "react-router-dom"

export const Editor: React.FC = () => {
  params = useParams()
  params.id
  ...
}

readonly !!!

TypeScript 型定義の変更

  • import type
  • props を定義する際に children プロパティを明示的に列挙する必要があるということです
interface BaseLayoutType {
  siteName: string
  pageName?: string
  children?: React.ReactNode
}

export const BaseLayout: React.FC<BaseLayoutType> = ({siteName, pageName, children}) => {
  ...
}
  • eslint consistent-indexed-object-style
// before
export const escapeEmptyValues = (queries: {[key: string]: any}) => {
  ...
}
// after
export const escapeEmptyValues = (queries: Record<string, any>) => {
  ...
}
  • Function を型定義として使ってはいけいない
// before
export const CheckBox: React.FC<{ setIds: Function, ...
// after
export const CheckBox: React.FC<{ setIds: React.Dispatch<React.SetStateAction<number[]>>, ...

react-scripts の問題

  • Module not found: Error: Can’t resolve ‘fs’


    https://github.com/C2FO/fast-csv/issues/278

    node_modules/objects-to-csv/package.json
    "browser": {
      "fs": false,
      "os": false,
      "path": false
    }

    を追加して解決できる

  • ‘buffer’ is not defined


    https://github.com/facebook/create-react-app/issues/11756#issuecomment-1001130053

    yarn add react-app-rewired を試してみたが、問題を解消できない

    // config.overrides.js
    const webpack = require('webpack');
    
    module.exports = function override(config) {
        const fallback = config.resolve.fallback || {};
        Object.assign(fallback, {
            "crypto": require.resolve("crypto-browserify"),
            "stream": require.resolve("stream-browserify"),
            "assert": require.resolve("assert"),
            "http": require.resolve("stream-http"),
            "https": require.resolve("https-browserify"),
            "os": require.resolve("os-browserify"),
            "url": require.resolve("url"),
            "fs": false,
            "path": false,
            "process": false
        })
        config.resolve.fallback = fallback;
        config.plugins = (config.plugins || []).concat([
            new webpack.ProvidePlugin({
                process: 'process/browser',
                Buffer: ['buffer', 'Buffer']
            })
        ])
        return config;
    }
    // package.json
    ...
     "dependencies": {
        "@testing-library/jest-dom": "^5.16.1",
        "@testing-library/react": "^12.1.2",
        "@testing-library/user-event": "^13.5.0",
        "assert": "^2.0.0",
        "buffer": "^6.0.3",
        "crypto": "npm:crypto-browserify",
        "crypto-browserify": "^3.12.0",
        "https-browserify": "^1.0.0",
        "os-browserify": "^0.3.0",
        "react": "^17.0.2",
        "react-app-rewired": "^2.1.9",
        "react-dom": "^17.0.2",
        "react-scripts": "5.0.0",
        "rewire": "^6.0.0",
        "stream": "npm:stream-browserify",
        "stream-browserify": "^3.0.0",
        "stream-http": "^3.2.0",
        "url": "^0.11.0",
        "web-vitals": "^2.1.2",
        "web3": "^1.6.1"
      },
      "scripts": {
        "start": "react-app-rewired start",
        "build": "react-app-rewired build",
        "test": "react-app-rewired test",
        "eject": "react-app-rewired eject"
      },

    react-scripts: 4.0.3 に downgrade すると、fs の問題も解消

  • Uncaught ReferenceError: process is not defined


    https://exerror.com/uncaught-referenceerror-process-is-not-defined/

    yarn add -D react-error-overlay@6.0.9 一旦問題を解消できたが、問題の再現方法がわからないので、完全に直ったか心配です。

この記事をシェア

弊社では、一緒に会社を面白くしてくれる仲間を募集しています。
お気軽にお問い合わせください!