樹脂が固まる前に

Web Frontend / Android / Designが好きな人のメモ

Next.jsでSSGしてたサイトをPages RouterからApp Routerに載せ替えた

Next.jsでSSGしてたサイトをPages RouterからApp Routerに載せ替えたので、備忘録。

App RouterにすることでRSC(React Server Component)を使えるので、いつかやらねばなと思っていました。

とはいえApp RouterでのWebアプリ構築はテストまわりなどでトラブりがちな印象ではあります。

もし、今から新規プロジェクトをやるならApp Routerにしつつ、ほぼApp Routerの機能を使わない形で始めるでしょう。

話を戻して、今までApp Routerに移行しなかったのは、Next.jsでApp Routerが登場した当初、SSGに対応していなかったからです。

それに気づかず移行作業を進めていたらうまく動かなくて萎えた覚えがあります。

以下のようにSSG対応されてからは、普通に面倒で移行をサボっていました。 nextjs.org

移行作業

手順は正直下の通りなので、ざっくり関係ある部分の作業をかいつまんでメモっておきます。 nextjs.org

方針としては、最低限App Routerで動く形にするだけにしました。

Pages RouterとApp Routerは共存でき、ページ単位で移行ができるので、少しずつやっていきました。

Layout追加

App RouterではPageファイルの他に共通部分をLayoutで管理するので、それの追加を行います。

基本的には_app.tsx_document.tsxで行っていたmetadataやGoogle Fontなど外部のリソースを読み込む部分をまとめます。

globalなCSSなどもここで読み込むと良さそうです。

import './global.css'

export const metadata: Metadata = {
  title: '...',
}

const RootLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => (
  <html lang='ja'>
    <head>
      {/* ... */}
    </head>
    <body>{children}</body>
  </html>
)

export default RootLayout

ざっくりこんな形です。

pageコンポーネントをClient Componentに移行する

pagesフォルダ以下にあるpageコンポーネントは、ほとんどがただのStatelessなコンポーネントでした。 ものによっては、それに追加で

  • 動的パス生成のためのgetStaticPaths関数
  • 静的ファイル生成のためのgetStaticProps関数

などが生えているファイルがありました。

そこからStatelessなコンポーネント部分を'use client'をつけてClient Componentとしてappフォルダ以下に移行します。

App Routerの場合は'next/router'のuseRouterがそのままでは動かないので、適宜'next/navigation'にあるHooksを使うようにしました。

ちなみにClientでしか動かないComponentでない場合は、普通にServer Componentとして定義してしまいます。

Server Componentを追加する

さっき追加したClient Componentを描画するためのServer ComponentのPageを追加します。

export async function generateStaticParams() {
  // ...
}

const Page = async () => {
  const data = await xxx
  return <ClientComponent data={data} />
}
export default Page

動的パス生成の場合はgenerateStaticParamsで行います。

Pages RouterとApp Routerとで同じページは同居できないので、pages以下の該当ページのファイルを削除してページの移行完了です。

これを各ページ分繰り返していきます。

感想

終わって見たらあっという間でした。

SSGのためにNode.jsでデータを用意していた部分も多かったので、思ったよりServer Componentへの移行は難しくなかったです。

どちらかというとClient Componentの方が少ないぐらいでした。

ただ、これがページ数の多いWebアプリだったら大変そうな感じはします。

IE卒業式に参加してきたら青春時代を思い出した

2022年6月15日、インターネットの礎を築いてきたInternet ExplorerIE)のデスクトップアプリがサポート終了しました。 後方互換性のために2029年までEdgeのIEモードはサポートはされますが、一応IEとしては一区切りついた形になります。

今回はIEサポート終了に関連して開かれたIE卒業式というイベントに参加してきたので、参加レポートとIEやインターネットへの思いを雑に書き留めておきます。

web-study.connpass.com

IE卒業式

久しぶりにオフラインイベントとのことで電車やマップを見ながら日本橋サイボウズへ。

はじめて行きましたが、ビルがきれいでエレベーターでかくてビビりました。 オフィス内のイベントスペースはカラフルな感じで良かったです。(写真撮り忘れた)

ネットの有名人がたくさん来ており、「あ、あの人だ...!」と心で叫びながら終始コミュ障発揮してました。 なかなか有名人同士の輪に入っていくのは難しいですね。

とは言え、IEの歴史やそれを取り巻く環境の変化、苦労話や思い出話など、とても楽しく聞くことができました。 mhtmlの話やCSSのexpression関数など、初めて聞く話題も多かったです。

普段Webフロントエンド開発をメインで行っていますが、本格的にIE対応したのは社会人になってからだったので、実際に経験してきた人の話を聞けるのは貴重な経験でした。 ちなみにIEは1995年生まれで1歳年下でした。マジか。

特にJxckさんの発表は心にぐっと来ました。

