Next.jsのapp routeつかってみて、時代の移り変わりを感じた

はじめましての人ははじめまして。そうでないひとはお久しぶりです。猫ロキP(@deflis/id:deflis55)です。

最近個人開発でNext.jsのapp routeをつかってみたのでその感想を書きたいと思います。 つれづれないままなので、まとまってなかったらすみません。

App Routerとは

Next.jsにおける、新しいアーキテクチャのルーティングです。 特徴としては、基本的な処理がServer Componentになり、ほとんどがSSG/ISRになるところでしょうか。

useStateなども使えないので、基本的にはpropsを受け取るか、fetchなどでデータを取得することになります。 fetchされるものも基本的に静的になるので、静的サイトジェネレーターとしての機能が強くなったイメージです。

なぜApp Routerを使ったのか

単純に、Next.jsの新しい機能を使ってみたかったからです。

また、(ここではリンクを張りませんが)作ったものはYouTubeやブログの更新情報を含んだポートフォリオなので、ほぼ静的サイトだけどもたまに更新されるという性質だったので、App Routerに向いていたからです。

というのは後付けの理由で、やってみたらそういうポートフォリオであればかなりApp Routerの特徴を活かせるなと思いました。クライアント側で動的に要素を変える必要がほとんどなければかなりいい選択肢になると思います。

使ってみてよかったところ

よかったところとしては、コンポーネントに直接fetchを書くと自動でISRされるところです。 今までReactQueryとかで苦労して取得していたりしたのでそういうのがスッキリ書けるようになった気がします。ずっといろんな難しい感じでデータ取得処理を書いていた感じがするので、これでだいぶ楽になるかなぁと思いました。

fetchの引数に revalidate を書くだけで、ISRの間隔を設定できるようになったのも革命的だと思いました。 これによって、既存のノウハウをそのまま活かしてISRを書くことができて非常に便利でした。感覚的にはSSRで書いているのと同じ感じで開発できました。

使ってみてよくなかったところ

よくなかったところとしては、クライアント側にコンポーネントを移さないと以前のノウハウやコンポーネントが利用できなくなっているところです。クライアントサイドで処理をするように"use client";を書けばいいんですが、そういうことを書くと頭の中でコンテキストスイッチが走るので難しいなと思ったりしています。

あと既存のコンポーネントをそのままServer Componentとして使えなくなっていそうな感じがしています。例えば、Material-UIとかを使おうとするとクライアントコードが増えて大変だろうなと思います。ただ、Next.jsとその手のコンポーネントの相性は年々悪くなっていっている印象があります。 Next.js的にはCSSモジュールやTailwind CSSを使ってほしいというのは見えていて、そういうCSSを直接各時代に戻ればそこまで問題ではなさそうとは思いますが…。

今回の場合は移行元のサイトがCSSフレームワークのBulmaを使っていたので、デザインそのままで移植しました。今回はこれで乗り切りましたが、Material UIとかEmotionを使っていたらもっと移行が大変だっただろうなと思っています…。

ディレクトリの切り方の工夫とかも必要そうで、atomic designの上になにかもう一つレイヤーがいりそうだなとかそういう事を考えています。 今回はあまりコンポーネントが多くなかったので適当に /components にServer Componentを置いて /components/client にClient Componentを置くことにしました。 なんかいい感じの切り方が他にあるなら教えてほしいです。

また、今回はつかってないんですが、Server Actionsを使ったフォームとかの処理に面食らう人も多そうな印象です。良くも悪くもPHP的な感じが否めず、まだ粗削りで変なところにバグを仕込んでしまいそうな感じがしています。そのうちこれをベースに、React-hook-formみたいないい感じのライブラリが出てきてくれることを祈っています。

まとめ

ポートフォリオみたいな半静的サイトを作るようなときの選択肢としてはApp Routerがかなり良いと思います。 XMLパーサなどのNode.jsの資産はだいたい使える感じですし、ISRもわかりやすくなりました。 ちょっとしたCSRを含む程度ならページのレンダリングは爆速です。

