Open87

Next.js サービス開発メモ

かっきーかっきー

Next.js 12.1 にしたら警告が出るようになった。

Do not add react_devtools_backend.js:4061 Do not add stylesheets using next/head (see <link rel="stylesheet"> tag with href="https://fonts.googleapis.com/icon?family=Material+Icons"). Use Document instead. 

https://nextjs.org/docs/messages/no-stylesheets-in-head-component
document使えや、って言ってるのかな?

Layout.tsx
<Head>
  <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
</Head>

この部分が気に入らないのか。
これなんで入れてたんだっけかな

あー最初にアイコンの使い方覚えた時のやり方と React Icons からのアイコンが混在してるのか。
最初のやつがそんな書き方したらパフォーマンスに悪いでしょって言われてると。
(そんな書き方=Layout の HEAD に link rel ぶっこむ。)

すべて React Icons に置き換えた。
Firebase Auth が遅いと思っていた部分も単にアイコンを外から持ってきていたから…dasee-

かっきーかっきー

Next.js 全般メモ

カスタムフックがだんだん Controller っぽい実装になってきているけどこれはどうなのかな。

かっきーかっきー

components フォルダ配下に layout フォルダ、forms フォルダ を作成した。
forms フォルダは React Hook Forms 専用のコンポーネント入れ。
なんちゃらデザインは分子の英単語が書けないので採用しないと決めている

かっきーかっきー

dayjsの変換処理が各ページに散在しすぎている&同じ処理を書いている感じなので一部まとめ始めた。

かっきーかっきー

Windows側の環境構築

https://docs.microsoft.com/ja-jp/windows/dev-environment/javascript/nextjs-on-wsl
MSさんのこういうの割りと手厚いよね

コマンドプロンプトからcodeで起動

Windows側で手癖になっててMacでもやろうとして動かなかったらこれが必要だった。
https://webrandum.net/vscode-terminal/

かっきーかっきー

Recoil 0.7 で例のエラーが激しくなっている件

