20190526のReactに関する記事は4件です。

nodejs製のwebアプリにnextjsを組み込むにはどのようにすればいいか試してみた

はじめに

以下の疑問点を解決するために試したことをまとめた。

  1. nodejs製のwebアプリにnextjsを組み込むにはどのようにすればいいか?
  2. DBに保存した値をSSRするためにはどのようにすればいいのか?
  3. ページの遷移はどのようにすればいいのか?

アプローチ

ユーザ別に登録できるタスクリストを作った。
repository
Kapture 2019-05-26 at 23.01.00.gif

koajsでwebアプリの基盤を作り、typeormでDB操作を行う。
DBはdocker上にmysqlを立てた。
ormはtypeormを使用した。
その他細かいライブラリについてはpackage.jsonを参照。

構成

全ユーザの一覧が見れるindexページと、タスクの一覧が見えるtaskページがある。
indexページではユーザとタスクのcrudが可能。
taskページではタスク一覧の読み取りのみ可能とした。

データの構造は次の通り。
- server/entities/User.ts
- server/entities/Task.ts

ユーザを削除すると紐付いたタスクが自動的に削除されるように Task.useronDelete: 'CASCADE' オプションを付与した。

nextに関係する処理があるファイルには★をつけた。

.
├── README.md
├── docker
│   └── db
│       └── my.conf
├── docker-compose.yml
├── models <- tableとapiの項目が一致するので同一のinterfaceを使用することにした
│   ├── Task.ts
│   └── User.ts
├── next.config.js
├── nodemon.json
├── ormconfig.json
├── package-lock.json
├── package.json
├── pages <- フロント側の処理。ちょっとnextが入ってるがほとんど普通のreact
│   ├── index.tsx ★
│   └── tasks.tsx ★
├── repositories <- api接続処理
│   ├── helpers.ts
│   ├── tasks.ts
│   └── users.ts
├── server
│   ├── api <- controllerに当たる部分。apiリクエストに応答する処理。
│   │   ├── tasks.ts
│   │   └── users.ts
│   ├── commands <- サーバ処理とは一切関係ない。
│   │   ├── generateData.ts <- データを作る。 npm run generate:data で起動する。
│   │   └── route.ts <- routingを確認する。 npm run route で起動する。
│   ├── createRouter.ts ★ <- routerを作るentrypoint
│   ├── entities <- tableの項目とマッピングするentity
│   │   ├── Task.ts
│   │   └── User.ts
│   ├── helpers.ts <- DB接続処理がある。commandsでも使用するので分けた。
│   ├── index.ts ★ <- entrypoint。npm start で起動する。
│   ├── next.ts ★ <- nextを直接触る処理はここに閉じ込めた。
│   ├── repositories <- repositoriesと名前をつけたがuseCase層と合体させた。
│   │   ├── TaskRepository.ts
│   │   └── UserRepository.ts
│   └── views ★ <- controllerに当たる部分。
│       ├── index.ts
│       └── tasks.ts
├── tsconfig.json
└── tsconfig.server.json

結論

1. nodejs製のwebアプリにnextjsを組み込むにはどのようにすればいいか?

1. 初期化処理でprepare()

まずserverのentrypointである server/index.tsprepare() を行う。
それなりに時間がかかる処理なので、DB接続処理と同時に行うと時間節約できる。

await Promise.all([
  connectDatabase(),
  prepare()
])

2. routingを設定する

すべてのリクエストにnextのhandleを設定する。

server/next.ts
const handler = app.getRequestHandler()
// omit...
export async function handle(ctx: BaseContext) {
  await handler(ctx.req, ctx.res)
  ctx.respond = false
}
server/createRouter.ts
import { handle } from './next'
// omit...
export default function () {
  const router = new Router()
  const assign = pipe(
    views,
    apiUsers,
    apiTasks,
    next
  )
  return assign(router)
}

// omit...

function next(router: Router) {
  return router
    .get('*', handle) // <- これが必要
}