一方、まだベータですがServer Actionsはまだまだこれからという感じを受けました。そもそも新しいパラダイムで周辺環境が整っていないのもありますが、使い方に注意が必要でまだ実運用で使うときには大変だろうなと思いました。しかし、良くも悪くもまだ出たばかりの機能なので、今後どのようにエコシステムが発展していくのかが気になっています。これらのデメリットはエコシステムが広がれば問題なくなるところだと思っています。

色々文句は書いていますが、その手間に見合うメリットはかなりあると思っているので今後も使っていきたいと思います。 さすが業界最大手のNext.jsという感じでした。Gatsby潰しだ…!

TypeScript 4.9から導入された satisfies 演算子で安全に配列やオブジェクトを作ろう

はじめましての人ははじめまして。そうでないひとはお久しぶりです。猫ロキ P(@deflis/id:deflis55)です。

TypeScript 4.9 で導入された新しい演算子 satisfies をご存知でしょうか? 自分には関係ないと思っている人も多いと思うんですが、意外と使えるところが多いので、ここで紹介したいと思います。

satisfies 演算子とは?

簡単に解説します。詳しくはリリースノートを見てください。 www.typescriptlang.org

TypeScript では as const という const アサーションによって静的なオブジェクトを作ることができます。

type ColorName = 'prop1' | 'prop2';

const obj: Record<ColorName, string> = {
  prop1: 'value1',
  prop2: 'value2',
} as const;

このように、as const をつけることで、オブジェクトのプロパティが readonly になり、型安全にできるのですが、一つ問題がありました。 この例だと問題ないのですが、もう少し発展した例を見てみましょう。

type ColorName = 'red' | 'green' | 'blue';

type Color = readonly [number, number, number] | string;

const obj: Record<ColorName, Color> = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
} as const;

これで obj にアクセスしようとしたとき obj の中に入っている値の型が string | [number, number, number] になってしまいます。 これでは string か number の配列(タプル)か判断することができなくなります。

そこで satisfies 演算子が登場します。

type ColorName = 'red' | 'green' | 'blue';

type Color = readonly [number, number, number] | string;

const obj = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
} as const satisfies Record<ColorName, Color>;

このようにすると green の値だけが string でほかがタプルになっていることが型推論により分かるようになります。

どこで使えるの?

特定の値だけ入っている配列を作りたい

as constsatisfies を組み合わせることで、特定の値だけ入っている配列を作ることができます。

type ColorName = 'red' | 'green' | 'blue';

const colors = ['red', 'green', 'blue'] as const satisfies readonly ColorName[];

// これだと型推論が効かない
const colors = ['red', 'green', 'blue'] as const;

// これだと型推論が効くが、長さが不定の配列になる。一部だけ抜き出したりするときには使えない。
const colors: readonly ColorName[] = ['red', 'green', 'blue'] as const;

このようにすると colors の中には 'red' | 'green' | 'blue' しか入っていないことが型推論により分かるようになります。いままでは ColorName が入っていることが保証できないか、タプルではなく不定帳として束縛されるようになります。

type ColorName = 'red' | 'green' | 'blue';

const allowedColor = ['red', 'green'] as const satisfies readonly ColorName[];
type AllowedColor = (typeof allowedColor)[number]; // 'red' | 'green'

こういうふうにすると、allowedColor に入っている値だけを使って型を作ることもできます。

OpenAPI Generator や GraphQL Code Generator で生成された型のうちどれかを使いたい、みたいなときに役に立つのではないでしょうか。もちろん、全部使いたいときもミスしてないか保証できるので便利です。

特定のキーのオブジェクトを作りたい

これはまさにさっきの satisfies 演算子とは? で紹介した例です。

type ColorName = 'red' | 'green' | 'blue';

type Color = readonly [number, number, number] | string;

const obj = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
} as const satisfies Record<ColorName, Color>;

これによって、objがColorNameのキーを持ち、その値がColorであることが型推論により分かるようになります。 こんな複雑でなくても、 Record<ColorName, string> のような簡単なものでも意識的に使っていくと良いと思います。