speakerdeck.com

これは集合写真。

(なんか今見たらマックスむらいさんいる?)

このあと、IEロゴの形をしたケーキをみんなで分けて食べました。 なかなか派手な見た目とは裏腹に、味はちゃんと美味しかったです。

IEのロゴのカケラ部分が食べられて満足でした。

イベントを企画してくださった皆さんには感謝しています。 楽しい時間をありがとうございました。

IEおよびインターネットの思い出

イベントを通して感じたのは、年齢もありますが私はIEとそこまで絡んでこなかったなということと、IEの歴史はインターネットの歴史そのものだということでした。

記憶がおぼろげなのでこの記事を見ながら思い出してみます。

gigazine.net

IEのそれぞれのバージョンや機能、エンジンなどの話についてはそれはそれで語りたいことがたくさんありそうですが、今回は思い出の部分だけ書いておきます。

Internet Explorer 5(1999年3月18日公開)

IEと最初に出会ったのはIE5でした。 家にあったWindowsIEが入っていて、そこで何か父がカタカタ打ち込んでいるのを見た気がします。 保育園児だった私にはUIに見覚えがあるぐらいで、記憶らしい記憶もありません。 とりあえず世間が21世紀という盛り上がってる時期だった気がします。

Internet Explorer 6(2001年9月19日公開)

小学校にあがり、はじめてパソコン室のWindowsで触ったのがIE6でした。 IE6はPCに詳しくない人が無限にいらないツールバーを追加していってしまうイメージがあります笑。

この頃、当時やっていた「電車男」のドラマ(2005年)をきっかけに、2ちゃんねるを始めとするインターネット文化が脚光を浴び始めました。 小学校高学年になると、個人ブログを作って仲の良い友達と交流するのがブームになり、学校ではコメント欄の荒らし行為が問題になるほどでした。 また「おもしろフラッシュ倉庫」と呼ばれるFlashのコンテンツも流行っており、今思えばPCを好きになった一つのきっかけだったかもしれません。

Internet Explorer 7(2006年11月2日公開)

IE7ではタブが採用され、かなり快適にブラウジングできていた気がします。 中学に上がってからは父が定期購読していた週刊アスキーを読むようになったこともあり、イキって新興勢力のFirefoxなどを使い始めた時期でもあります。 Firefoxの高速さや拡張機能のカスタマイズにだいぶハマっており、正直この頃からIEを触らない期間が長くありました。 また、ブラッディ・マンデイというハッカーを題材にしたドラマが放映されており、私を含むたくさんの子どもたちがハッカーに憧れました。

IEはこのあとも8, 9, 10と間隔をあけながらも新バージョンをリリースしていきますが、その頃にはもうGoogle ChromeChromium派生の様々なブラウザに移行してしまっていました。 中学・高校のパソコン室のPCにはIEしか入ってませんでしたが、こっそりUSBメモリーを指してChromeを起動して快適ブラウジングしていた記憶があります。

大学に上がってからもずっとChromeを使っており、大学院を卒業するまでChrome漬けでした。 アルバイトでIEをサポートする必要があるウェブサイトの改修などを行うときにだけ、ES5を使って生のJSを書いた思い出があります。 そのときには既に世間はIE11になっていました。

2019年に就職してからはソースコードでIE8, 9 10あたりの対応が大変だったことを感じつつ、サポートしていたIE11の対応だけ行っていました。 そのときには既にIEはかなり下火になりつつも、完全にサポートを切れるようなシェアではなく、現場に不満が募っていたような気がします。

2020〜2021年にかけて、MSがTeamsやOffice 365でIEサポートを切ることになり、国内でもIEサポートを切る流れになりました。 そこからは社内でも積極的にサポートを切るように動きました。(ここの話はどこかで記事にできたらなと思います。)

私の開発しているサービスでは、IEを推奨環境から外すのは少し前からしていたのですが、2022年6月16日に完全にIEからサービスを見れないようにしました。

これからはIEボトルネックとなって出来ていなかったことをどんどんやることになります。

こういった機会にはなかなか恵まれないと思うので、この状況を楽しみたいと思います。

最後に、改めてありがとうIE

電動昇降デスクを導入した

前から気になっていた電動昇降デスクを導入しました。 結論から言うと、とても良いです。

机低い問題

在宅勤務のとき、私はリビングにある小さなダイニングテーブルをデスクとして作業していたのですが、机の高さが低く姿勢が悪くなってしまい、結果として肩こりや頭痛を引き起こしていました。
PCを台にのせて高くしたり、椅子を家にある少し小さいものに変えて相対的にデスクを高くしてみましたが、いまいち合いませんでした。
手動で高さを調整できるデスクも検討しましたが、手間などを考えた結果、本格的に電動昇降デスクの導入を検討することにしました。

電動昇降デスクのメリット・デメリット