Expectation Violation: Duplicate atom key "user". This is a FATAL ERROR in
      production. But it is safe to ignore this warning if it occurred because of
      hot module replacement.
    at expectationViolation (/Users/user/Code/ictsss/node_modules/recoil/cjs/recoil.js:551:19)
    at registerNode (/Users/user/Code/ictsss/node_modules/recoil/cjs/recoil.js:666:9)
    at baseAtom (/Users/user/Code/ictsss/node_modules/recoil/cjs/recoil.js:8183:16)
    at atom (/Users/user/Code/ictsss/node_modules/recoil/cjs/recoil.js:8238:12)
    at eval (webpack-internal:///./src/hooks/authentication.ts:19:63)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)

Duplicate atom key いつか消えてくれると思いきや激しくなってるんですけど…。
そしてコンソールから無視を押してしまったら戻し方がわからないという

かっきーかっきー

Recoil のあのエラーを消せるやつ?

https://github.com/junhoyeo/next-intercept-stdout

Duplicate atom key "xxxxxxxxxx".
This is a FATAL ERROR in production.
But it is safe to ignore this warning if it occurred because of hot module replacement.

試してみたいような、余計なものは入れたくないような…。

かっきーかっきー

Ctrl + C で止めた時にエラー出るようになったので諦めて消した。

TypeError: callback is not a function
    at interceptor (/Users/user/Code/ictsss/node_modules/intercept-stdout/intercept-stdout.js:40:16)
    at WriteStream.write (/Users/user/Code/ictsss/node_modules/intercept-stdout/intercept-stdout.js:25:14)
    at process.handleSessionStop (/Users/user/Code/ictsss/node_modules/next/dist/cli/next-dev.js:109:20)
かっきーかっきー

React18関連

@types/react を 18.0 にしたら Recoil でエラーが出た。
@types/react@17.0.39 に戻した。
React 18 に上げるのを止めているのに間違えて入れてしまった。

かっきーかっきー

FullCallendar がいまいちで対応が終わるまで移行できない感じ。
やっぱこの手の重厚なやつ入れるとそうなるよなー。

かっきーかっきー

ということで React18 にアップデートした。

Warning: A title element received an array with more than 1 element as children. In browsers title Elements can only have Text Nodes as children. If the children being rendered output more than a single text node in aggregate the browser will display markup and comments as text in the title and hydration will likely fail and fall back to client rendering
    at title
    at head
    at Head (webpack-internal:///./node_modules/next/dist/pages/_document.js:294:1)
    at html
    at Html (webpack-internal:///./node_modules/next/dist/pages/_document.js:260:106)
    at Document (webpack-internal:///./node_modules/next/dist/pages/_document.js:16:1)

今度はこの警告が出るな。なんだろこれ

かっきーかっきー

ical-generator で Failed to compile (Module not found: Can't resolve 'fs')

スケジュールデータをiCal形式に出力しようとして、ical-generatorを入れたらこのエラーが出た。

./node_modules/ical-generator/dist/calendar.js:9:0
Module not found: Can't resolve 'fs'

Import trace for requested module:
./node_modules/ical-generator/dist/index.js
./src/pages/admins/icalexport.tsx

https://nextjs.org/docs/messages/module-not-found
かっきーかっきー

icalのファイルをpublic出力しておいてそれをURL参照する。
再生成時にはファイル名を変更して旧URLでは参照できないようにする。
やりたいのはこの感じかな。

かっきーかっきー

iCalendar形式のファイルダウンロードは出来た。
URLで提供すれば変更は自動反映される?しない?
したい場合はどこかに吐き出さないといけない?どうやる?

かっきーかっきー

getStaticProps に慣れてきたのでこっちも何とかなりそうかな?
fallback true か getServerSideProps どっちかで ical形式吐き出せば予定データに連動したURLを発行できる?

かっきーかっきー

React Dropzone 12.1.0 → 14.0.1 でエラー

型 'string' を型 'Accept' に割り当てることはできません。ts(2322)

  const { getRootProps, getInputProps, open, isDragActive } = useDropzone({
    onDrop,
    onFileDialogCancel,
    onDropAccepted,
    onDropRejected,
    accept: 'text/plain, text/csv, application/vnd.ms-excel',
    noClick: true,
    noKeyboard: true,
    multiple: false,
    maxSize: Infinity,
  })
かっきーかっきー

ReactHookForm のコンポーネントをそろそろ分離したい

https://zenn.dev/erukiti/articles/webform-2021
https://zenn.dev/manalink/articles/manalink-react-hook-form-v7
https://zenn.dev/yuitosato/articles/292f13816993ef

ReactHookForm を使ってないコンポーネントとは一緒にしないまではやってきた。
ただし ReactHookForm を使った方はベタ書きしてたのでそろそろ共通化したい。

かっきーかっきー

まず、親から name と control 引っ張り回してくる
子の中で useController で field 取ってきて配れば最低限ってところかな?

かっきーかっきー

とりあえず簡単な所でうまく動いた。

import { Control, useController } from 'react-hook-form'

// Props
type Props = {
  name: string
  control: Control
  required: string
  min: number
  max: number
}

// InputFormNumeric
export const InputFormNumeric: React.FC<Props> = (props) => {
  const { name, control, required, min, max } = props
  const { field } = useController({
    name,
    control,
  })

  // return
  return (
    <input
      className="form-control"
      type="number"
      inputMode="numeric"
      {...control.register(field.name, { required: required, min: min, max: max })}
    />
  )
}
かっきーかっきー

field.name なんてしなくても name 引っ張ってきてるんだから useController 要らないじゃん。

かっきーかっきー

GitHub に上げたリポジトリの続きから作業したい

git init
git remote add origin git@github.com:kakimoty/hlthobs.git
git pull origin main

ってやっても master ブランチが追加されてしまう。

かっきーかっきー

git init した時に master がデフォで作られているっぽい。
.git フォルダ の HEAD ファイルが

ref: refs/heads/master

となっていたのを

ref: refs/heads/main

に変えてから

git pull origin main

をすればOK

かっきーかっきー

テンプレートプロジェクトがうまく引用されない

URL指定の最後に .git がついていた…。

かっきーかっきー

nextjs-progressbar

https://github.com/apal21/nextjs-progressbar
とりあえず追加してみた。
個人的にはこういうの使わない事が多いんだけど、まぁ手軽なので…。

かっきーかっきー

いくつか入れて試したけど、1つを残してやっぱり消した。
求められたら嫌々入れるぐらいのスタンスでいこうと思う。

かっきーかっきー

next.config.js のエラー

warn  - Invalid next.config.js options detected: 
[
  {
    "instancePath": "",
    "schemaPath": "#/additionalProperties",
    "keyword": "additionalProperties",
    "params": {
      "additionalProperty": "webpack5"
    },
    "message": "must NOT have additional properties"
  }
] 
See more info here: https://nextjs.org/docs/messages/invalid-next-config

webpack5: true って無くなったかな?

かっきーかっきー

GetStaticProps に慣れる

GetStaticPaths でファイル名にするパラメータを配列で吐き出して、
GetStaticProps でページにするデータを取得してページに投げる。

https://maku.blog/p/rdq3ep2/

かっきーかっきー

├ ● /titles/[title] 860 B 166 kB
├ └ /titles/testtitle1
Vercel で SSG に吐き出せた。
次は GetStaticProps で Firestore から値を引っ張ってこれるかを試すか。

かっきーかっきー

paths を別のところから取ってきて props に投げてデータ取得、複数ページ生成までできた。
途中 JSONっぽいエラーのところでハマったけど単にデータの持ち方が失敗していただけだった。

かっきーかっきー

React18 useEffect対応

とりあえずこんな感じで組み込んだ。

  const mounted = useRef(false)

  // useEffect
  useEffect(() => {
    if (mounted.current) {
      return
    }
    mounted.current = true

    // TODO: 走らせたい処理をここに書く 
  }, [])

様子を見ながらどのくらい入れるか考える

https://gihyo.jp/book/2022/978-4-297-12916-3
この本に載ってました!

かっきーかっきー

useEffect の 第2引数で再実行かかっても処理しなくなる…って当たり前やんw
一旦上記処理は全部外した。

かっきーかっきー

Loginページでログイン済みならリダイレクト処理をuseEffectに書いていたので上記の処理を書くことでエラーが出なくなった。

かっきーかっきー

Next.js 12.3 にあげたら yarn dev で止まった

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
info  - Loaded env from /Users/user/Code/ictsss/.env.local
info  - SWC minify release candidate enabled. https://nextjs.link/swcmin
info  - automatically enabled Fast Refresh for 1 custom loader          

この部分から先に行かなくなった

12.2.5 に下げても止まった。どこが原因だ…。

かっきーかっきー

yarn.lock を消して yarn し直しで直った。意味わからん状態だったので助かった…。

かっきーかっきー

同じテンプレ派生のもの全部同じ症状なんで原因があるはずなんだけど調べきれないなこれ

かっきーかっきー

GitHub Codespaces

iPadで使ってみている。便利だね。
今の疑問。github にアップされていない .env ファイルどうしてるのかな?

かっきーかっきー

iPad はまだ動きが重いんでまだ学習&緊急修正用かな?
PCからならいけるけどそれなら従来のやり方する手もある…って所かな?

かっきーかっきー

iPadだとローカル環境での確認でもたついたりエラーになったりする時がある
気分が落ち着いてきて皆が通った道を歩いた感じがしたw

かっきーかっきー

Next.js 13 への移行

既存プロジェクトをようやく Next.js 13 移行させることにした。
React本体や他パッケージなどは常にアップデートしていたたので作業は yarn add next のみ

  1. next-transpile-moduleの削除
    主に FullCalendar で next-transpile-module を使っていた。
    作者さんが Next.js13 の標準機能になったから俺の役割終わりだよ!ってのは見ていた。

https://zenn.dev/torahack/scraps/d4b06542babbd9

手順通りに実施、あっさり動作。

  1. Error: Invalid <Link> with <a> child. Please remove <a> or use <Link legacyBehavior>. が表示される
    <Link>に<A>タグの機能あるからLinkの内側にaタグ書かないでね、ってことらしい。

https://qiita.com/hiroyukiwk/items/8ba0f9e63d6a2ccd845c
https://qiita.com/FumioNonaka/items/0e97dca13528fb3366a0
https://zenn.dev/k_kazukiiiiii/articles/5e8a72ec1a5d27

最初 legacyBehavior を Linkタグ につけて動作させてから徐々に外していった。
a タグの className以下 はLinkに付け替えれば特に問題なく動作した。

かっきーかっきー

App Router への移行

App Router への移行を調査中、まずは公式
https://nextjs.org/docs/app

Pages と併用でいけるとあるけどどういうやり方になるんだろうか…とか考えながら

かっきーかっきー

app フォルダを作成、layout.tsx, page.tsx を作成。

pages 配下の index.tsx とコンフリクトしてエラーが出たので既存ページを暫定リネーム
同じページ名は使えないあたりは移行作業としては考えないといけないかも。
リネームして app フォルダ側のページを表示させた。ふむ

かっきーかっきー
import NextNprogress from 'nextjs-progressbar'
      
<NextNprogress
        color="#FFFFFF"
        startPosition={0.2}
        stopDelayMs={20}
        height={2}
        showOnShallow={true}
      />

これは use clinet しろって言われた。そりゃそうだ。
別ファイルでuse clinet 付きのコンポーネント化してタグで貼ればOKかな?

かっきーかっきー
'use client'
import NextNprogress from 'nextjs-progressbar'

// NextProgress
export const NextProgress = () => {
  return (
    <>
      <NextNprogress
        color="#FFFFFF"
        startPosition={0.2}
        stopDelayMs={20}
        height={2}
        showOnShallow={true}
      />
    </>
  )
}

NextProgress.displayName = 'NextProgress'

こんな感じにして layout.tsx にインポートしてうまくいっている感じ。
Bootstrap、Recoil も同様にしてエラーは出なくなった。

_componentsフォルダに入れてみたが良い命名規則なんかあるかな?
暫定で NextProgress、Bootstrap、Recoil なんだけど… 後ろに Component つけるのだるい

かっきーかっきー

Firebase 系はめんどそうな感じなので後回し、Bootstrap系統は表示OK
なんでも 'use client' すりゃ動きそうだけど、ServerComponent にできそうなところを考えながらやれやと言われている感じなので一応真面目には考えてみよう

かっきーかっきー

Firebase Auth は ’use client' 使って通るようにはなった。
けど、なんか定期的にこれが出るな

Module not found: Can't resolve 'encoding' in '/Users/user/Code/*****/node_modules/node-fetch/lib'

Import trace for requested module:
./node_modules/node-fetch/lib/index.js
./node_modules/@firebase/auth/dist/node-esm/index.js
./node_modules/firebase/auth/dist/index.mjs
./src/lib/firebase.ts

https://github.com/supabase/supabase-js/issues/612
supabaseとかでも出てて、対応するとかあるけど Firebase 側で直すやつ?
yarn add encoding しちゃえよみたいな事も答えにあるのでやってみたら消えた。
注意しつつ様子見にしよう。

かっきーかっきー

要はマウントチェックしてあれならnull返せってことらしいけど…これもだるいw

このだるい処理を入れておかないと Bootstrap でプルダウンが動かなかった
いるか入らないか分からないので全部入れるしかないのか?

かっきーかっきー

Metadata って 'use client' 使ってる tsx 内では使えないのか … そりゃそうか。
てことは page.tsx は use client 付けてベタ貼りするんじゃなくて頑張って sc にしないとページごとのタイトルが付けられないってことか?

かっきーかっきー

sc と cc の階層の話は Flutter の StatefulWidget をコンポーネント化して分離していくのと同じ感じかな〜と思いながら移行作業中

かっきーかっきー

とりあえず大体移行できたけど…これ微妙じゃね?
いやまぁやりたいことと、今後の技術考えた理想型ではあると思うけど…。
今まで以上に裏でこねくり回されてる感が強い。

とりあえず移行後のコードは全保存しておいて元に戻そうかと考えている。

かっきーかっきー

とりあえず移行コードを退避しておいて元に戻した。
Hooksでコントローラー的に分離しておくとか移行に有効なコードの書き方は何となくわかったので備えをしつつpagesフォルダの扱いがどうなるか、プラグイン群がどうなるかで決めようかな。

かっきーかっきー
Problems loading reference 'vscode://schemas/settings/configurationDefaults': Unable to load schema from 'vscode://schemas/settings/configurationDefaults': cannot open vscode://schemas/settings/configurationDefaults. Detail: Unable to resolve text model content for resource vscode://schemas/settings/configurationDefaults.(768)

https://qiita.com/Yasushi-Mo/items/44e4ad188038dac9663f
このエラーが突然でて上記(vscode の settings.json に追記)で対処、これ何だろ?

かっきーかっきー

json ファイルを読み込むのに許可が必要になったのかな?
firebase 系の json は反応しない感じもあるけど…。