さっきの例と組み合わせるとこんな感じの使い方ができるでしょう。

type ColorName = 'red' | 'green' | 'blue';

const allowedColor = ['red', 'green'] as const satisfies readonly ColorName[];
type AllowedColor = (typeof allowedColor)[number]; // 'red' | 'green'

const allowedColorNotation = {
  red: '赤',
  green: '緑',
} as const satisfies Record<AllowedColor, string>;

まとめ

意外とこういうところで使えるっていうのを紹介した記事がなかったので書いてみました。 使い所は他にもあると思うので活用してみてください!

それではよきTypeScriptライフを!

○○の帽子を被るって表現が好き

はてなの社内用語というか自分の今いるチームだけかもしれないですが、最近社内で「エンジニアの帽子を被る」「マネージャーの帽子を被る」という表現をよく聞くようになりました。

人間誰しもポジショントークをすることがあると思うんですけど、自分の複数あるポジションでそれぞれ対立するトークをしたい時があると思います。 そんなときにこの「〇〇の帽子を被る」は便利です。

最初の例だと、エンジニア兼マネージャーみたいな人が「マネージャーの身としては嬉しいんだけど、エンジニアの身としては嬉しくない」っていうのを「マネージャーの帽子を被ったときは嬉しいけど、エンジニアの帽子を被ったときはうれしくない」と表現する感じです。

これ、他のことにも応用できると思っていて、ユーザー目線と開発者目線みたいなのが必要なときに役に立つと思うのです。

「ユーザーの帽子を被るとめっちゃほしいんだけど、開発者のl帽子を被るとめっちゃ面倒だからすぐはできない」みたいなことは往々にしてありがち。 でも、それぞれの帽子被って見える目線を戦わせれば、落とし所みたいなところが見つかると思うのです。 消費者の目線と作り手の目線ってどっちも大切なので、どちらも忘れないようにしていきたいものです。

まぁそんな感じで複数のポジションを表現する面白い方法を知ったので活用していきたいなって思ってる次第です。


【4/20 13:40追記】

あとでブコメとかで指摘されたんだけど、割と一般的な英語イディオムの wearing several hats をそのまま直訳で日本語で使っているということらしい。

これらの本で使われてる表現だそうです。

(結論はまだ出てない)ターミナルをいい感じにしたい話

ここ1年ぐらい*1から、ターミナル環境を良くしようという活動を頑張っている。

今使ってる環境が Windows / macOS / Manjaro Linux と、完全マルチプラットフォームな感じになっておりそれぞれで違うものをあんまり使いたくはない。 悩んでるけど結論が出ないので、ここに備忘録的にかいておこうと思う。

*1:だいたいchezmoi + oh-my-poshを導入したあたり

続きを読む

コードの草むしりをしよう(ボーイスカウトルール)

はじめましての人ははじめまして。そうでないひとはお久しぶりです。猫ロキP(@deflis/id:deflis55)です。

今日は、コードをキレイにする心がけの話を書きたいと思います。

前職のチームでは「草むしり」という習慣がありました。いわゆるボーイスカウトルールみたいな話なんですが、コードのちょっとした不満点を草としてむしっていこうというルールでした。

歴史の長い大規模なコードベースをいじっていると細かいけど修正したい箇所にちょくちょく出くわすと思います。 「このメソッドの引数の説明ちょっと間違ってるな?」とか「この変数の名前ちょっと変だな?」とか「型引数つけ忘れてない?*1」とか「これ新しい文法/ライブラリならもっときれいに読みやすく書けるのに」とか。 これらのホントにちょっとした雑草を、せめて今回の変更でいじる範囲だけでもキレイにしていこうというのが草むしりです。*2

草が大きくなってくると、リファクタリングの域に達するような変更もあるかもしれません。ですが、それもちゃんと行った理由*3を説明すれば納得してもらえるはずです。

様々な理由でちゃんと動いてはいるけど(コードとしては)中途半端なものが動作している状態になるのはありがちです。 でも、この心がけ一つで少しづつでもよく触るような箇所のコードは良くなっていくと思います。 始める前は草ボーボーの汚いソースコードでも、少しづつ草むしりをすれば地面が見えてくるようになるはずだと思っています。 草をむしっていく心構えがあるだけで、どんどんコードは読みやすくなっていくはずなので積極的にコードの草はむしっていきましょう。