私が調べたり、実際に実感したメリット・デメリットをまとめてみます。

メリット

  • スタンディングで作業できる(眠気覚まし、姿勢を変えることで姿勢の悪化を防ぐ)
  • 座っているときも自分の好みの高さにできる(個々人の好みや椅子・PC・モニターのサイズに合わせて柔軟に変えられる)
  • 脚だけのものも売っているので、天板を好きなものにできる(インテリアや使い方に応じてカスタマイズできる)

デメリット

  • 脚回りがゴツく、インテリアとしてすこし微妙
  • 普通のデスクより相場は高い(天板と脚を別々の場所で調達するとより高くなる傾向)
  • 組み立てるタイプだとそもそも組み立てが大変
  • 電気代がかかる

個人的にはインテリアにこだわりがあり、脚がゴツい点がかなりネックだったのですが、探してみるとシンプルめな脚もあったので購入に踏み切りました。
加えて、会社の電動昇降デスクで作業してみて結構良かったのでスタンディングも割と自分にはハマりそうだなと思いました。

購入

買う前にネットの記事を色々調べたり、YouTubeとかで電動昇降デスクについて調べてみました。
安いもので2-3万円から存在していましたが、自分好みの質感の天板がセットになっているものが少なく、天板をカスタマイズできるよう脚だけのものを探しました。
ダイニングテーブルとしても使おうと思っていたので、ある程度値段がはっても気に入るものを選ぶようにしました。

色々調べてみましたが、口コミも多くハズレが少なそうなFlexiSpotというブランドの脚とKANADEMONOという家具ブランドの天板を使うことにしました。

FlexiSpotは以前から聞いたことのある有名なブランドで、品質に関しても大きな問題はなさそうだったので決めました。
以前調べた時はシングルモータでゴツい感じだったのですが、今はデュアルモータで脚以外に余計なものがついていないシンプルな形が出ていたのでE7の黒にしました。
脚の断面が楕円形の新型もありましたが、黒い脚は四角形のほうが似合うと感じE7を選択しました。

FlexiSpot | E7

天板を買ったKANADEMONOは割と昔から雰囲気が好きなブランドで、フロアランプを買ったりしたこともあります。

天板はTHE BOARDというシリーズのラバーウッドアッシュにしました。

THE BOARD / ラバーウッド アッシュ – KANADEMONO

素材については、家のインテリアにあうようナチュラルウッドか、グレー系のリノリウムにしようと思っていました。
家にグレー系のリノリウムの作業机があるのですが、経年変化を楽しめるのは木の方かなと思い、ある程度傷や汚れに強いラバーウッドにしました。
リビングにはミルク加工した木製のテレビボードがあるので、それに合うようナチュラルウッドの中でもある程度明るくて黄色みが少ないアッシュにしました。

組立作業

事前に調べた感じ、電動ドライバーがあったほうがネジ締めや天板への穴あけがスムーズということでXiaomiのものを買いました。

電動ドライバーはデザインが好きで所有欲で買ってしまいましたが、ホームセンターなどで1日レンタルできるので、別にそれで良いと思います。 ドリル用のアタッチメントは先人たちの知恵を借り、ダイソーで買いました。

組み立ては2時間ぐらいで終わりました。

まず展開

脚を組み立てて載せたら、そのまま穴あけて締めます。
穴を空けすぎないように目印となるマスキングテープをドリルの先につけます。

最後にひっくり返して完成!
ひっくり返すのはYouTuber達が2人でやったほうがよいと言っていたのでヘルプしてもらいました。

最後に

今の所めっちゃ良いです。
やはり若干普通のダイニングテーブルよりは脚がゴツいですが、ダイニングとしても割と溶け込んでいます。
ちょっと高くしてカウンターみたいにしても、カフェっぽいおしゃれな感じになります。

これから配線周りなどをやっていきたいです。

8年半使っていたアイコンを変更した話

ツイッターで8年半使っていたアイコンを変更しました。
ここでは、その経緯とアイコンデザインに込めた思いをメモしておこうと思います。

f:id:pvcresin:20211108001018p:plain

旧アイコン

そもそも旧アイコンはTwitterを始めてからずっと使っていた思い入れのあるものでした。
2013年4月に大学に入学して初日に先生から言われたことは、「この学科ではTwitterが必須である」ということでした。
FMS学科のユニークさについては、いくつも記事が書けてしまうほどの話があるので避けますが、とにかく大学・大学院生活においてTwitterが学生間の大きなコミュニケーションツールでした。
なので、初日になんとなく好きだったリラックマの顔を雑に切り取ったアイコンを設定し、なんとなく昔好きだった玩具の素材のPVC樹脂(pvcresin)というIDをつけました。
インターネット上で使うアイコンは統一していると識別に便利だったので、そのままこのアイコン(とID)を使って様々なサービス上で活動していくことになります。

