Remix+CloudflareでWebサイトを作る 2(MUIエラー修正・Web Analitics導入・フォームバリデーション・ドメイン購入・Superflare)
【2024-02-03】エラー: Element type is invalid: expected a string
エラー内容
こんな感じのコードを書いたがアイコンを表示している箇所でエラーが出る
import { FavoriteBorder } from "@mui/icons-material";
import EmailIcon from "@mui/icons-material/Email";
import IconButton from "@mui/joy/IconButton";
export default function LoginPage() {
return (
<IconButton variant="soft" color="primary" size="sm">
{/* ここでエラー */}
<EmailIcon />
{/* これだとエラーがでない */}
<FavoriteBorder />
</IconButton>
</div>
);
}
内容は以下。
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `LoginPage`.
at createFiberFromTypeAndProps (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:20439:25)
at createFiberFromElement (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:20460:23)
at reconcileSingleElement (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:11801:31)
at reconcileChildFibers2 (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:11838:43)
at reconcileChildren (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:14292:37)
at updateHostComponent (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:14802:11)
at beginWork (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:15923:22)
at beginWork$1 (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:19749:22)
at performUnitOfWork (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:19194:20)
at workLoopSync (http://0.0.0.0:8788/build/_shared/chunk-GIAAE3CH.js:19133:13)
原因
この記事を見る限り、Matreial UIのアイコンはドキュメントに書いてあるimport方法で読み込んでもこのエラーが出てしまう場合があるらしい。
この記事にとはちょっと違うが、以下のようにするとうまく表示された。
公式ドキュメントのように LightModeIcon
にするのではなく LightMode
として Icon
を省く必要がある。
// 🚨 表示されない
import LightModeIcon from "@mui/icons-material/LightMode";
// ✅ 表示される
import { LightMode } from "@mui/icons-material";
【2024-02-03】Hydration関連のエラー色々
エラー内容
以下のエラーが発生
installHook.js:1 Error: Hydration failed because the initial UI does not match what was rendered on the server.
react-dom.development.js:86 Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.
Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.
ncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
解決策
<StyledEngineProvider injectFirst>
を削除するとエラーが出なくなった。
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{/* <StyledEngineProvider injectFirst> */}
<Outlet />
{/* </StyledEngineProvider> */}
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
これでラップすることでJoy UI本来のスタイルよりもカスタムスタイルを優先的に適用させられるようになるっぽい。
1つ上のコメントで書いてあるとおり、アイコンのimport順ですらエラーになるから公式あまり信用しないでおこうかな。
MUI、なんだか雲行き怪しいな。。
Style library interoperability - Material UI
【2024-02-04】エラー: Not symbolizing stack traces because $LLVM_SYMBOLIZER is not set
背景
以下のSandboxはMUIが公式に出しているものだが、これを参考にしながらログインページを作成していた中で発生した
admiring-curie-k77ty6 - CodeSandbox
エラー内容
$ npm run dev
...
workerd/util/symbolizer.c++:98: warning: Not symbolizing stack traces because $LLVM_SYMBOLIZER is not set. To symbolize stack traces, set $LLVM_S
workerd/jsg/jsg.c++:136: error: took recursive isolate lock; kj::getStackTrace() = 10060a9ef 1008c9f07 1008e095b 1008e08df 101f19107 100c69493 100c6a1af 100bceaff 100bced27 101eeaadf 1009cde07 101eeae07 1009ce8eb 101eeae07 1008ab1c7 101eec78b 101eeae07 1008abdbb 101eebab3 101eeaadf 1008ac4
Remix v2へアップデートした時のメモ | Web Scratch
このページを見る限り、$ kill $(lsof -t -i:8788)
でキルしたら解決されるそうだが解決されない。
Sandbox の中にある<CssVarsProvider defaultMode="dark" disableTransitionOnChange>
らへんが怪しいかと思ったがコードを消しても何回かリロードするとこのエラーがちょくちょくでてきてしまう。
少なくともブラウザコンソールでは何もエラーがでていないし、UI側の問題ではなさそう。
🐛 BUG: "warning: Not symbolizing stack traces because $LLVM_SYMBOLIZER is not set" · Issue #3631 · cloudflare/workers-sdk
このissueを見る限りCloudflareのWranglerを最新にするのが良しとされている。
解決
package.jsonを見ると、"wrangler": "3.8.0"
になっているが2024-02-04時点での最新は3.26.0
。
ということでアップグレードしてみると治った!
【2024-02-04】Web Analyticsの導入
使ってみる
CloudflareのページをポチポチいじっていたらAnalyticsのページがあったのでスクリプトを埋め込んでデプロイしてみる。
ローカルからデプロイしてみると今までと違いアカウントを選択するフローが存在し、「プレビュー」ではなく「プロダクション」環境にデプロイされた。
$ npm run deploy
> deploy
> npm run build && wrangler pages deploy ./public
> build
> remix build
info building... (NODE_ENV=production)
info built (7.3s)
✔ Select an account › Hogehoge Account
No project selected. Would you like to create one or use an existing project?
Create a new project
❯ Use an existing project
Select a project:
❯ YOUR_PROJECT_NAME
以下は過去7日間のデータ(開発してからまだ3日なので今までの全てと同義)だが、アカウント分析を見てみたら海外から謎のアクセスあって怖い...。
ついでに通知設定
サイドバーをいじっていたら通知設定があったのでなんとなくDDos攻撃アラートだけ設定してみる。
「テスト」ボタンを押すと設定したメアドに通知が飛んでくる。
通知系の設定でテスト機能があるのGood UX。
【2024-02-04】エラー: Could not resolve "crypto"
エラー内容
なんかちょくちょく出てくるな。
$ npm run dev
> dev
> remix dev --manual -c "npm run start"
💿 remix dev
info building...
✘ [ERROR] Could not resolve "crypto"
node_modules/cookie-signature/index.js:5:21:
5 │ var crypto = require('crypto');
╵ ~~~~~~~~
The package "crypto" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
✘ [ERROR] Could not resolve "stream"
node_modules/stream-slice/index.js:3:24:
3 │ var Transform = require('stream').Transform;
╵ ~~~~~~~~
The package "stream" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
原因・解決方法
原因を特定するとどうやら以下のloaderを追加すると出てきていた。
同じようなコードは他のページにもあるのに謎だなぁと思って、エラーを吐かないコードと見比べていたらjson
のimport元の違いがあった。
Remix v1をいじっていたときのコードからコピペしてきた弊害。
json
は@remix-run/node
と @remix-run/cloudflare
どちらからもimportできるが、v1だと@remix-run/node
を使っていたのでミスってしまった。
import { json } from "@remix-run/node"; // エラーが出る
import { json } from "@remix-run/cloudflare"; // エラーが出ない
export async function loader({ context }: LoaderFunctionArgs) {
const env = context.env as Env;
const users = await client(env.DB).select().from(usersSchema).all();
return json({
users: users ?? [],
});
}
【2024-02-04】エラー: ReferenceError: Buffer is not defined
背景
Basic認証を実装しようとして以下のようなコードを書いていた
const isAuthorized = (request: Request) => {
const header = request.headers.get("Authorization");
if (!header) return false;
const base64 = header.replace("Basic ", "");
const [username, password] = Buffer.from(base64, "base64")
.toString()
.split(":");
return username === "admin" && password === "password";
};
export const loader = async ({ request }: LoaderArgs) => {
// ログイン済みの場合 /admin に遷移させる
const userId = await getUserId(request);
if (userId) return redirect("/admin");
// Basic認証
if (!isAuthorized(request)) {
return json({ authorized: false }, { status: 401 });
}
return json({ authorized: true });
};
エラー内容
ReferenceError: Buffer is not defined
at isAuthorized (file:///Users/.../.wrangler/tmp/dev-RRisB7/7ly80mup8w2.js:44174:69)
at loader2 (file:///Users/.../.wrangler/tmp/dev-RRisB7/7ly80mup8w2.js:44179:44)
原因・解決方法
フォーカスする限りBuffer
は存在しそう。
実際にこのコードはRemix v1をいじっていた時に動いていた。
以下を追加したら修正された。
エラー文で調べてみるとwindow.Buffer
でアクセスしたり、そもそも npm i buffer
している人もいるがその必要は無し。
import { Buffer } from "buffer";
Basic認証のキャッシュ削除方法
エラーとは関係ないけど、ホスト名の前に<適当な文字列>@
を入れると削除される。
例: http://hoge@0.0.0.0:8788/login
ただし、http://hoge@
がついていると正しくUsernameとPasswordを入れても常にBasic認証が出てきてしまうので、削除後には再度 hoge@
をなくした正しいアドレスにアクセスする必要があることに注意。
Chromeの場合は http://hoge@
が検索フォームに表示されず 0.0.0.0:8788/login
だけが表示されているので最初これに気づかなかった。
【2024-02-04】フォームバリデーションはどれを使うか
候補
更新頻度、人気を考慮すると以下の2つ。
remix-validated-form
Remix v1の時に使ってたので基本的な使い方はある程度わかってるけど、当時は凝ったことをしようとした時に痒いところに手が届きにくかった印象がある(もちろん自分の力量不足の可能性は大いにあるが)。
あとDemo をクリックしたら「デモサイト」に飛べるのかと思ったら動画ファイルダウンロードさせようとしてくるのだるい。
remix-hook-form
使ったことがないが、仕事では react-hook-form を使っているので、こちらに関してもある程度勝手はわかっているし、使いやすかった印象がある。
最近上の記事も見たけどReact Hook Formはやっぱドキュメント充実してて良いよなぁと思う。
remix-validated-form は最後の更新が4ヶ月前だが、こっちは2週間前。
もちろん単純に後発だから、というのはあるかもしれないが remix-validated-form が4ヶ月更新されていないのがちょっとネガティブに見えてしまう。
結論
まだまだ小さいプロダクトでだめだったら修正しやすいはず。
使ったことのない remix-hook-form の方を使ってみる。
追記:書いてみたら remix-hook-form + Joy UI + Zod をいい感じに使えて良さそう
更に追記:結局フロントとバックエンドどちらも共通のスキーマを使ってバリデーションをできるConformを使うようになりました。とても便利。
その他
なんかのタイミングで「It will be sunset」使いたい。
【2024-02-04】ドメインを取得する
空いているドメイン調べてみる
サポートされているドメインの中から良さそうなのを見繕うと以下。
ドメイン名 | ドル/年 |
---|---|
APP_NAME.party | 4.16 |
APP_NAME.app | 12.18 |
APP_NAME.red | 15.18 |
APP_NAME.ink | 19.18 |
APP_NAME.beer | 20.18 |
APP_NAME.systems | 21.18 |
APP_NAME.news | 21.18 |
APP_NAME.ninja | 21.18 |
APP_NAME.land | 25.18 |
APP_NAME.media | 28.18 |
com, io, infoらへんは既にとられていた。
appやnewsは普通に良いし、partyとかbeerもかわいい。
正直いつリリースできるかわからないので3月中にいい感じのところまで実装終わってたらapp
news
party
beer
のうち空いてる1つを取ろうかな。
買う
買っちゃったら開発頑張らなくちゃいけないし。
「ジム代払ったらジム行くはず」というのと同じ理論。
行かなさすぎて解約したけど。
時間かかりそうだしここらへんの設定無知なのでまた今度。
色々簡単に済んで助かる。
Hello, Superflare!
Superflareというもの
RemixのactionでCloudflareに色々リクエスト送るのどうやるのか調べていたら以下の記事を発見。
以下のような記述もありなんだか良さそう。
Superflare より提供されている parseMultipartFormData 関数を使うことで、ファイルをメモリに展開せず、R2 にファイルを直接ストリーミングできます。R2 ストレージの操作は storage オブジェクトを使用します。storage().putRandom() メソッドはランダムな名前を生成してファイルをアップロードします。extension オプションを指定することで、ファイルの拡張子を指定できます。
プロジェクトの中身見てみる
$ npx superflare@latest new
でRemix + Superflareのプロジェクトが作成できるので中身を見てみる。
drizzleの時に困っていたseed作成用ファイルなどもある。最初っからこいつを使っておけば...。
なんといってもCloudflareとの連携をスムーズにしてくれるのが良い。
上のZennの記事にたんまりExample Codeあったから割とすぐに動くものは作れそう。
npm install
また最初から作るのは面倒なので公式に則って npm コマンドで superflareを追加しようとしたら以下のエラーが発生。
$ npm install @superflare/remix
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: YOUR_PROJECT_NAME@undefined
npm ERR! Found: @remix-run/cloudflare@2.6.0
npm ERR! node_modules/@remix-run/cloudflare
npm ERR! @remix-run/cloudflare@"^2.5.1" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @remix-run/cloudflare@"^1.14.0" from @superflare/remix@0.0.18
npm ERR! node_modules/@superflare/remix
npm ERR! @superflare/remix@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR!
npm ERR! For a full report see:
npm ERR! /Users/saneatsuwakana/.npm/_logs/2024-02-04T07_57_14_114Z-eresolve-report.txt
npm ERR! A complete log of this run can be found in: /Users/saneatsuwakana/.npm/_logs/2024-02-04T07_57_14_114Z-debug-0.log
ERESOLVE unable to resolve dependency treeの解決方法 #Docker - Qiita
この記事を参考にオプションを付けてインストールし直した。
npm install @superflare/remix --save --legacy-peer-deps
が、この後にもパッケージimport周りやら諸々の設定周りでかなりしんどい。
Repository見る感じAlpha版で止まってしまってあまり開発も活発じゃなさそう。
この記事でも同様のことを書いている
現状はRemixでしか動作しません。
Remixプロジェクトの後からSuperflareを入れるのは結構苦労します。(RequestHandlerの修正やCloudflare > Workersの型やビルドなどなど結構手が入ります)
使用してみた限りAlpha版です。コンセプトとして出している状況に近いです。
結論
採用見送り。
使いたかったので残念。