npmパッケージのコードリーディングを100倍しやすくする方法

100倍という表現はだいぶ大げさだと思うのですが、自分はこの方法を使ってからそれくらいnpmパッケージのコードリーディングがかなりしやすくなったので自分がこの方法を知った時の感覚をタイトルに反映させてみました！
方法というのはシンプルで**npmパッケージの気になる箇所にconsole.logを仕込んでデバックをする**だけです！

今回はその「npmパッケージの気になる箇所にconsole.logを仕込んでデバックをする方法」について解説をします
デバックするライブラリは[react-hook-form](https://github.com/react-hook-form/react-hook-form)にしました！

# npmパッケージの気になる箇所にconsole.logを仕込んでデバックをする方法
少し手順が多いのですが、なるべくコピペするだけで良いようにしました！
また、一度この手順を踏めば次からのデバックはかなり楽になるはずです

#### 1 適当なディレクトリを作り、そこにreact-hook-formをクローンする
````
mkdir react-hook-form_debug
cd react-hook-form_debug
git clone https://github.com/react-hook-form/react-hook-form.git
````

#### 2 debug用のreactプロジェクトを作成し、react-hook-formをinstallする
````
yarn create react-app react-hook-form_code-reading --template typescript
cd react-hook-form_code-reading
yarn add react-hook-form
cd ..
````

#### 3 react-hook-formをビルドする
````
cd react-hook-form
yarn
yarn build
cd ..
````

#### 4 react-hook-formのパッケージと先程作成したreactプロジェクトをリンクさせる
````
cd react-hook-form_code-reading/node_modules/react-hook-form
rm -rf dist
ln -s ../../../react-hook-form/dist
cd ../..
````
※[lnコマンド](https://wa3.i-3-i.info/word14607.html#:~:text=%E3%80%8Cln%E3%80%8D%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AF%E3%80%8C%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB,%E3%81%A8%E3%81%8B%EF%BC%89%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%A7%E3%81%99%E3%80%82)はファイルやディレクトリのリンクを作るときに使うコマンド

#### 5 reactプロジェクトでreact-hook-formを使用する
https://react-hook-form.com/get-started のコードをコピペしましょう
````App.tsx
import React from "react";
import { useForm, SubmitHandler } from "react-hook-form";

type Inputs = {
  example: string,
  exampleRequired: string,
};

export default function App() {
  const { register, handleSubmit, watch, formState: { errors } } = useForm<Inputs>();
  const onSubmit: SubmitHandler<Inputs> = data => console.log(data);

  console.log(watch("example")) // watch input value by passing the name of it

  return (
    /* "handleSubmit" will validate your inputs before invoking "onSubmit" */
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* register your input into the hook by invoking the "register" function */}
      <input defaultValue="test" {...register("example")} />
      
      {/* include validation with required or other standard HTML validation rules */}
      <input {...register("exampleRequired", { required: true })} />
      {/* errors will return when field validation fails  */}
      {errors.exampleRequired && <span>This field is required</span>}
      
      <input type="submit" />
    </form>
  );
}
````

#### 6 reactプロジェクトをスタートさせる
````
yarn start
````

もし以下のようなReactの重複参照エラーが発生した場合はreact-hook-formのReactのバージョンを利用する
````
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
````

````
cd node_modules
rm -Rf ./react ./react-dom
ln -s ../../react-hook-form/node_modules/react
ln -s ../../react-hook-form/node_modules/react-dom
````
※React18を利用する場合はindex.tsxファイルも修正する必要が有ります
````index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(<App />, document.getElementById("root"));

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

````

#### 7 react-hook-formの`handleSubmit`関数にconsole.logを仕込む
````createFormControl.ts
  const handleSubmit: UseFormHandleSubmit<TFieldValues> =
    (onValid, onInvalid) => async (e) => {
      console.log("submit!!") // console.logを追加
      if (e) {
        e.preventDefault && e.preventDefault();
        e.persist && e.persist();
      }
      let hasNoPromiseError = true;
      let fieldValues: any = cloneObject(_formValues);

      _subjects.state.next({
        isSubmitting: true,
      });

      try {
        if (_options.resolver) {
          const { errors, values } = await _executeSchema();
          _formState.errors = errors as FieldErrors<TFieldValues>;
          fieldValues = values;
        } else {
          await executeBuildInValidation(_fields);
        }

        if (
          isEmptyObject(_formState.errors) &&
          Object.keys(_formState.errors).every((name) => get(fieldValues, name))
        ) {
          _subjects.state.next({
            errors: {} as FieldErrors<TFieldValues>,
            isSubmitting: true,
          });
          await onValid(fieldValues, e);
        } else {
          if (onInvalid) {
            await onInvalid({ ..._formState.errors }, e);
          }

          _options.shouldFocusError &&
            focusFieldBy(
              _fields,
              (key) => get(_formState.errors, key),
              _names.mount,
            );
        }
      } catch (err) {
        hasNoPromiseError = false;
        throw err;
      } finally {
        _formState.isSubmitted = true;
        _subjects.state.next({
          isSubmitted: true,
          isSubmitting: false,
          isSubmitSuccessful:
            isEmptyObject(_formState.errors) && hasNoPromiseError,
          submitCount: _formState.submitCount + 1,
          errors: _formState.errors,
        });
      }
    };

````

#### 8 react-hook-formをビルドする
別のターミナルを起動して
````
cd react-hook-form
yarn build
````
buildのwatchモードを使いたかったのですが、うまく動かなかったので断念

#### 9 ブラウザで確認する
![Screenshot from 2022-04-20 00-24-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656522/a2989102-4f20-e2d9-edc9-cd49f040dca4.png)
**submit!!というのがlogで出力されているのを確認することが出来ると思います！**
もし反映されていなかったらリロードしてみてください

いかがだったでしょうか？
この方法は他のパッケージのコードリーディングをするときもかなり使えると思うので、是非ためしてみてください！

参考資料
https://github.com/apollographql/apollo-client/blob/main/CONTRIBUTING.md