問題

問題はシンプルに版権問題です。
学生のLTなどであれば、アニメアイコンの人も多かったので、グレーな扱いで済まされていました。 しかし、外部への発表などを行う際に、オリジナルのアイコンでなければ使いづらい場面が存在しました。
なんとか大学院修了までは持ちこたえましたが、そのまま社会人になってからも同じTwitterのアカウントを継続して使っていることから、そろそろ変えないとヤバいなと思うようになりました。

要件

8年半もアイコンを使っていると、そのアイコンで自分を認識している人がほとんどになります。 なので、大まかなイメージを変えすぎず、なんとかリラックマを消し去りたいと考えました。
もちろん、これを機にガラッと変えるということも考えました。 しかし、アイコンづくりに正解はなく無限に悩めてしまうため、レギュレーションという意味も込めてイメージを変えないことにしました。
一度オリジナルのアイコンを作ってしまえば後でまた変えることもできます。 まずは、問題の解決にフォーカスしました。

この時点でなんとなくあげた要件は以下のとおりです。

  • 拡大・縮小に耐えられる
  • 色が大きく変わらない
  • 構図が大きく変わらない

拡大・縮小に耐えられる

これはアイコンを作るときにいつも意識しているアイコンの耐久性の話です。
密度が高すぎるグラフィックなどを使うと、縮小に弱くなるため、できる限りシンプルな線で描きます。
もちろんベクター形式(SVG等)で作成し、必要に応じてラスター形式(PNG等)に書き出します。

色が大きく変わらない

人間は大まかな色の印象でアイコンを認識しています。
そのため、色のテーマ感をあまり変えないことや色数を少なく保つことを意識しました。
これにより、オリジナルパターン以外にもモノクロバージョンなどの作成が容易になります。

構図が大きく変わらない

構図も重要です。
旧アイコンはリラックマの顔が全面に押し出されているため、そのアイコンでツイートを行うと、まるでリラックマが喋っているかのような柔らかな、気の抜けた印象を与えます。
その使い方を継続するべく、新アイコンでも顔全面の形にしています。
また、背景色の上に顔のパーツを配置している形は様々な形に切り取ることが可能で便利です。 これはAndroidAdaptive Iconと同じ考え方です。

ツール選定

旧アイコンは雑な画像切り抜きで作成したあと、Adobe Illustratorイラレ)できれいな線に直してSVGとして保管していました。
今回はイラレを契約していなかったので、無料ソフトのInkscapeを使おうかとも考えました。
何回か昔使ったことはあったのですが、使用感のクセが強かったので代替物を探していたところ、Figmaがあったことを思い出してそれを使いました。
FigmaはUIデザインに使うイメージが強いですが、ベジェ曲線などを使ってパスを描くこともできるので簡易的なイラレの代替になります。
作業もブラウザで簡潔して便利。

新アイコンの制作

いくつかペイントソフトでの雑なお絵かきを繰り返して、完成したのが画像右の手書きプロトです。
リラックマのゆるい獣な感じをなんとか残せないか格闘して生まれました。 クマとかイヌとか、ハロウィンのカボチャ(ジャックオーランタン)をイメージしています。

ちなみに口の形はなんとなくハロウィンのカボチャが好きなのでギザギザにしましたが、ちょうどアイコンを作っていたのが9月後半だったので10月のハロウィンシーズンに変えてしまおうと計画しました。

f:id:pvcresin:20211108001322p:plain

元の色を使いつつ、よしなに気の抜けた感じを残していて気に入りました。 これをFigmaでパスに起こしつつ清書して完成したものが画像左です。

いくつかこだわりがあります。

  • 目の形
  • 口の形

f:id:pvcresin:20211108005133p:plain

新アイコンでは2色に抑えることにしました。
これは元から考えていたというよりは、お絵描きしていたら2色がしっくり来る絵になったからです。
プロトでは色のテーマ感を変えないようそのままの色を流用していました。
しかし、流石に絵とマッチせず、暗い印象になってしまったので背景色のトーンを少しだけ明るくしました。
それにより、顔パーツの色は同じでもくっきり見えるようになりました。

目の形

目だけはリラックマの形で流用するなども考えましたが、リラックマの目はパッチリし過ぎで、口のゆるさで中和しているのだと気づきやめました。
ちょっと眠たそうな目をイメージしてパスを描いています。
ちなみに横長の長方形の左右に半円をつけた、陸上トラックのような形ではじめは作成していました。 しかし、それだと半円と長方形の接続部分に違和感が残ってしまったので、ゆるい曲線でつなぎ、楕円に近い形に変更しています。 ここらへんはUIでも同じような視覚的な補正を行うプラクティスがあるようです。
完全に水平に並んでいると地蔵みたいな印象を受けたので、ハの字になるよう3度ほど角度をつけているのも小さなこだわりです。

