Open45

Next.js サービス開発メモ2

かっきーかっきー

別サービスを作り始めたので作業記録用
・Vercel + Firebase 構成
・CSSフレームワークは Bootstrap(開発速度重視)

かっきーかっきー

早速 Firebase init ではまった
https://chaika.hatenablog.com/entry/2021/02/28/150000
firebase logout → login にて既存プロジェクト取得できた。

https://qiita.com/k3ntar0/items/b151034026c8f4a0f447
こっちはロケーション設定を再度入れて直った

.firebaserc
firebase.json
firebase.indexes.json
firebase.rules
まで出力できた。記述を入れて deploy する予定

かっきーかっきー

strage.rules は名前が名前だからかVSCode上でアイコンがつかないな…まぁいいけど

かっきーかっきー

React-Bootstrap Navbar で Dropdown を展開するとエラー

React-Bootstrap の Navbar で Dropdown を使うと初回このエラーがでる

Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>.
    at a
    at LinkComponent (webpack-internal:///./node_modules/next/dist/client/link.js:105:19)
    at a 

Navbar.Item は Aタグを持っているようなのでタグ内にNextのLinkタグを入れるとこのエラーが出るっぽい。最近 <a>タグいらなくなったことと関連しているかな?
Navbar.Item → Navbar.ItemText でエラーは消えたっぽいのでこれで様子見

https://astatsuya.medium.com/react-bootstrapを使ってポートフォリオを作成-626cf4df19f6

かっきーかっきー

Vercel でコンパイルエラーが出る

突然コンパイルエラーが出て Vercel を通らなくなった。

Failed to compile.
./src/pages/_app.tsx:32:10
Type error: 'Component' cannot be used as a JSX component.
  Its element type 'ReactElement<any, any> | Component<any, any, any> | null' is not a valid JSX element.
    Type 'Component<any, any, any>' is not assignable to type 'Element | ElementClass | null'.
      Type 'Component<any, any, any>' is not assignable to type 'ElementClass'.
        The types returned by 'render()' are incompatible between these types.
          Type 'React.ReactNode' is not assignable to type 'import("/vercel/path0/node_modules/@types/react-transition-group/node_modules/@types/react/ts5.0/index").ReactNode'.
            Type 'ReactElement<any, string | JSXElementConstructor<any>>' is not assignable to type 'ReactNode'.
              Property 'children' is missing in type 'ReactElement<any, string | JSXElementConstructor<any>>' but required in type 'ReactPortal'.
  30 |       />
  31 |       <RecoilRoot>
> 32 |         <Component {...pageProps} />
     |          ^
  33 |       </RecoilRoot>
  34 |     </>
  35 |   )
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Error: Command "yarn run build" exited with 1

@types/react のバージョンが噛み合わなくなってるっぽい?

  "resolutions": {
    "@types/react": "17.0.40"
  },

この記述で通るようにはなった。
17のどのバージョン書けばいいのか今の正解探さないと…

https://qiita.com/takano-h/items/69b4d7ee2952c6331b85

かっきーかっきー

突然 ReactーBootstrap が cannot be used as a JSX component を吐き倒す

 yarn add --dev @types/react-dom

これで回避、なんでや

かっきーかっきー

その後も @types/react @types/react-dom あたりを最新(v18)にすると同様のエラーを吐くようになった。package.json の resolution 設定やバージョンダウンで回避していたが面倒になったので React-Bootstrap を完全除去した。その方が楽

かっきーかっきー

React-Hook-From を Zod でバリデーションする

React-Hook-From の内蔵機能でバリデーションしていたが Zod に切り替えする。
業務に直結する部分でややこしい記述を公開されがちなので分かりやすいものを探す。

https://note.com/cyberz_cto/n/n0d608b9380d3

かっきーかっきー

エラーメッセージを