router.get('*', handle) で設定しないと以下のエラーが発生する。

  <-- GET /_next/on-demand-entries-ping?page=/
  --> GET /_next/on-demand-entries-ping?page=/ 404 1ms -
  <-- GET /_next/static/development/pages/index.js?ts=1558873127678
  --> GET /_next/static/development/pages/index.js?ts=1558873127678 404 0ms -
  <-- GET /_next/static/development/pages/_app.js?ts=1558873127678
  --> GET /_next/static/development/pages/_app.js?ts=1558873127678 404 1ms -
  <-- GET /_next/static/runtime/webpack.js?ts=1558873127678
  --> GET /_next/static/runtime/webpack.js?ts=1558873127678 404 1ms -
  <-- GET /_next/static/runtime/main.js?ts=1558873127678
  --> GET /_next/static/runtime/main.js?ts=1558873127678 404 0ms -
  <-- GET /_next/static/development/dll/dll_599a58a60c43245180de.js?ts=1558873127678
  --> GET /_next/static/development/dll/dll_599a58a60c43245180de.js?ts=1558873127678 404 0ms -
  <-- GET /_next/static/development/pages/index.js?ts=1558873127678
  --> GET /_next/static/development/pages/index.js?ts=1558873127678 404 1ms -
  <-- GET /_next/static/development/pages/_app.js?ts=1558873127678
  --> GET /_next/static/development/pages/_app.js?ts=1558873127678 404 1ms -
  <-- GET /_next/static/runtime/webpack.js?ts=1558873127678
  --> GET /_next/static/runtime/webpack.js?ts=1558873127678 404 1ms -
  <-- GET /_next/static/runtime/main.js?ts=1558873127678
  --> GET /_next/static/runtime/main.js?ts=1558873127678 404 0ms -

一見viewへのリクエストに書けばいいように見える。
そこで server/views/index.ts に書いてみたが、 await render(ctx.req, ctx.res, '/', query) の後に await handler(ctx.req, ctx.res) を差し込めば上のエラーが、 await render(ctx.req, ctx.res, '/', query) より前に差し込めば下のエラーが発生する。

fetch is not defined
ReferenceError: fetch is not defined
    at _callee$ (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/.next/server/static/development/pages/index.js:886:13)
    at tryCatch (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/node_modules/regenerator-runtime/runtime.js:62:40)
    at Generator.invoke [as _invoke] (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/node_modules/regenerator-runtime/runtime.js:288:22)
    at Generator.prototype.(anonymous function) [as next] (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/node_modules/regenerator-runtime/runtime.js:114:21)
    at asyncGeneratorStep (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/.next/server/static/development/pages/index.js:186:24)
    at _next (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/.next/server/static/development/pages/index.js:208:9)
    at /Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/.next/server/static/development/pages/index.js:215:7
    at new Promise (<anonymous>)
    at new F (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/node_modules/core-js/library/modules/_export.js:36:28)
    at Module.<anonymous> (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/.next/server/static/development/pages/index.js:204:12)
    at Module.all (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/.next/server/static/development/pages/index.js:873:15)
    at _callee8$ (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/.next/server/static/development/pages/index.js:696:75)
    at tryCatch (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/node_modules/regenerator-runtime/runtime.js:62:40)
    at Generator.invoke [as _invoke] (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/node_modules/regenerator-runtime/runtime.js:288:22)
    at Generator.prototype.(anonymous function) [as next] (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/node_modules/regenerator-runtime/runtime.js:114:21)
    at asyncGeneratorStep (/Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/.next/server/static/development/pages/index.js:186:24)

1. レンダリング処理を行う

次項(2. DBに保存した値をSSRするためにはどのようにすればいいのか?)で説明する。

2. DBに保存した値をSSRするためにはどのようにすればいいのか?

views/index.tsviews/tasks.ts にあるようにrender関数に 文字列化した データを設定する。

export default async function (ctx: BaseContext) {
  const users = await getRepository().all()
  const stringified = JSON.stringify(users)
  const query = { users: stringified }
  await render(ctx.req, ctx.res, '/', query) // <- ここで設定
  ctx.respond = false
}