口の形

このあたりはかなりパスと格闘しました。
笑っている感じに全体的には口角をあげるようなカーブを付けつつ、ちょっとやんちゃな形の口にしています。
これは自分が華やかに大声で笑うと言うより、ニヤッとニヒルな感じに笑うことが多いのをイメージしています。
線に太さを持たせて印象を調節しています。

アイコンの修正

最後に各種SNSなどのアイコンを修正していきました。
様々なWebサービスで旧アイコンを使っていたため、思いつく範囲でも3-40個ほどは変えたと思います。 まだ、修正できていないものもあるかもしれません。
Gravatarに対応しているサービスや、GitHubなどのアカウントを使ってログインできるサービスは自動で反映されて便利でした。
ここらへんはもっと統一されてくると良いなという印象です。 10月頭に修正作業を終えました。

まとめ

思い入れのあるアイコンを変えるのはなかなか気が進まず、8年半も使い続けるようになってしまいました。
ひとまずオリジナルのアイコンにできたので、外部での発表やオリジナルグッズなどにも(使うかはおいておいて)使えます。
このアイコンをまた認識してもらえるよう、色々頑張っていきたいです。

npm に glob-extension-changer を publish しました

最近少しづつ OSS 活動に興味が出てきている今日このごろです。 とはいえ、能力も時間も足りていないのでのんびり学んでいこうかなと考えています。

Zenn で オリジナルの JavaScript ライブラリを公開しよう というのを見てからライブラリを公開することに興味が湧いてきました。
思い返してみれば、何かプロダクトを作るときにライブラリを使うことは結構してきたものの、自分名義のライブラリを作成して公開したことはありませんでした。
そこで、普段お世話になっている npm への公開を体験してみることにしました。

作成したもの

実際に公開したものはこちらになります。

https://www.npmjs.com/package/glob-extension-changer

glob パターンで指定したファイルの拡張子を変えるだけのシンプルな CLI ツールです。

使い方は

npx glob-extension-changer 'path/to/file/**/*.js' --extension .ts

のように使います。

--check フラグを使うことで、実際に拡張子を変更することなく、変更の結果を確認することができるようになっています。

npx glob-extension-changer 'path/to/file/**/*.js' --extension .ts --check

基本的な機能はこれだけです。

モチベーション

元々、業務で JavaScript から TypeScript への移行などを進めてきた関係で、拡張子だけを.tsから.jsに変えたいというシチュエーションが度々ありました。

解決手段はいくらでもあると思いますが、なんとなく npm package で解決したいと思い軽く調べたところ、私の思い描くシンプルな文法で使えるツールが見つかりませんでした。

そこで、簡単そうだし作ってみることにしました。

作業手順

ここからは実際の作業手順を記していきます。 なお、私がフロントエンド開発などで使うことを想定しているため、Node.js が前提になっています。

要件定義

まずは、どんなツール(ライブラリ)を作りたいか、どんな体験を作りたいかを視点に考えていきました。
掘り下げていった結果、以下の観点が浮かび上がりました。

  1. 指定した拡張子を変更できる
  2. glob パターンで指定できる
  3. CLI ツール
  4. インストール不要
  5. 機能がミニマル

指定した拡張子を変更できる: これはマスト。
glob パターンで指定できる: 様々なツールでファイル指定に利用されており、私も馴染み深い点と、シンプルな文法で柔軟にファイル指定が可能である点が気に入っています。
CLIツール: 拡張子を変えるためだけにスクリプトファイルを作成することは避けたかったため、CLI ツールにしました。
インストール不要: ローカルやグローバルにインストールするのも面倒であったため、インストール不要で npx で呼べる形が良いと思いました。
機能がミニマル: 拡張子を変えるというためだけのツールに特化することで余計な機能を削ぎ落とすことにしました。

リポジトリ作成

まずはリポジトリ作成します。 GitHub で作成し、ここにコミットしていきました。

意外に悩むのがライブラリ名です。
ライブラリの名前にはキャッチーなあだ名のようなものから、機能をそのまま説明したようなものまで様々なバリエーションがあります。
今回は検索でヒットしやすいように「glob で拡張子を変更する」という意味をそのままに glob-extension-changer と名付けました。
npm info で同名ライブラリが無いことは確認しておきます。

実装方針

今回は自分向けのツールを npm publish することのみを目標に置いていたため、できるだけ手を抜くことにしました。

JavaScript 直書き

TypeScript などを使うことも考えましたが、コンパイルするのが面倒であったのと、そもそもそんな複雑なツールではないので型はなくてもよいかなということで、思い切って生の JavaScript で書くことにしました。

テスト無し

テストは書いたほうが良いですが、ツールを公開することのほうが重要だったので、後回しにしています。

Done is better than perfect.

