🌴

Nextjsで書いたblogがvercelでbuildできなくなったのでpnpmからyarnに移行した[solved]

2024/02/06に公開

Nextjsで書いたblogがvercelでbuildできなくなったのでpnpmからyarnに移行した[solved]

  • created: 2024-02-05
  • updated: 2024-02-06

まず仮説を立てる

pnpmの新しいversion8.15.1がどうやらvercelに対応していない。pnpm-lock.yamlのlockfileVersion: '6.0'をいじったり8.14.3も試したけどError変わらず。(6th/Feb/2024時点) そこでpackage managerはyarnで管理することにした。(Package管理のVoltaがバージョン固定pinをnpmとyarnのみ対応にしたのも理由)

ERR_PNPM_LOCKFILE_CONFIG_MISMATCH  Cannot proceed with the frozen installation. The current "settings.autoInstallPeers" configuration doesn't match the value found in the lockfile

prerequisite

Errorが出た環境: Nextjs+ vercel

  • React v18.2.0
  • Next v14.1.0
  • Node v20.11.0(LTS)
  • pnpm v8.15.1
  • vercel環境変数設定:ENABLE_EXPERIMENTAL_COREPACK=1

まずGitの過去ログから消してしまっていたpackage-lock.jsonをcopy、復活させる。(重要)

  • yarn importでtry⇒ Error(yarn importはv1のみ対応)

プロジェクト内のpackage.jsonのpackage Managerをyarn3.6.4に設定。

Home directoryのpackage.jsonのPackage Managerをyarn3.6.4に設定。(Plug and Play)

  • 空のyarn.lockファイルを作る。これでyarn installを行うとpackage-lock.jsonの内容が反映される
(13:07:05 on main ✹ ✭)──> yarn import                                1 ↵ ──(Mon,Feb05)─┘
Internal Error: root-workspace-0b6124@workspace:.: This package doesn't seem to be present in your lockfile; run "yarn install" to update the lockfile

Error時に言われたとおりにyarn install

└─(13:12:06 on main ✹ ✭)──> yarn install                               1 ↵ ──(Mon,Feb05)─┘
➤ YN0000: ┌ Resolution step
➤ YN0032: │ fsevents@npm:2.3.3: Implicit dependencies on node-gyp are discouraged
➤ YN0032: │ pnpm@npm:8.14.3: Implicit dependencies on node-gyp are discouraged
➤ YN0000: └ Completed in 34s 145ms
➤ YN0000: ┌ Fetch step
➤ YN0013: │ wrap-ansi@npm:7.0.0 can't be found in the cache and will be fetched from the r
➤ YN0013: │ wrap-ansi@npm:8.1.0 can't be found in the cache and will be fetched from the r
➤ YN0013: │ yallist@npm:4.0.0 can't be found in the cache and will be fetched from the rem
➤ YN0013: │ yaml@npm:2.3.4 can't be found in the cache and will be fetched from the remote
➤ YN0013: │ zwitch@npm:2.0.4 can't be found in the cache and will be fetched from the remo
➤ YN0000: └ Completed in 31s 620ms
➤ YN0000: ┌ Link step
➤ YN0000: └ Completed in 2m 18s
➤ YN0000: Done with warnings in 3m 24s

pnpm-lock.yamlとpackage-lock.jsonをdelete.

しかしyarnでもvercelへのBuildがErrorが出てしまう。

  • engineをいままでlockfileにnode ≥18とざっくりと定義していたので、LTSを超えてlatest指定になってerrorしていた可能性大。
Warning: Detected "engines": { "node": ">=18" } in your `package.json` that will automatically upgrade when a new major Node.js Version is released. Learn More: http://vercel.link/node-version

⇒ node version 20.xと明記する on package.json

https://vercel.com/docs/functions/serverless-functions/runtimes/node-js#node.js-version

  • package.jsonのreactの^を外す

  • vercelで環境変数設定してある ENABLE_EXPERIMENTAL_COREPACK=1を消してみる⇒ 消したらvercel server上でyarn install v1.22.17がはじまってしまった、yarn v3.6.4が使いたいので、挙動がかわってしまったのでこの変更はrevert。

//before delete env
Detected ENABLE_EXPERIMENTAL_COREPACK=1 and "yarn@3.6.4" in package.json
Installing dependencies...
//after delete env

Installing dependencies...
yarn install v1.22.17
  • Nodeを20から18にdowngrade。⇒ volta pinでこのprojectのみnodev18.19.0に設定してみる( nodeの場所がpnpmでの設定になっているが、pinした後は関係なくシェル再起動すればnodeが固定できている。必ず再起動。) *結果、nodeのdowngradeは必要なかったのでv20LTSに戻した(追記)