pages/index.tsxpages/tasks.tsx にある通り、 getInitialProps でデータを取得する。

Page.getInitialProps = async (context: NextContext) => {
  const renderingOnServer = context.query.users !== undefined
  if (renderingOnServer) {
    // server処理の場合はqueryに文字列が設定されているので
    // JSON.parseして使用する。
    const raw = context.query.users as string
    const users = JSON.parse(raw)
    return { users }
  }
  // ブラウザ側ならapiからデータを取得する。
  const users = await UsersRepository.all()
  return { users }
}

生成されたhtmlを見てみると、以下のようにjsonが書き込まれていることがわかる。

<script id="__NEXT_DATA__" type="application/json">{"dataManager":"[]","props":{"pageProps":{"users":[{"id":1,"name":"山田","tasks":[{"id":1,"userId":1,"text":"皿洗い"},{"id":2,"userId":1,"text":"買い物"}]},{"id":2,"name":"佐藤","tasks":[{"id":3,"userId":2,"text":"草むしり"},{"id":4,"userId":2,"text":"押入れの片付け"}]},{"id":3,"name":"平田","tasks":[{"id":5,"userId":3,"text":"野菜の皮むき"}]},{"id":4,"name":"山本","tasks":[{"id":6,"userId":4,"text":"カレー作り"}]},{"id":5,"name":"柴田","tasks":[{"id":7,"userId":5,"text":"食卓の準備"},{"id":8,"userId":5,"text":"押入れの片付け"}]}]}},"page":"/","query":{"users":"[{\"id\":1,\"name\":\"山田\",\"tasks\":[{\"id\":1,\"userId\":1,\"text\":\"皿洗い\"},{\"id\":2,\"userId\":1,\"text\":\"買い物\"}]},{\"id\":2,\"name\":\"佐藤\",\"tasks\":[{\"id\":3,\"userId\":2,\"text\":\"草むしり\"},{\"id\":4,\"userId\":2,\"text\":\"押入れの片付け\"}]},{\"id\":3,\"name\":\"平田\",\"tasks\":[{\"id\":5,\"userId\":3,\"text\":\"野菜の皮むき\"}]},{\"id\":4,\"name\":\"山本\",\"tasks\":[{\"id\":6,\"userId\":4,\"text\":\"カレー作り\"}]},{\"id\":5,\"name\":\"柴田\",\"tasks\":[{\"id\":7,\"userId\":5,\"text\":\"食卓の準備\"},{\"id\":8,\"userId\":5,\"text\":\"押入れの片付け\"}]}]"},"buildId":"development","dynamicBuildId":false}</script>

server側の処理のときならDBに接続できるのでは?と思い以下のようにしたがだめだった。

Page.getInitialProps = async (context: NextContext) => {
  const renderingOnServer = context.query.users !== undefined
  if (renderingOnServer) {
    const UserRepository = require('../server/repositories/UserRepository')
    const Container = require('typedi')
    const repository = Container.get(UserRepository)
    const users = await repository.all()
    return  { users }
    // const raw = context.query.users as string
    // const users = JSON.parse(raw)
    // return { users }
  }
  const users = await UsersRepository.all()
  return { users }
}
./server/repositories/UserRepository.ts
SyntaxError: /Users/h-h/h_h/2019-05-25-nextjs-koa-mysql/server/repositories/UserRepository.ts: Support for the experimental syntax 'decorators-legacy' isn't currently enabled (6:1):

  4 | import { User } from '../entities/User'
  5 |