と言いたいところですが、手を抜くときにこの言葉を引用すると怒られるので避けましょう。
私のための(ほぼ書き捨ての)ツールなので、大きな問題が出ない限りはいいかなという感じです。
後々に余裕があればユニットテストを追加したいです。
空っぽの test ファイル作って力尽きました。

テスト書かない代わりにいくつかの場所でライブラリがちゃんと動作しているかの手動チェックはしました。

CI 無し

テスト無しであることも後押ししてか、CI もなしになっています。
多くの人に使ってほしいライブラリの場合は、様々な OS や Node.js のバージョンで動くことを保証したほうが良いでしょう。
ゆくゆくは README にバッジとか表示したいですね。

技術選定

今回は node-glob で glob パターンによるファイルのリストアップを行い、commanderCLI ツールを作成しています。 どちらも老舗ライブラリです。
これらのライブラリに依存している glob-extension-changer 自体の Node.js への対応も v12 以上と、LTS が v16 台の現在においてはまずまずな感じに古い Node.js に対応できています。

実装

作成したリポジトリはこちらです。

https://github.com/pvcresin/glob-extension-changer

CLI のパラメータ取得などはよしなに commander が行ってくれるので、それを node-glob に受け流すだけになっています。
--extension で変更後に拡張子設定を行う、--check で dry-run するというのだけ決めてあとは素直にコードに書きました。
初見だったのですが、Node.js 標準の util package に promisify というコールバック型の関数をいい感じに Promise に置き換えてくれるものがあって便利でした。

CLI ツールとして呼び出すため、index.js の一番上に

#!/usr/bin/env node

と書いて、

package.jsonbinに index.js へのパスを書きました。
これで、npx glob-extension-changer xxxができるっぽい。簡単。

下準備

一応公開するツールなのでライセンスはつけておきます。今回は MIT にしました。
ライセンスを作成するツールはたくさんありましたが、適当にネットでヒットしたオンラインツールで作成しました。
おそらくどんな言語でも実装されていそうなので、一回探しておくと良さそうです。
VSCode 拡張とかでも多分ありそうです。

README は npm publish されるときにライブラリの顔になるため、最低限のツールの概要と使い方を載せておきました。

巷のライブラリにはたくさんの項目が README に載っていますが、概要と使い方だけで 9 割のユーザは救える気がしています。
あと付け加えるなら、コントリビュートの仕方とかですが、まぁ追々で。

公開

npm にアカウント登録します。 私は Web サイトからポチポチしました。
ターミナルで npm login してから npm publish だけで公開されました。🎉

アップデートする時は、package.json の verson を更新して再度 npm publish します。
ここらへんも version ごとに tag を切るとか、リリースノートとかモチベがあったらいい感じにしたいですね。

最後に

感想としては、公開自体はめちゃくちゃ簡単だなと思いました。
巷に溢れているライブラリ作りました記事だと、すごく CI の設定が凝っていたりテストの部分が充実していたりで、なんとなくハードルを高く感じてしまいます。
私のようにテストなし、CI 無し、いろいろな自動化なしでも公開まではできるということを伝えたいです。
どんなライブラリも始めから完璧ではないと思うので、まずは公開して少しづつリポジトリを改善していけばよいのかなと思います。
書き捨てのツールでも一旦どんどん公開していけば、世界の誰かの役に立つかもしれません。
これからも何か作りたいものがあれば公開していこうかなと思います。

Riot.js から Next.js に移行した話

マジで年 1 ぐらいでしか個人ブログ更新してないなと気付き反省しています。

はじめに

最近、 自分の Portfolio サイトを Riot.js から Next.js に移行しました。 理由としては、 大きく以下の 2 点があります。

  • Riot.js のメジャーアップデート(v3 -> v4)による API の変化が個人的にしっくりこなかった
  • Next.js の SSG について勉強したいと思っていて、ちょうどよい題材が欲しかった

長年お世話になった Riot への感謝とともに、移行の手順について簡単に残しておきたいと思います。

※ Riot.js は今でも開発が続けられてますし、dis る意図はありません。

Riot.js との思い出

