Remix+CloudflareでWebサイトを作る 5(Drizzle Timestamp・refetchの方法・remix.env.d.ts・エラーハンドリング・react-hot-toast)
【2024-02-11】DrizzleでSQLiteを使う時のTimestampとデフォルト値の書き方
スキーマの定義方法
もともとこんな感じで定義していた。
const timestamp = {
createdAt: integer("createdAt", { mode: "timestamp" })
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
};
実際にデータを入れて値を取ってみると createdAt: undefined
になってしまっていた。
以下のように修正。
const timestamp = {
createdAt: text("createdAt")
.notNull()
.default(sql`datetime(CURRENT_TIMESTAMP, '+9 hours')`),
updatedAt: text("updatedAt").notNull(),
};
// 共通化しているtimestampをこんな感じで使っている
export const tagSchema = sqliteTable("tags", {
id: integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }),
name: text("name").notNull().unique(),
...timestamp,
});
npx drizzle-kit generate:sqlite
を実行してマイグレーションファイルを作成すると、以下のようなsqlファイルが作成されている
CREATE TABLE `tags` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL,
`createdAt` text DEFAULT datetime(CURRENT_TIMESTAMP, '+9 hours') NOT NULL,
`updatedAt` text NOT NULL
);
これをローカルに反映させようとすると以下のようなエラーが出る
$ npx wrangler d1 migrations apply YOUR_DB_NAME --local
┌───────────────────────────────┬────────┐
│ name │ status │
├───────────────────────────────┼────────┤
│ 0000_smiling_multiple_man.sql │ ❌ │
└───────────────────────────────┴────────┘
❌ Migration 0000_smiling_multiple_man.sql failed with the following errors:
✘ [ERROR] near "(": syntax error at offset 159
作成されたsqlファイルを以下のように修正する。
具体的には datetime(CURRENT_TIMESTAMP, '+9 hours')
を括弧で囲んだ。
CREATE TABLE `tags` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL,
`createdAt` text DEFAULT (datetime(CURRENT_TIMESTAMP, '+9 hours')) NOT NULL,
`updatedAt` text NOT NULL
);
最終形
これでエラーが出なくなった。
sqlファイルを作成するたびに修正するわけにも以下ないのでスキーマ自体を括弧で囲むように修正。
const timestamp = {
createdAt: text("createdAt")
.notNull()
.default(sql`(datetime(CURRENT_TIMESTAMP, '+9 hours'))`), // datetimeを括弧で囲む
updatedAt: text("updatedAt").notNull(),
};
取得結果
すると以下のような形式でデータが取れるようになる。
{
id: 1,
name: 'テクノロジー',
createdAt: '2024-02-11 05:06:35',
updatedAt: '2024-02-11 05:06:35',
}
【2024-02-11】Remixでfetcher.submitでDELETEした後にfetcher.submitでGETしたい
背景
テーブルに何かしらの情報一覧があって、1つのRowを削除した後に再度フェッチをするというごく一般的なユースケース。
雑に書くと以下のようなコード。
削除確認のモーダルを出して「削除」ボタンを押したらfetcher.submit
を実行して削除するところまではできた。しかしながらfetcherはawaitできないので再取得を削除前に行ってしまう。
今まではTanStack Query使って脳みそあまり使ってこなかったけどRemixではどうしようか。
こういうケースはあるあるだし、流石にRemixでのベストプラクティスがありそうだから探したい。
export default function Hoge() {
const fetcher = useFetcher();
return (<div>
fetcher.submit(
{ id: tag.id },
{
action: "/admin/tags/delete",
method: "POST",
}
);
fetcher.submit({
action: "/admin/tags",
method: "GET",
});
</div>
)
}
削除処理が終わったことをどう知るか
ここらへんを見ると、useEffect
を使って特定の状態になった時に何かしらを実行することが推奨されているっぽい。
再取得の方法
fetcher.load()
とかで良いのかと思ったけど、以下を見ると2つの方法があった。
2つ目を採用した。
// 1つ目
const navigate = useNavigate()
navigate('.', { replace: true })
// 2つ目
const revalidator = useRevalidator();
remix.env.d.ts
とはなんなのか
【2024-02-12】背景
Rmix x CloudflareのExampleコードとか眺めているとこのファイルに定義されたものはexportしていないのに他のファイルから型定義を参照できていたりする。
また、どっかから前に拾ってきたコードだが以下のように書くと「loaderで返される値が JsonifyObject
型なので型定義でてますよ」系のエラーが出なくなる(このコードは使っていない)
このファイルはどのような役割を果たしているのか良くわかっていないので調べる
declare module "@remix-run/server-runtime" {
export interface AppLoadContext {}
}
///
とは
そもそも これは、TypeScriptのトリプルスラッシュディレクティブと呼ばれるもので、特定の型定義を参照するために使用される。
/// <reference types="@remix-run/dev" />
と書くことで @remix-run/dev
パッケージの型定義を参照することで、パッケージが提供する型を利用できるようになる
因みに、@remix-run/dev
は、Remixフレームワークの開発サーバーと関連ツールを提供するパッケージで、Remixの開発サーバーのAPIやツールをTypeScriptで型安全に使用することができるようなるらしい(by ChatGPT)
まずは公式ドキュメントを漁る
Remix has TypeScript type definitions built-in as well. The starter templates create a remix.env.d.ts file that is referenced by the tsconfig.json:
Remix には TypeScript の型定義も組み込まれています。 スターター テンプレートは、tsconfig.json によって参照される remix.env.d.ts ファイルを作成します。
Note that the types referenced in remix.env.d.ts will depend on which environment you're running your app in. For example, there are different globals available in Cloudflare.
remix.env.d.ts で参照されるタイプは、アプリを実行している環境によって異なることに注意してください。たとえば、Cloudflare ではさまざまなグローバルが使用できます。
ChatGPTに聞いてみた
remix.env.d.tsはRemixにおいてどのような役割のために利用されるファイルですか?
remix.env.d.tsは、Remixフレームワークで使用される環境変数をTypeScriptに型定義するためのファイルです。.envファイルや環境変数は、アプリケーションの設定や秘密情報(APIキーなど)を管理するためによく使用されます。しかし、これらの変数はJavaScriptでは動的に扱われるため、TypeScriptの型チェックの対象外となります。
remix.env.d.tsファイルを使用することで、環境変数に対する型チェックを有効にすることができます。これにより、環境変数の使用に関するエラーをコンパイル時に検出することができ、バグを早期に発見することが可能になります。
例えば、以下のようにremix.env.d.tsを定義することで、process.env.MY_API_KEYが文字列型であることをTypeScriptに伝えることができます:
declare global {
namespace NodeJS {
interface ProcessEnv {
MY_API_KEY: string;
}
}
}
declare module "@remix-run/server-runtime"
declare
は既存のJSモジュールや、グローバル変数、関数を型定義をするために使用される。
これによってTypescriptはJSのコード理解し型チェックを行う。
daclare
を使って同じ名前のモジュールをやインターフェースを複数回定義すると、それらの定義はマージされる(宣言的マージ:Declaration Merging)。
これによって既存の型を拡張したり、モジュール間で方を共有する。
// @remix-run/server-runtimeモジュールがSomeInterfaceとAnotherInterfaceの両方をエクスポートするという意味になります。
declare module "@remix-run/server-runtime" {
export interface SomeInterface {
// ...
}
}
declare module "@remix-run/server-runtime" {
export interface AnotherInterface {
// ...
}
}
まとめ
remix.env.d.ts
とは?
- remix.env.d.tsは型定義や環境変数などの型定義をするファイル
- 環境変数に型チェックをすることができるようになることで安全に開発できる
- 宣言的マージをすることで既存のモジュールを拡張することも可能
- ファイル内ではトリプルスラッシュディレクティブ(
///
)などを使って型定義の参照が行われている - このファイルで定義されたものはimportせずともグローバルで使用可能になる
MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.
が出続ける
【2024-02-12】killしても背景
2つ前のスクラップでも同じエラーがでていて以下を実行して再度立ち上げで直っていたのだが何回やっても治らない
$ kill $(lsof -t -i:8788)
$ npm run dev
エラー内容
✘ [ERROR] Address already in use (127.0.0.1:8788). Please check that you are not already running a server on this address or specify a different port with --port.
[wrangler:inf] Ready on http://localhost:51672
⎔ Starting local server...
/Users/app_name/node_modules/wrangler/wrangler-dist/cli.js:29572
throw a;
^
MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.
解決方法
立ち上げ前にビルドしたら動いた。謎だ...。
$ kill $(lsof -t -i:8788)
$ npm run build
$ npm run dev
【2024-02-12】エラーハンドリングを実装した時に参考になったリンクをメモ
この動画をみながらErrorBdoundaryについて実例を元に理解しながら真似して書いてみる。
便利だ〜。
TypescriptでErrorを継承した独自のエラーの型を定義したかったので参考にした。
【2024-02-12】Joy UIではなく react-hot-toast を選択
現在Joy UIは v5.0.0-beta.27
だが、Snackbarコンポーネントは連打した時に何個も重ねていくことができない。
前にも使ったことあるし、やりたいことがおおよそできる react-hot-toast を使う。
以下の画像のような感じでスタックしていけるし、スタイルも柔軟に対応できる。
【2024-02-13】Remixではv2からメソッド名が大文字になった
公式ドキュメントより
Multiple APIs return the formMethod of a submission. In v1 they returned a lowercase version of the method but in v2 they return the UPPERCASE version. This is to bring it in line with HTTP and fetch specifications.
複数の API は送信の formMethod を返します。 v1 ではメソッドの小文字バージョンが返されましたが、v2 では大文字バージョンが返されました。 これは、HTTP およびフェッチの仕様に準拠させるためです。(Google翻訳)
method
も大文字に修正しておいた。
- <form action="/logout" method="post">
+ <form action="/logout" method="POST">
そういやpatchとPATCHは違ったな
https://zenn.dev/neet/articles/de54e08de01c22 #zenn
前に見たこの記事を思い出した。
普通に読み物として面白いし歴史的経緯が詳細に書いていて好き。
【2024-02-13】後で読むものメモ
色々調べ物したりTwitter徘徊して見つけた面白そうな技術に関して、少しずつ導入していきたいので一旦メモってみる。
ここらへん弱いのでリリース後に見る。
久々に読み返す。
今まさにPrettier+ESLintなのでBiome使ってみる。
Vite, Rollup, Rolldown周りを学んでおきたい。
読む