本日の一冊のコーナー!

恒例にしたい一冊コーナーです。

今回は草むしり、つまりゴミ拾いなのではということでこれです!

もうすでにアニメ化決定しているぐらいの大人気作品です。ほのぼのかと思いきやちょっとダークなところもあって、非常に説明しづらいんですがなにはともあれ漫画版からでもいいので読んでみてください。

to-corona-ex.com

*1:とくにPHPだと、古いバージョンではプリミティブ型の型引数が書けなかったりとかしたのでよく見かけそうです。

*2:もちろん、変更を加える範囲以外もキレイにしていくべきだし、そういう余裕があればやるべきです。

*3:安全に変更したいとか、機能を追加するにも拡張性が足りないとか、なにかリファクタリングしたい理由はあるはずです。

Obsidian使い始めました

はじめましての人ははじめまして。そうでないひとはお久しぶりです。猫ロキP(@deflis/id:deflis55)です。

昨年、増田で メモアプリの知見を貸してほしい というのを見て、いろんなメモアプリをとっかえひっかえしてたのを思い出したりしてなんですが、そこでObsidianというのが最近良いらしいと言うのを見つけたので使い始めてみました。*1

*1:id:Windymelt さんも使い始めた記事を書いてたので自分も書いてみようと思った次第です。Obsidian使ってみた - Lambdaカクテル (3qe.us)

続きを読む

最高のトラックボールを買ったと喜び勇んでいたら、自作キーボードのDZ60を壊したのでKeychron Q2を買ってしまった話

はじめましての人ははじめまして。そうでないひとはお久しぶりです。猫ロキP(@deflis/id:deflis55)です。

前作のPloopy thumb trackballが届いたの続きです。

Ploopyを試していたときに悲劇は起こりました。同じUSB TypeCコネクタなのでケーブルを交換しようと思ったらバキッっと…。

結局、結構気に入っていた自作キーボードのDZ60はお亡くなりになってしまいました。こんな変なキーマップを作るぐらいには気に入ってたので、残念な限りです。(このせいで半端に括弧の位置だけがUS風にずれたキーボードを使い続ける変な人になっています)

はじめは同じケースでJP60にしようと思って*1基板まで遊舎工房で買ったんですが、そのあとヨドバシを眺めてたらKeychron Q2をレジに持っていってました…。

なぜなら、Keychron Q2は自作基板含めてJIS配列の60~65%キーボードで最も理想に近いと思うのです。

Keychron Q2 JIS Knob Version (赤軸)

というわけでKeychron Q2を買った理由と買ってよかったのかをお教えします。

  • Pros
    • 組み立て済みでホットスワップ対応
    • メタルケースがかっこいい。重厚感ある。
    • 割と静か
    • 標準のキーキャップがPBT
    • VIAやRemapに対応
    • スペースキーの左に4つキーがあるのでキーマップの自由度が高い
    • 65%なので十字キーがある
    • ヨドバシで買える
  • Cons
    • 枠がでかい(意外とデカくてつらい)
    • ノブどう使えばいいのかわからない
    • 標準のキーキャップがめっちゃごちゃごちゃしてる
    • OEMとDSAの間の子みたいな変な形してるキーキャップ
    • Enterの横の2つのキーがいらない(個人的に使い道がない)
    • スペースの長さが多分特殊

あと、標準のキーマップだと前のキーボードと違って矢印キーがシフトキーの外側に合ったりするのですけど、よく考えればキーマップ変えてキーキャップのいちをずらせば解決する話だったので自己解決しました。

というわけで、JIS配列で60%ぐらいで矢印キーを欲しい人はQ2をすこるしかないというお話でした。静音じゃないリニア軸初めてなのですけど、割と軽めでちょっとたのしいかも。

*1:矢印キーと左側4キーでどっちか悩んで十字キーを捨てた