Riot は私にとって青春でした。 私がお世話になったのは v3 で、初めて知ったのは 2016 年の冬でした。 v3 のページは現行のバージョン(https://riot.js.org/ja/)とは別になっています ↓

https://v3.riotjs.now.sh/ja/

今でこそ Web フロントエンドエンジニアとして仕事をしていますが、当時は少しだけ React を触ったことがある程度で、ただの Kotlin / Android 大好き学生でした。 そんな私にとって、初めて出会った時は凄まじい衝撃が身体を駆け巡りました。

<todo>

  <!-- layout -->
  <h3>{ opts.title }</h3>

  <ul>
    <li each={ item, i in items }>{ item }</li>
  </ul>

  <form onsubmit={ add }>
    <input ref="input">
    <button>Add #{ items.length + 1 }</button>
  </form>

  <!-- style -->
  <style>
    h3 {
      font-size: 14px;
    }
  </style>

  <!-- logic -->
  <script>
    this.items = []

    add(e) {
      e.preventDefault()
      var input = this.refs.input
      this.items.push(input.value)
      input.value = ''
    }
  </script>

</todo>
  • 非常にシンプルでミニマルな文法(API
  • HTML や CSS、JS をひとまとめに書ける単一ファイルコンポーネント
  • バンドルサイズの小ささ

は衝撃的でしたし、その美しい文法とは相反する内なる思想の強さみたいなものが Riot (暴動)という名前にふさわしいと思いました。 Vue も似たような立ち位置でしたが、特に JS 周りの文法はかなり記述量が少なく、Minimalism という観点で個人的にかなりしっくり来ていました。 HTML 部分や CSS 部分、JS 部分もカスタマイズが可能で、Pug + SCSS + ES6 という当時のお気に入りのセットが実現できたのも嬉しかったです。

すぐに虜になった私は、Riot でたくさんの Web アプリケーション(SPA)を作りました。 特に自分しかフロントエンドの開発をせず、規模が大きくならなそうなものに関しては、積極的に使っていきました。 例えば、アルバイト先で開発を担当した新規のサービスのうち、半分ほどは Riot を使いました。 また、研究で使うデモ用の Web アプリケーションを作成するときも Riot を使いました。 ミニマルな構文は、生産性に直結し、かなりスピーディに開発をできていた気がします。 Riot が少し日本で有名になった頃には勉強会なども開かれ、参加したりもしました。 その学習の容易さはエンジニアだけでなくデザイナにも受け入れられている様子で、なぜか私自身も嬉しくなってしまいました。 他にも、就活をしていて好きな FW について聞かれたときはいつも Riot の話をしていました。 Web フロントエンドの FW としては初恋だったと思います。 知れば知るほど奥深く、本当に Riot が大好きでした。

ただ、徐々に疎遠になっていきました。 私自身はあまり感じたことなかったのですが、パフォーマンスでの問題やバグなどがあったらしく、そういうツイートをちょいちょい見かけるようになりました。 それを見てから私も自信を持って Riot を布教することがだんだん難しくなってきたように思います。 人に流されるなと言われればそうなのですが、頭の片隅でやはり気にしてしまう自分がいました。

そして、それらの多くが解決された Riot v4 が誕生したとき、 私の好きだった Riot のミニマルな文法は失われ、より Vue っぽいものへと変わってしまいました。

<todo>
  <!-- layout -->
  <h1>{ props.title }</h1>

  <ul>
    <li each={ item in state.items }>{ item }</li>
  </ul>

  <form onsubmit={ add }>
    <input name="todo">
    <button>Add #{ state.items.length + 1 }</button>
  </form>

  <!-- style -->
  <style>
    :host {
      padding: 16px;
    }
  </style>

  <!-- logic -->
  <script>
    export default {
      state: {
        items: []
      },
      add(e) {
        e.preventDefault()
        const input = e.target.todo

        this.state.items.push(input.value)
        this.update()

        input.value = ''
      }
    }
  </script>
</todo>

完全に個人の趣味なのですが、この JS 部分がどうにも、受け入れられず、そのあたりからリタイアしてしまいました。 実際使いこなすだけであれば、全く問題ないと思います。 ただ、思いを寄せていた相手がガラッとイメチェンしてしまった感じです。 このなんとも言えない行き場のない思いは、興味の衰退という形であらわれていきました。

Riot との思い出はここまでです。 また、気になったら「初めまして」から始めたいと思います。

Next.js への興味

話は変わって React ベースの SSR, SSG の FW である Next.js に移ります。 Next.js にはフロントエンドのパフォーマンスを高めるための様々な工夫が盛り込まれています。 実際に勉強がてら触ってみたいと思い、題材として自分の Portfolio サイトを選択しました。 Portfolio サイトは Riot v3 で作られており、v4 への移行はかなり根本から変えなければならなそうだったため、それなら勉強したい Next.js にしようということです。 中身のコンテンツはめちゃめちゃ古いままなのですが、FW を刷新した感じです。

移行

ここでは移行の手順を説明します。 今考えると遠回りしていた感じもありますが、実際の作業どおりに書いていきます。 まず、現状の状況を整理します。

  • Riot v3 による SPA
    • Pug
    • SCSS(Scoped CSS)
    • ES6
  • webpack でビルド(バンドル)
  • GitHub Pages で配信
    • master ブランチの root に手動でビルドして Push

ここから以下に変更しました。

  • Next.js v9.5
    • React
    • SCSS
    • TypeScript
  • Next.js で SSG して HTML ファイル生成
  • GitHub Pages で配信
    • GitHub Actions で自動ビルド(エクスポート)

URL を変えたくなかったので、GitHub Pages を使うことは継続しました。 一方でビルドは、手動から GitHub Actions での自動ビルド(エクスポート)に変更しました。 その方がリポジトリソースコードだけになってきれいそうだったので。 あとは、型が欲しかったので TypeScript に移行しました。 ちなみに古いリポジトリなので main ではなく master ブランチです。

移行の仕方としては、現状のコードやビルドされた生成物には触れず、Next.js の設定をして完全に同じサイトが再現できたタイミングで GitHub Pages の設定を切り替えました。

Pug -> HTML

サイト作成時は Pug というテンプレートエンジンにハマっていたので、Riot でも Vue でも Pug を使っていました。 ここから React(TSX)にする必要があるので、まずは HTML に近づけるところから始めました。 Riot の標準のテンプレートはほぼ HTML なので、Pug を HTML に変換するサイトなどを使って変換しました。

Scoped CSS -> Global CSS

Riot ではコンポーネント内にスタイルの定義を閉じる、Scoped CSS:scopedが独自実装されているので、それをグローバルでも衝突しないように変更しました。 具体的には SCSS のネスト機能を使っていたので、:scopedで囲まれていたスタイルを.component-fooのような一意なクラス名で囲む形にしていきました。

ルーティング

GitHub Pages で SPA を実現するため、riot-route を使い、以下のような Hash によるルーティングを行っていました。 github.io/#projects/foo

個人的にはこの Hash は好きではなかったので、Next.js の SSG で以下のパスに変更しました。 github.io/projects/foo

詳細ページのリンクを貼ることはあまりなかったので、ルート以外のパスが変わってしまうのは許容することにしました。

Next.js 導入

そろそろ Next.js のセットアップを行っていきます。 普通に Next.js のドキュメント通りに作っていくだけだったので特に書くことはないです。 まずは開発用サーバで SPA が良い感じに動くようにし、ルーティングできるようにしていきました。 中身はまだ空っぽです。 CDN をいくつか使っていたので、_app.tsxで NextHead コンポーネントを使って対応しました。 あと、モダンブラウザ以外を考える気はあまりなかったのですが、Babel の設定をするのが面倒だったので polyfill.io をとりあえず入れておきました。 IE でチェックしてないのでもしかしたら動いてないかもしれません。 最後に、next export して SSG したファイルでも問題ないかを確認しました。

CI

GitHub Actions で自動ビルドするようにしました。 以下の記事を参考にしました。

GitHub Pages に Next.js をデプロイする | Qiita

master への Push を検知し、gh-pages ブランチに SSG の生成物を Push する形です。 yarn を使ったりコマンド名を変えたり多少変えましたがほぼ同じ設定を書きました。 記事中でも言及がありますが、GitHub Pages の仕様で _ で始まるディレクトリがデフォルトでは見えないようになっているらしく、.nojekyll ファイルをリポジトリのルートに置くというのが勉強になりました。 これで GitHub Pages の配信設定を master ブランチではなく、gh-pages ブランチに切り替えれば Next.js で作成したページが見られるようになりました。

コンポーネントを Next.js 側に移行

あとは気合です。 Next.js 側にコンポーネントを作成しまくり、Riot に書かれたロジックを移していきました。 特に Riot 特有の記法(each や if など)を JavaScript に書き換えるのは単純作業ですが、楽しかったです。

SCSS

スタイル定義にはこれまで通り SCSS を使っています。 正直なんでも良かったのですが、移行前がそうなのでそのままです。 各コンポーネントの隣に同名の SCSS ファイルを置き、それを import しています。 global の定義は_app.tsxで読み込んでいます。

GitHub Pages の設定変更

配信設定を master ブランチではなく、gh-pages ブランチに切り替えたあと、実際に問題がないか確認しました。

Riot 削除

家に帰るまでが遠足です。移行は掃除まで含めて移行完了です。 ということでバッサバッサと Riot のビルドで使っていたツール群を消していきました。 webpack や loader、コンポーネントの tag ファイルなどです。 これは気持ちよかったですね。

移行完了して

何年も放置していた Portfolio サイトを久しぶりに触って、ひどい作りだったのでこれから技術的にもデザイン的にもコンテンツ的にもアップデートしていきたいなと思いました。 今までありがとう Riot。 また会う日まで。

今年あったことを年が明けるまでに一瞬で振り返る

2019/12/31 23:52に書き始めた記事です。

あと8分以内で今年を振り返ります。

  • Web制作のアルバイト卒業
  • 大学院修了
  • エンジニアとして就職
  • 入籍&引っ越し
  • 新婚旅行

環境がガラリと変わった1年でした。

エンジニアとしても人としても変化に適応し、強く大きくなりたいと思います。