> 6 | @Service()
    | ^
  7 | @EntityRepository(User)
  8 | export class UserRepository {
  9 |

SyntaxErrorなのでbabelの設定次第では行けそうな気もするが、できたとしてもviewにDB操作するような処理を書くのは好きじゃないので考えるのをやめた。

3. ページの遷移はどのようにすればいいのか?

pages/index.tsxpages/tasks.tsxにある通り次のようにする。

import Link from 'next/Link'

// omit...

<Link href="/tasks">
  <a>> tasks</a>
</Link>

参考資料

nextの組み方を調べたときに確認した。
- custom-server-koa

nextでtypescriptを使えるようにするために確認した。
- custom-server-typescript
- with-typescript

nodemonの設定方法を確認した。
- custom-server-nodemon

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

create-react-app が Node.js 12.0.0 で動かない

問題

次のように create-react-app を動かそうとした(環境は Mac):

$ npx create-react-app hello-react --typescript
$ cd hello-react
$ yarn start

しかしエラー:

#
# Fatal error in , line 0
# Check failed: U_SUCCESS(status).
#
#
#
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

原因

ググったところ同様の問題を扱った issue を見つけ、そのなかで次のコメントを見つけた:

If anyone is using Node.js 12.0.0, try to upgrade to 12.1.0. For me it is now working.

ちょうど 12.0.0 をインストールしていたので、12.1.0 にアップグレードすることにした。

解決

  1. まず、Node.js 12.1.0 をインストールして、バージョンを 12.1.0 に切り替える(ここの詳細は別の記事に書きました
  2. yarn をグローバルにインストールし直す(npm install -g yarn
  3. プロジェクトルート(hello-react)に移動し、node_modules を削除して、yarn install し直す(一応)
  4. yarn start し直す

これで無事アプリが起動!

スクリーンショット 2019-05-26 22.32.22.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

安全に React Hooks を使用する

React Hooks はとても便利で、Custom Hooks を上手く実装することで、再利用性の高いコードを、簡潔に実装することができます。

しかし、Hooksを不用意に使用してしまうと 意図しない無限ループに陥ったり、正しくStateが反映されなかったりすることがあります。

useCallback を使い無限ループを避ける

例えば以下のようなDivの大きさを取得するuseRectというCustom Hooksについて考えてみます。

const useRect = () => {
  const [rect, setRect] = useState<ClientRect | DOMRect>();
  const ref = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    const target = ref.current;
    if (target) {
      const rect = target.getBoundingClientRect();
      setRect(rect);
    }
  }, []);

  return { ref, rect };
};

このHooksは以下のようにrefをセットして使用できます。

const App: React.FC = () => {
  const { ref, rect } = useRect();

  return (
    <div className="target" ref={ref}>
      <p>Width: {rect ? `${rect.width}px` : "undefined"}</p>
      <p>Height: {rect ? `${rect.height}px` : "undefined"}</p>
    </div>
  );
};

ここで、windowの大きさが変化した時に、divの大きさを取得し直したいと考えたとします。この場合は、handleResizeのようなhandlerを記述し、EventListenerのresizeイベントに登録することになるでしょう。

import debounce from "lodash/debounce";

export const useRect = () => {
  const [rect, setRect] = useState<ClientRect | DOMRect>();
  const ref = useRef<HTMLDivElement | null>(null);

  const resize = () => {
    if (ref.current) {
      const rect = ref.current.getBoundingClientRect();
      setRect(rect);
    }
  };
  useEffect(() => resize(), []);

  const handleResize = debounce(resize, 16);
  useEffect(() => {
    window.addEventListener("resize", handleResize);
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, [handleResize]);

  return { ref, rect };
};

このHooksは一見正しく動作するように見えます。しかし、resize関数は、描画のたびに毎回生成されてしまいます。ここで問題になるのは、resizeを呼び出すとresize関数が新たに生成されてしまう、ということです。

例えば、うっかり、mount時にresizeを呼び出している useEffect を誤って以下のように書き換えてしまうとどうなるでしょうか?

 useEffect(() => resize(), [resize]);

この場合は、resize を呼び出すと resize が生成され また useEffect が実行されてしまい、無限に処理が実行されてしまいます。

ここで、 eslintreact-hooks/exhaustive-deps を入れている場合は、次のような warning を出してくれます。

./src/useRect.ts
  Line 8:  The 'resize' function makes the dependencies of useEffect Hook (at line 18) change on every render. To fix this, wrap the 'resize' definition into its own useCallback() Hook  react-hooks/exhaustive-deps

この warning に書かれている通り、この無限ループを避けるためには、useCallbackresize を囲むことで、描画ごとにresizeが生成されることを避ける必要があります。

const resize = useCallback(() => {
  if (ref.current) {
    const rect = ref.current.getBoundingClientRect();
    setRect(rect);
  }
}, []);

useCallback の代わりに useMemo を使っても良いでしょう。

const resize = useMemo(() => {
  return () => {
    if (ref.current) {
      const rect = ref.current.getBoundingClientRect();
      setRect(rect);
    }
  }
}, []);

適切にメモ化をすることで、描画ごとにresizeは生成されることはなくなり、無限ループを回避できるようになりました!

react-hooks/exhaustive-deps を設定する

useCallback による関数のメモ化ができていても、第二引数が正しく設定されていないと、state の更新がうまくいかない場合があります。

例えば以下のような簡単な counter を考えます。

const App: React.FC = () => {
  const [count, setCount] = useState(0);

  const addCount = useCallback(() => {
    setCount(count + 1);
  }, []);

  return (
    <div className="target">
      <button onClick={() => addCount()}>Add Count</button>
      <p>count: {count}</p>
    </div>
  );
};

この例では、addCount が 描画の最初にメモ化されていますが、メモ化されているせいでcount の参照が古いままになっています。この例では、useCallback には count を第二引数に加える必要があります。

const addCount = useCallback(() => {
  setCount(count + 1);
}, [count]);

react-hooks/exhaustive-deps を lint の rule として設定していると、この場合も以下のように warning を出してくれます。

./src/App.tsx
  Line 9:  React Hook useCallback has a missing dependency: 'count'. Either include it or remove the dependency array. You can also do a functional update 'setCount(c => ...)' if you only need 'count' in the 'setCount' call  react-hooks/exhaustive-deps

react-hooks/exhaustive-depsは、Hooks内で参照している変数が第二引数に加えられていない場合に warning を出します。この lint を入れておくことで、古い変数を参照してしまうケースを避けることができます。

さらに、このreact-hooks/exhaustive-deps は賢く、useState の dispatcher や、useRef の current など設定の必要がないものは除外してくれます。

また、 react-hooks/exhaustive-deps を設定しておく副次的なメリットとして、仮に第二引数を意図的に変更する場合も、コメントでdisableにする必要があるということが挙げられます。

例えば、Mount時にだけ呼び出したい場合や、使用しているライブラリが毎描画ごとに変更される場合など、第二引数を意図的に変えたい時、自分たちのチームでは、なぜ react-hooks/exhaustive-deps を disable するかのコメントを eslint-disable のコメントとともに付記しています。

このルールによって、Hooksの引数を誤って変更してしまうリストを減らすことができました。

useEffect(() => {
// ...
// apolloClient は毎描画ごとに変更されてしまうため第二引数から除外する
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [paramId]);

React の公式ドキュメントでも、react-hooks/exhaustive-deps を設定することをお勧めしています。最新のcreate-react-app では、デフォルトでこのルールが設定されています。

We recommend using the exhaustive-deps rule as part of our eslint-plugin-react-hooks package. It warns when dependencies are specified incorrectly and suggests a fix.
cf. Hooks API Reference – React

stop-runaway-react-effects

react-hooks/exhaustive-deps によるルールチェックは万能ではなく、間接的に実行する関数が変化する場合をチェックできません。例えば、useRect の例にある、 handleResize を使用している useEffect の処理を以下のように書き換えた場合、

useEffect(() => {
  handleResize();
  window.addEventListener("resize", handleResize);
  return () => {
    window.removeEventListener("resize", handleResize);
  };
}, [handleResize]);

この場合も handleResizeresize を呼び出すため、useCallback でメモ化されていない場合は、無限に処理が走ってしまいますが、react-hooks/exhaustive-deps は warning を出してくれません。

そこで、自分たちのチームは stop-runaway-react-effects を使用して、 useEffect の無限ループがないか監視しています。

このライブラリは useEffectuseLayoutEffect の 処理を tracking して、ある一定の期間で useEffect の実行回数が閾値を超えた場合に warning を表示してくれます。また、その warning で第二引数を表示してくれるので、どこの引数が変更されてしまっているかを確認することができます。

導入は簡単で、index に以下のコードを追加するだけです。時間当たりの閾値を設定することもできます。

import { hijackEffects } from "stop-runaway-react-effects";

if (process.env.NODE_ENV !== "production") {
  hijackEffects();
  // hijackEffects({ callCount: 10, timeLimit: 1000 });
}

無限ループが起きている場合には、以下のようにwarningが出ます。

Screen Shot 2019-05-26 at 20.12.09.png

まとめ

React Hooksの引数の設定・メモ化を適切に行うことで、より安全にHooksを使用することができます。具体的には、以下の3つに留意しましょう。

  • 適切にメモ化を行い無限ループを避ける
  • 適切なメモ化を行うためにreact-hooks/exhaustive-depsを設定する
  • stop-runaway-react-effects で無限ループを監視する(お好み)

冒頭にも書きましたが、Hooksを使用することで、再利用性の高いコードを、簡潔に実装することができます。これは、可読性やパフォーマンスの向上にも繋がります。ぜひ安全に、そして積極的にHooksを使っていきましょう!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactのversionを上げるためにyarnを実行したらfseventsでERRORが発生した

久しぶりに個人で作っているPortfolioのversionを上げようとしたらfseventsが原因でエラーが発生したのでメモ。

yarnを実行したら下記のようなエラーが発生する

warning Error running install script for optional dependency: "/Users/minusfive/dev/oss/ember-cli-sass-variables-export/node_modules/fsevents: Command failed.
Exit code: 1
Command: node install
Arguments:
Directory: /Users/minusfive/dev/oss/ember-cli-sass-variables-export/node_modules/fsevents
Output:
node-pre-gyp info it worked if it ends with ok
node-pre-gyp info using node-pre-gyp@0.6.39
node-pre-gyp info using node@10.4.0 | darwin | x64
node-pre-gyp info check checked for \"/Users/minusfive/dev/oss/ember-cli-sass-variables-export/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node\" (not found)
node-pre-gyp http GET https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.1.3/fse-v1.1.3-node-v64-darwin-x64.tar.gz
node-pre-gyp http 404 https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.1.3/fse-v1.1.3-node-v64-darwin-x64.tar.gz
node-pre-gyp ERR! Tried to download(404): https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.1.3/fse-v1.1.3-node-v64-darwin-x64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for fsevents@1.1.3 and node@10.4.0 (node-v64 ABI, unknown) (falling back to source compile with node-gyp)
node-pre-gyp http 404 status code downloading tarball https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.1.3/fse-v1.1.3-node-v64-darwin-x64.tar.gz
node-pre-gyp ERR! Tried to download(undefined): https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.1.3/fse-v1.1.3-node-v64-darwin-x64.tar.gz
node-pre-gyp ERR! Pre-built binaries not found for fsevents@1.1.3 and node@10.4.0 (node-v64 ABI, unknown) (falling back to source compile with node-gyp)
node-pre-gyp http Connection closed while downloading tarball file
gyp info it worked if it ends with ok
gyp info using node-gyp@3.6.2
gyp info using node@10.4.0 | darwin | x64
gyp info ok
gyp info it worked if it ends with ok
gyp info using node-gyp@3.6.2
gyp info using node@10.4.0 | darwin | x64

以下略

yarn startもERRORが発生してしまい、1~6の解決策がyarn側から提示されたがうまくいかなかった。

これはfseventsNode.jsのversionが対応していないために起こるエラーで、fseventsv1.2.9で解決されている。

versionを上げるにはpackage.jsonにて以下のように記述して、yarnを実行する。

package.json
"resolutions": {
  "**/**/fsevents": "^1.2.9"
}

これ以外の解決策で見つけたのは以下の通り

  • rm -r /node_modules => rm yarn.lock => yarn
  • yarn cache clean => yarn upgrade
  • yarn upgradeを実行すると解決するといったissueが多かった

fseventsに関する解決策の参考URI: https://github.com/yarnpkg/yarn/issues/5962

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む