{errors.body && ({errors.body.message})

で受けようとすると以下のエラーが表示される

型 'string | FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined' を型 'ReactNode' に割り当てることはできません。
  型 'FieldError' を型 'ReactNode' に割り当てることはできません。
    型 'FieldError' には 型 'ReactPortal' からの次のプロパティがありません: children, props, keyts(2322)
index.d.ts(1466, 9): 予期された型は、型 'DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>' に対してここで宣言されたプロパティ 'children' から取得されています
(property) message?: string | FieldError | Merge<FieldError, FieldErrorsImpl<any>> | undefined

これで回避できたけどこれでいいのか?

{errors.body && ({errors.body.message as string})

https://qiita.com/derasado/items/98405235010ec0537ef2

かっきーかっきー

Union ではなく discriminatedUnion を使った。
基本部分のスキーマと条件分岐するスキーマに分けて最後に結合して export で多分正常動作

かっきーかっきー
const fileSchema = z.object({
  file: z
    .custom<FileList>()
    .refine((files) => {
  }
})

これであとはなんとかなるか

 .transform((file) => file[0])

ファイルを1つにしてしまえば楽なんでこの処理が多い

かっきーかっきー

refine だと 返せるエラーは1つだけになるのか
superRefine 使えと、よく読めば前に見たこれに書いてある … 神!
https://qiita.com/kalbeekatz/items/09df07f78420ab6b6e57

.refine は一つの項目のバリデーションエラーしか指定できませんが、 .superRefine は .addIssue を複数回呼び出すことで、複数の項目に渡ってバリデーションエラーを指定することができます。

かっきーかっきー

これでいけるかな?

const photoSchema = z
  .object({
    photos: z.custom<FileList>(),
  })
  .superRefine(({ photos }, ctx) => {
    const files = Array.from(photos)
    let message: string[] = []
    files.map((file) => {
      if (file.size > MAX_FILE_SIZE) {
        message.push(
          `ファイルサイズが大きすぎます。${MAX_MB}MB以下のファイルを選択してください [${file.name}]`,
        )
      }
      if (!ACCEPTED_IMAGE_TYPES.includes(file.type)) {
        message.push(`jepg, jpg, png, webpのいずれかの画像を選択してください [${file.name}]`)
      }
    })
    if (message.length > 0) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: message.join(`\n`),
        path: ['photos'],
      })
    }
  })
かっきーかっきー

INPUTタグの onChange イベントに setValue つけてなかったので別のトラブル引き起こしてたので追加した。

かっきーかっきー

ブログなどによくあるタグの入力フォームを作りたいけど良い部品ないなぁ
事例も少なさそうで手作りが多いんかな?

かっきーかっきー

結局デザイン部分を合わせるのが面倒で諦めて手作りし始めた。

かっきーかっきー

HTMLでIncorrect use of <label for=FORM_ELEMENT>

name で指定した値を htmlFor に入れるように部品を修正して対応した

かっきーかっきー

コンソールでこのエラーが出続ける(表示される)ようになった

Third-party cookie will be blocked. Learn more in the Issues tab.

原因は Fireabase Auth かな?

かっきーかっきー

とりあえず デベロッパーツール → コンソール → 選択したコンテンツのみ のチェックを入れてログ部分の表示からは消しておいた。

かっきーかっきー

https://zenn.dev/knowledgework/articles/a716c529a708df
記事中にあったこの辺も読みながら対応を考える
https://qiita.com/advent-calendar/2023/3rd-party-cookie

3rd Party Cookie は Google がモリモリ進めてるけど Firebase は対応に苦慮している感じ
App Router 化でもどうしよっかなみたいな気分になっていてFirebaseから離脱しようかなとか漠然と考えているのが今

かっきーかっきー

FullCalendar v6 アップデート

長い間 v6 を避けていたのでアップデートを実行

  <FullCalendar
 // 中間省略
    dayCellContent={(event: DayCellContentArg) => {
      return (event.dayNumberText = event.dayNumberText.replace('日', ''))
    }}
  />

return を入れないと日付が表示されなくなっていた…まぁそうなんだけど

かっきーかっきー
import { EventClickArg, DayCellContentArg } from '@fullcalendar/core'

あとは上2つの値の参照先が変わっていた