└─(20:36:08 on main ✹)──> volta pin node@18.19.0                          1 ↵ ──(Mon,Feb05)─┘
success: pinned node@18.19.0 (with npm@10.2.3) in package.json
└─(20:37:34 on main ✹)──> exec $SHELL -l                                  1 ↵ ──(Mon,Feb05)─┘
┌─(~/dev/nextjs-blog)─────────────────────────┐
└─(20:41:13 on main ✹)──> node -v                                             ──(Mon,Feb05
v18.19.0

ちなみにちゃんとHOMEdirectoryのmainはnodev20のLTSの状態をkeep

└─(20:45:16 on main ✖ ✹ ✭)──> node -v                           ──(Mon,Feb05)─┘
v20.11.0

Error継続 ただbuild時にreact-gtm-moduleが_app.js上でうまくいってなさそうなのがわかってきた

unhandledRejection ReferenceError: document is not defined
    at Object.dataScript (/vercel/path0/node_modules/react-gtm-module/dist/TagManager.js:11:18)
    at Object.gtm (/vercel/path0/node_modules/react-gtm-module/dist/TagManager.js:30:27)
    at Object.initialize (/vercel/path0/node_modules/react-gtm-module/dist/TagManager.js:50:20)
    at /vercel/path0/.next/server/pages/_app.js:1:297 {
  type: 'ReferenceError'
}
Error: Command "yarn run build" exited with 1
Running "yarn run build"
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry

vercelのissueをcheck.
All browser-related APIs should still be guarded.がヒントになりそう

I think it is not falsely reported - as per the documentation:
Client Components enable you to add client-side interactivity to your application. In Next.js, they are prerendered on the server and hydrated on the client. You can think of Client Components as how Next.js 12 and previous versions worked (i.e. the pages/ directory).
Client components = SSR + hydration + CSR.
All browser-related APIs should still be guarded.

これ解決に近そう
https://stackoverflow.com/questions/60729564/next-js-react-gtm-module-referenceerror-document-is-not-defined

gtmことgoogle tag managerがSSRを試みて悪さをしていることが判明。client sideで処理が完了するように実装する。

/Users/HOME/dev/nextjs-blog/pages/_app.js

import TagManager from 'react-gtm-module'

const tagManagerArgs = {
    gtmId: 'uhouho'
}

    TagManager.initialize(tagManagerArgs);

Wrapping the piece of TagManager initializer with a checker helped:

You need to wrap your document using validator process.browser, because this document is belong to client side, and the error occured when nextjs render in server side.

import TagManager from 'react-gtm-module'
 
const tagManagerArgs = {
    gtmId: 'GTM-uhouho'
}
if (process.browser) {
    TagManager.initialize(tagManagerArgs);
}

参考codeのprocess.browserがdeprecatedだったのでtypeof window !== "undefined"に変更 https://stackoverflow.com/a/66939086

for me, this error occurs from lots of mistakes: first, you have to use

if (typeof window !== "undefined") {

for every window. and document. and especially for localStorage. functions (my self forgot to use this if clause for localStorage.getItem and the error didn't fix)
another problem was the import of the line below which was totally wrong!

Implement Conditional Rendering

https://medium.com/@saileshadhikari72/handling-window-is-not-defined-error-in-react-and-next-js-for-client-side-code-993eec31bc48

Wrap the code that relies on the window object inside a conditional check. We’ll use the (typeof window !== ‘undefined’) condition to ensure that the code is executed only in a browser environment.

Conclusion

package manager pnpm@latestのvercel非対応(6/Feb/2024時点)と、Google Analytics 4にupdateしたgoogle tag managerをnextjs仕様に対応できていなかったのがErrorの原因。

You need to wrap your document using validator typeof.window because this document is belong to client side, and the error occured when nextjs render in server side.

engineをlockfileにnode ≥18とざっくりと定義していたので、LTSを超えてlatest version指定になってerrorを吐いていた。=> WARNで前から言われていたことなのでこれからは早めに対応する。

package.jsonのreact^18.12.0^を外す =>reactのversionは今後もしっかり固定していきたい

(pnpmからyarn.lock移行作業が完了したら、pnpm-lock.yamlを消去。)

ReCap

pnpmからyarn環境に移行するパターンのいいpracticeになった。(このprojectはこのままyarnでいく)

パッケージのupgradeはこれからも慎重に。

その他用意していた対策

.yarnrc.yml fileのsetting...設定済みのyarnPATHをdeleteするなど。(corepack対応のため) ⇒今回は変更必要なかった。v3からv4に移行する時に必要。

.Nextのcacheを消す ⇒消さなくて済んだ

appendix

  • node v20.11.0 LTSでのbuild check ⇒ success

Skipping build cache since Node.js version changed from "18.x" to "20.x”

└─(22:40:32 on main)──> volta pin node@20.11.0                                ──(Mon,Feb05)─┘
success: pinned node@20.11.0 (with npm@10.2.4) in package.json
┌─(~/dev/nextjs-blog)─────────────────────────┐
└─(23:36:29 on main ✹)──> exec $SHELL -l                                      ──(Mon,Feb05)─┘
┌─(~/dev/nextjs-blog)────────────────────────)─┐
└─(23:37:00 on main ✹)──> node -v                                             ──(Mon,Feb05)─┘
v20.11.0
"engines": {
    "node": "20.x"
  },

Discussion